User prompt
ahora haz que las cartas puedan usarse presionando las mismas
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'createEnemyConfig')' in or related to this line: 'self.typeConfig = GAME_CONFIG.createEnemyConfig(self.enemyType, config || {});' Line Number: 957
User prompt
implementa la 2.3 ahora
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'length')' in or related to this line: 'for (var i = ProjectileFactory.activeProjectiles.length - 1; i >= 0; i--) {' Line Number: 6159
User prompt
Please fix the bug: 'ReferenceError: _typeof4 is not defined' in or related to this line: 'var threshold = _typeof4(gameConfigThreshold) === 'object' ? gameConfigThreshold[difficulty] : gameConfigThreshold;' Line Number: 5786
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'NORMAL')' in or related to this line: 'var base = GAME_CONFIG.enemies.skeleton.spawnInterval[difficulty];' Line Number: 5791
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'scaleX')' in or related to this line: 'manaBarBg = LK.getAsset('manaBarBg', {' Line Number: 5223
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'scaleX')' in or related to this line: 'manaBarBg = LK.getAsset('manaBarBg', {' Line Number: 5223
User prompt
Ahora implementa 2.1
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'skeleton')' in or related to this line: 'var base = GAME_CONFIG.enemies.skeleton.spawnInterval[difficulty];' Line Number: 5837
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'scaleX')' in or related to this line: 'manaBarBg = LK.getAsset('manaBarBg', {' Line Number: 5261
User prompt
implementa el 1.2
User prompt
implementa el 1.1
User prompt
hazme una lista con estos puntos
User prompt
haz que el critico que hizo la ultima resena haga una nueva con el codigo actual
User prompt
haz la 1.4
User prompt
entonces empieza con la 1.3
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'processOrbEnemyCollisions')' in or related to this line: 'self.processOrbEnemyCollisions = function () {' Line Number: 6199
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'processOrbEnemyCollisions')' in or related to this line: 'self.processOrbEnemyCollisions = function () {' Line Number: 6199
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'processOrbEnemyCollisions')' in or related to this line: 'self.processOrbEnemyCollisions = function () {' Line Number: 6199
User prompt
ahora pon la 1.2
User prompt
me gustaria empezar por la 1.1
User prompt
como lo puedo arreglar?
User prompt
1. **Cada proyectil se elimine del array cuando se destruye** 2. **Los proyectiles fuera de pantalla se detecten y eliminen correctamente** 3. **Los proyectiles que pierden su objetivo se eliminen automáticamente** 4. **El sistema de pool y los arrays se mantengan sincronizados**
User prompt
haz que se eliminen los proyectiles cuando golpean objetivos
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
// Intelligent Animation Manager with frame skipping optimization for performance enhancement
var AnimationManager = Container.expand(function () {
	var self = Container.call(this);
	// Performance monitoring for intelligent frame skipping
	self.performanceMetrics = {
		frameTime: 0,
		avgFrameTime: 16.67,
		// Target 60fps = 16.67ms per frame
		frameTimeHistory: [],
		maxHistorySize: 60,
		// Track last 60 frames
		lowPerformanceThreshold: 25,
		// Skip frames if above 25ms (40fps)
		criticalPerformanceThreshold: 33 // Aggressive skipping above 33ms (30fps)
	};
	// Frame skipping configuration
	self.skipConfig = {
		enabled: true,
		skipLevel: 0,
		// 0=none, 1=moderate, 2=aggressive
		lastSkipUpdate: 0,
		skipUpdateInterval: 30,
		// Update skip level every 30 frames
		entitySkipPatterns: {
			enemies: {
				moderate: 2,
				aggressive: 3
			},
			// Skip every 2nd or 3rd frame
			projectiles: {
				moderate: 1,
				aggressive: 2
			},
			effects: {
				moderate: 3,
				aggressive: 4
			},
			ui: {
				moderate: 1,
				aggressive: 1
			} // UI rarely skips
		}
	};
	// Optimized animation state tracking
	self.animatedEntities = [];
	self.entityGroups = {
		enemies: [],
		projectiles: [],
		effects: [],
		ui: []
	};
	// Performance analysis and frame skip decision
	self.analyzePerformance = function () {
		var currentTime = performance ? performance.now() : Date.now();
		if (self.performanceMetrics.lastFrameTime) {
			var frameTime = currentTime - self.performanceMetrics.lastFrameTime;
			self.performanceMetrics.frameTimeHistory.push(frameTime);
			// Maintain history size
			if (self.performanceMetrics.frameTimeHistory.length > self.performanceMetrics.maxHistorySize) {
				self.performanceMetrics.frameTimeHistory.shift();
			}
			// Calculate rolling average
			var sum = 0;
			for (var i = 0; i < self.performanceMetrics.frameTimeHistory.length; i++) {
				sum += self.performanceMetrics.frameTimeHistory[i];
			}
			self.performanceMetrics.avgFrameTime = sum / self.performanceMetrics.frameTimeHistory.length;
		}
		self.performanceMetrics.lastFrameTime = currentTime;
		// Update skip level based on performance
		if (LK.ticks - self.skipConfig.lastSkipUpdate > self.skipConfig.skipUpdateInterval) {
			self.updateSkipLevel();
			self.skipConfig.lastSkipUpdate = LK.ticks;
		}
	};
	// Intelligent skip level adjustment
	self.updateSkipLevel = function () {
		var avgTime = self.performanceMetrics.avgFrameTime;
		var newSkipLevel = 0;
		if (avgTime > self.performanceMetrics.criticalPerformanceThreshold) {
			newSkipLevel = 2; // Aggressive skipping
		} else if (avgTime > self.performanceMetrics.lowPerformanceThreshold) {
			newSkipLevel = 1; // Moderate skipping
		}
		// Smooth transitions to avoid jerky animation changes
		if (newSkipLevel > self.skipConfig.skipLevel) {
			self.skipConfig.skipLevel = newSkipLevel;
		} else if (newSkipLevel < self.skipConfig.skipLevel) {
			// Gradually reduce skip level to ensure stability
			self.skipConfig.skipLevel = Math.max(0, self.skipConfig.skipLevel - 1);
		}
	};
	// Register entity for optimized animation management
	self.registerEntity = function (entity, type, animationCallback) {
		if (!entity || typeof animationCallback !== 'function') return;
		var animationData = {
			entity: entity,
			type: type || 'effects',
			callback: animationCallback,
			lastUpdate: LK.ticks,
			skipCounter: 0,
			priority: self.getAnimationPriority(type)
		};
		self.animatedEntities.push(animationData);
		// Group by type for efficient processing
		if (!self.entityGroups[type]) {
			self.entityGroups[type] = [];
		}
		self.entityGroups[type].push(animationData);
		return animationData;
	};
	// Unregister entity from animation management
	self.unregisterEntity = function (entity) {
		// Remove from main list
		for (var i = self.animatedEntities.length - 1; i >= 0; i--) {
			if (self.animatedEntities[i].entity === entity) {
				self.animatedEntities.splice(i, 1);
				break;
			}
		}
		// Remove from type groups
		for (var type in self.entityGroups) {
			var group = self.entityGroups[type];
			for (var i = group.length - 1; i >= 0; i--) {
				if (group[i].entity === entity) {
					group.splice(i, 1);
					break;
				}
			}
		}
	};
	// Determine animation priority based on type and game state
	self.getAnimationPriority = function (type) {
		var priorities = {
			ui: 1,
			// Highest priority - always animate
			projectiles: 2,
			// High priority - important for gameplay
			enemies: 3,
			// Medium priority - can skip occasionally
			effects: 4 // Lower priority - can skip more frequently
		};
		return priorities[type] || 4;
	};
	// Intelligent frame skipping decision
	self.shouldSkipAnimation = function (animationData) {
		if (!self.skipConfig.enabled || self.skipConfig.skipLevel === 0) {
			return false;
		}
		var type = animationData.type;
		var skipPattern = self.skipConfig.entitySkipPatterns[type];
		if (!skipPattern) return false;
		var skipInterval = self.skipConfig.skipLevel === 1 ? skipPattern.moderate : skipPattern.aggressive;
		animationData.skipCounter++;
		// Skip based on pattern and priority
		if (animationData.skipCounter >= skipInterval) {
			animationData.skipCounter = 0;
			return true;
		}
		return false;
	};
	// Optimized animation update cycle with enhanced tween integration
	self.updateAnimations = function () {
		// Performance analysis first
		self.analyzePerformance();
		// Process animations by priority groups
		var typeOrder = ['ui', 'projectiles', 'enemies', 'effects'];
		for (var t = 0; t < typeOrder.length; t++) {
			var type = typeOrder[t];
			var group = self.entityGroups[type];
			if (!group) continue;
			for (var i = group.length - 1; i >= 0; i--) {
				var animData = group[i];
				// Clean up destroyed entities
				if (!animData.entity || !animData.entity.parent) {
					self.unregisterEntity(animData.entity);
					continue;
				}
				// Apply intelligent frame skipping
				if (self.shouldSkipAnimation(animData)) {
					continue; // Skip this frame
				}
				// Enhanced animation with tween-based smooth transitions
				try {
					// Apply performance-based tween timing adjustments
					if (self.skipConfig.skipLevel > 0) {
						// Slow down tweens during performance issues for smoother appearance
						var tweenSpeedMultiplier = 1 + self.skipConfig.skipLevel * 0.3;
						if (animData.entity._activeTweens) {
							for (var tweenIdx = 0; tweenIdx < animData.entity._activeTweens.length; tweenIdx++) {
								var activeTween = animData.entity._activeTweens[tweenIdx];
								if (activeTween && activeTween.duration) {
									activeTween.duration *= tweenSpeedMultiplier;
								}
							}
						}
					}
					// Execute animation callback with tween enhancement
					animData.callback.call(animData.entity);
					animData.lastUpdate = LK.ticks;
					// Add micro-tweens for smooth property transitions during low performance
					if (self.skipConfig.skipLevel > 1 && animData.type === 'enemies') {
						self.applyPerformanceTweens(animData.entity);
					}
				} catch (error) {
					// Remove problematic animations to prevent crashes
					console.error('Animation error:', error);
					self.unregisterEntity(animData.entity);
				}
			}
		}
	};
	// Enhanced animation wrapper for existing entities
	self.optimizeEntityAnimation = function (entity, originalUpdateFn) {
		if (!entity || typeof originalUpdateFn !== 'function') return;
		// Store original update function
		entity._originalUpdate = originalUpdateFn;
		// Create optimized update wrapper
		entity.update = function () {
			// Let AnimationManager handle the timing
			// The original update will be called via registerEntity callback
		};
		// Register with animation manager
		var entityType = 'effects'; // Default type
		if (entity.enemyType) entityType = 'enemies';else if (entity.type && entity.direction) entityType = 'projectiles';else if (entity.setText) entityType = 'ui';
		self.registerEntity(entity, entityType, originalUpdateFn);
	};
	// Batch animation processing for similar entities
	self.processBatchAnimations = function (entities, animationType) {
		if (!entities || entities.length === 0) return;
		var shouldProcess = true;
		// Apply batch-level frame skipping for large groups
		if (entities.length > 10 && self.skipConfig.skipLevel > 0) {
			var batchSkipChance = self.skipConfig.skipLevel === 2 ? 0.3 : 0.15;
			shouldProcess = Math.random() > batchSkipChance;
		}
		if (!shouldProcess) return;
		// Process entities with staggered updates to spread CPU load
		var processCount = Math.min(entities.length, self.skipConfig.skipLevel === 2 ? 5 : 8);
		for (var i = 0; i < processCount; i++) {
			var entity = entities[(LK.ticks + i) % entities.length];
			if (entity && entity.update && typeof entity.update === 'function') {
				entity.update();
			}
		}
	};
	// Apply performance-optimized micro-tweens for smooth animations during frame skipping
	self.applyPerformanceTweens = function (entity) {
		if (!entity || entity.x === undefined) return;
		// Store last position if not exists
		if (!entity._lastSmoothPos) {
			entity._lastSmoothPos = {
				x: entity.x,
				y: entity.y,
				rotation: entity.rotation || 0
			};
			return;
		}
		// Calculate movement delta
		var deltaX = entity.x - entity._lastSmoothPos.x;
		var deltaY = entity.y - entity._lastSmoothPos.y;
		var deltaRot = (entity.rotation || 0) - entity._lastSmoothPos.rotation;
		// Apply micro-tween only if significant movement detected
		if (Math.abs(deltaX) > 2 || Math.abs(deltaY) > 2 || Math.abs(deltaRot) > 0.1) {
			// Calculate performance-based smoothing factor
			var performanceSmoothing = self.calculatePerformanceSmoothingFactor();
			var adaptiveDuration = Math.floor(performanceSmoothing.duration);
			// Create smooth transition tween with performance-adjusted parameters
			tween(entity, {
				x: entity.x,
				y: entity.y,
				rotation: entity.rotation || 0
			}, {
				duration: adaptiveDuration,
				easing: performanceSmoothing.easing
			});
		}
		// Update stored position
		entity._lastSmoothPos.x = entity.x;
		entity._lastSmoothPos.y = entity.y;
		entity._lastSmoothPos.rotation = entity.rotation || 0;
	};
	// Calculate performance-based smoothing parameters for tween optimization
	self.calculatePerformanceSmoothingFactor = function () {
		var avgFrameTime = self.performanceMetrics.avgFrameTime;
		var skipLevel = self.skipConfig.skipLevel;
		// Base smoothing configuration
		var smoothingConfig = {
			duration: 100,
			easing: tween.easeOut
		};
		// Adjust based on performance metrics
		if (avgFrameTime > self.performanceMetrics.criticalPerformanceThreshold) {
			// Critical performance: minimal tweening
			smoothingConfig.duration = 50;
			smoothingConfig.easing = tween.linear;
		} else if (avgFrameTime > self.performanceMetrics.lowPerformanceThreshold) {
			// Low performance: reduced smoothing
			smoothingConfig.duration = 75;
			smoothingConfig.easing = tween.easeOut;
		} else if (skipLevel === 0) {
			// High performance: enhanced smoothing
			smoothingConfig.duration = 150;
			smoothingConfig.easing = tween.easeInOut;
		}
		return smoothingConfig;
	};
	// Get performance statistics for debugging
	self.getPerformanceStats = function () {
		return {
			avgFrameTime: Math.round(self.performanceMetrics.avgFrameTime * 100) / 100,
			skipLevel: self.skipConfig.skipLevel,
			entityCount: self.animatedEntities.length,
			groupCounts: {
				enemies: self.entityGroups.enemies ? self.entityGroups.enemies.length : 0,
				projectiles: self.entityGroups.projectiles ? self.entityGroups.projectiles.length : 0,
				effects: self.entityGroups.effects ? self.entityGroups.effects.length : 0,
				ui: self.entityGroups.ui ? self.entityGroups.ui.length : 0
			}
		};
	};
	return self;
});
var Coin = Container.expand(function () {
	var self = Container.call(this);
	var coinGraphics = self.attachAsset('coin', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.bobOffset = Math.random() * Math.PI * 2;
	self.initialY = 0;
	self.update = function () {
		if (self.initialY === 0) {
			self.initialY = self.y;
		}
		// Only do bobbing animation and collection if not animating to coin counter
		if (!self.isAnimating) {
			// Bobbing animation
			self.y = self.initialY + Math.sin(LK.ticks * 0.1 + self.bobOffset) * 10;
			// Check collection by wizard
			if (wizard && self.intersects(wizard)) {
				self.collect();
			}
		}
	};
	self.collect = function () {
		LK.getSound('coinCollect').play();
		LK.setScore(LK.getScore() + 5);
		coinCounter++;
		coinText.setText('Coins: ' + coinCounter);
		// Remove from coins array
		for (var i = coins.length - 1; i >= 0; i--) {
			if (coins[i] === self) {
				coins.splice(i, 1);
				break;
			}
		}
		self.destroy();
	};
	return self;
});
// Unified visual effects manager for streamlined and efficient effects system
var EffectManager = Container.expand(function () {
	var self = Container.call(this);
	// Effect configuration templates for consistent visual effects
	self.effectTemplates = {
		damage: {
			asset: 'projectileGlow',
			color: 0xFF0000,
			duration: 50
		},
		impact: {
			asset: 'projectileGlow',
			color: 0xFFAA00,
			duration: 450,
			scale: 1.5
		},
		explosion: {
			asset: 'projectileGlow',
			color: 0xFF6600,
			duration: 600,
			scale: 4.0
		},
		heal: {
			asset: 'energySphere',
			color: 0x00FF00,
			duration: 500,
			scale: 2.0
		},
		shield: {
			asset: 'shield',
			color: 0x0080FF,
			duration: 300,
			scale: 3.0
		},
		lightning: {
			asset: 'spell',
			color: 0x00FFFF,
			duration: 500,
			scale: 2.0
		}
	};
	// Unified damage application with streamlined visual feedback
	self.applyDamage = function (target, amount, damageType) {
		if (!target || target.health === undefined) return false;
		target.health -= amount;
		target.animationState = 'attacking';
		// Create streamlined damage effects using templates
		self.createEffect('damage', target, {
			amount: amount
		});
		self.createDamageText(target.x, target.y, amount, target.typeConfig ? target.typeConfig.damageTextColor : 0xFF4444);
		// Return to walking state after brief animation
		tween({}, {}, {
			duration: 300,
			onFinish: function onFinish() {
				if (target.animationState === 'attacking') target.animationState = 'walking';
			}
		});
		return true;
	};
	// Streamlined effect creation using pooled objects with enhanced tween animations
	self.createEffect = function (effectType, target, options) {
		var template = self.effectTemplates[effectType];
		if (!template) return;
		// Get effect from pool
		var effect = globalObjectPool.getObject('effect', {
			x: target.x,
			y: target.y,
			scaleX: 0.3,
			scaleY: 0.3,
			anchorX: 0.5,
			anchorY: 0.5
		});
		if (!effect) {
			// Fallback to direct creation if pool fails
			effect = game.addChild(LK.getAsset(template.asset, {
				anchorX: 0.5,
				anchorY: 0.5,
				x: target.x,
				y: target.y,
				scaleX: 0.3,
				scaleY: 0.3
			}));
		} else {
			game.addChild(effect);
		}
		effect.tint = options.color || template.color;
		effect.alpha = 0.8;
		var targetScale = options.scale || template.scale || 1.5; // Provide default scale value
		// Enhanced tween animation with multiple sequential effects
		tween(effect, {
			scaleX: targetScale * 0.7,
			scaleY: targetScale * 0.7,
			alpha: 1.0,
			rotation: Math.PI * 0.25
		}, {
			duration: template.duration * 0.3,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				// Second phase: expand and fade
				tween(effect, {
					scaleX: targetScale,
					scaleY: targetScale,
					alpha: 0.6,
					rotation: Math.PI * 0.5
				}, {
					duration: template.duration * 0.4,
					easing: tween.easeInOut,
					onFinish: function onFinish() {
						// Final phase: rapid fade with slight shrink
						tween(effect, {
							scaleX: targetScale * 1.2,
							scaleY: targetScale * 1.2,
							alpha: 0,
							rotation: Math.PI
						}, {
							duration: template.duration * 0.3,
							easing: tween.easeIn,
							onFinish: function onFinish() {
								// Return to pool instead of destroying
								if (effect.pooled) {
									globalObjectPool.returnObject(effect);
								} else {
									effect.destroy();
								}
							}
						});
					}
				});
			}
		});
	};
	// Efficient damage text with object pooling for optimal memory usage
	self.createDamageText = function (x, y, damage, color) {
		// Get damage text from pool
		var damageText = globalObjectPool.getObject('damageText', {
			x: x + (Math.random() - 0.5) * 60,
			y: y - 40
		});
		if (!damageText) {
			// Fallback to direct creation if pool fails
			damageText = new Text2('-' + damage, {
				size: 120,
				fill: color || 0xFF4444,
				font: "monospace"
			});
			damageText.x = x + (Math.random() - 0.5) * 60;
			damageText.y = y - 40;
		} else {
			// Configure pooled text - ensure style object exists
			if (!damageText.style) {
				damageText.style = {
					size: 120,
					fill: color || 0xFF4444,
					font: "monospace"
				};
			} else {
				damageText.style.fill = color || 0xFF4444;
			}
		}
		damageText.setText('-' + damage);
		damageText.anchor.set(0.5, 0.5);
		game.addChild(damageText);
		var startY = damageText.y;
		tween(damageText, {
			y: startY - 120,
			alpha: 0,
			scaleX: 1.5,
			scaleY: 1.5
		}, {
			duration: 1000,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				// Return to pool instead of destroying
				if (damageText.pooled) {
					globalObjectPool.returnObject(damageText);
				} else {
					damageText.destroy();
				}
			}
		});
	};
	// Streamlined flash effect wrapper
	self.createFlashEffect = function (target, color, duration) {
		LK.effects.flashObject(target, color, duration);
	};
	// Unified visual effect dispatcher with enhanced tween-based effects
	self.createVisualEffect = function (type, target, config) {
		var options = config || {};
		// Calculate performance-based effect scaling
		var performanceScale = self.calculateEffectPerformanceScale();
		switch (type) {
			case 'impact':
				self.createEnhancedImpactEffect(target, options, performanceScale);
				break;
			case 'explosion':
				self.createEnhancedExplosionEffect(target, options, performanceScale);
				break;
			case 'heal':
				self.createEnhancedHealEffect(target, options, performanceScale);
				break;
			case 'shield':
				self.createEnhancedShieldEffect(target, options, performanceScale);
				break;
			case 'lightning':
				self.createEnhancedLightningEffect(target, options, performanceScale);
				break;
			default:
				// Fallback to original effect creation
				self.createEffect(type, target, options);
				break;
		}
	};
	// Calculate performance-based effect scaling for optimal visual quality
	self.calculateEffectPerformanceScale = function () {
		var skipLevel = globalAnimationManager ? globalAnimationManager.skipConfig.skipLevel : 0;
		var avgFrameTime = globalAnimationManager ? globalAnimationManager.performanceMetrics.avgFrameTime : 16.67;
		return {
			particleCount: skipLevel > 1 ? 0.3 : skipLevel > 0 ? 0.6 : 1.0,
			duration: skipLevel > 1 ? 0.5 : skipLevel > 0 ? 0.75 : 1.0,
			complexity: avgFrameTime > 25 ? 'simple' : avgFrameTime > 20 ? 'medium' : 'complex'
		};
	};
	// Enhanced impact effect with sophisticated tween sequences
	self.createEnhancedImpactEffect = function (target, options, performanceScale) {
		var template = self.effectTemplates.impact;
		var effect = self.getEffectFromPool('impact', target);
		if (effect) {
			effect.tint = options.color || template.color;
			effect.alpha = 0.1;
			// Multi-stage tween sequence for dynamic impact
			tween(effect, {
				scaleX: template.scale * 0.3,
				scaleY: template.scale * 0.3,
				alpha: 1.0,
				rotation: Math.PI * 0.1
			}, {
				duration: template.duration * 0.2 * performanceScale.duration,
				easing: tween.elasticOut,
				onFinish: function onFinish() {
					tween(effect, {
						scaleX: template.scale * 1.2,
						scaleY: template.scale * 1.2,
						alpha: 0.7,
						rotation: Math.PI * 0.3
					}, {
						duration: template.duration * 0.5 * performanceScale.duration,
						easing: tween.bounceOut,
						onFinish: function onFinish() {
							tween(effect, {
								scaleX: template.scale * 0.1,
								scaleY: template.scale * 0.1,
								alpha: 0,
								rotation: Math.PI * 0.5
							}, {
								duration: template.duration * 0.3 * performanceScale.duration,
								easing: tween.easeIn,
								onFinish: function onFinish() {
									self.returnEffectToPool(effect);
								}
							});
						}
					});
				}
			});
		}
	};
	// Enhanced explosion effect with cascading tween animations
	self.createEnhancedExplosionEffect = function (target, options, performanceScale) {
		var template = self.effectTemplates.explosion;
		var particleCount = Math.floor(6 * performanceScale.particleCount);
		for (var i = 0; i < particleCount; i++) {
			var particle = self.getEffectFromPool('explosion', target);
			if (!particle) continue;
			var angle = Math.PI * 2 / particleCount * i;
			var distance = template.scale * 30;
			particle.tint = options.color || template.color;
			particle.alpha = 0.8;
			particle.scaleX = 0.2;
			particle.scaleY = 0.2;
			// Staggered explosion particles with individual tween paths
			var delay = i * 50 * performanceScale.duration;
			tween({}, {}, {
				duration: delay,
				onFinish: function (particleRef, angleRef, distanceRef) {
					return function () {
						tween(particleRef, {
							x: target.x + Math.cos(angleRef) * distanceRef,
							y: target.y + Math.sin(angleRef) * distanceRef,
							scaleX: template.scale * 0.8,
							scaleY: template.scale * 0.8,
							alpha: 1.0
						}, {
							duration: template.duration * 0.4 * performanceScale.duration,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								tween(particleRef, {
									scaleX: template.scale * 1.5,
									scaleY: template.scale * 1.5,
									alpha: 0,
									rotation: Math.PI
								}, {
									duration: template.duration * 0.6 * performanceScale.duration,
									easing: tween.easeIn,
									onFinish: function onFinish() {
										self.returnEffectToPool(particleRef);
									}
								});
							}
						});
					};
				}(particle, angle, distance)
			});
		}
	};
	// Enhanced heal effect with pulsing tween animations
	self.createEnhancedHealEffect = function (target, options, performanceScale) {
		var template = self.effectTemplates.heal;
		var effect = self.getEffectFromPool('heal', target);
		if (effect) {
			effect.tint = options.color || template.color;
			effect.alpha = 0.3;
			effect.scaleX = 0.5;
			effect.scaleY = 0.5;
			// Pulsing heal animation with multiple cycles
			var pulseCount = performanceScale.complexity === 'simple' ? 2 : 4;
			self.createPulsingTween(effect, template, pulseCount, performanceScale);
		}
	};
	// Enhanced shield effect with orbital tween movement
	self.createEnhancedShieldEffect = function (target, options, performanceScale) {
		var template = self.effectTemplates.shield;
		var orbCount = performanceScale.complexity === 'simple' ? 3 : 6;
		for (var i = 0; i < orbCount; i++) {
			var orb = self.getEffectFromPool('shield', target);
			if (!orb) continue;
			orb.tint = options.color || template.color;
			orb.alpha = 0.6;
			orb.scaleX = 0.3;
			orb.scaleY = 0.3;
			var angle = Math.PI * 2 / orbCount * i;
			var radius = template.scale * 40;
			// Orbital shield animation
			self.createOrbitalTween(orb, target, angle, radius, template, performanceScale);
		}
	};
	// Enhanced lightning effect with branching tween paths
	self.createEnhancedLightningEffect = function (target, options, performanceScale) {
		var template = self.effectTemplates.lightning;
		var branchCount = performanceScale.complexity === 'simple' ? 2 : 5;
		for (var i = 0; i < branchCount; i++) {
			var bolt = self.getEffectFromPool('lightning', target);
			if (!bolt) continue;
			bolt.tint = options.color || template.color;
			bolt.alpha = 1.0;
			bolt.scaleX = 0.1;
			bolt.scaleY = 2.0;
			var angle = (Math.random() - 0.5) * Math.PI * 0.5;
			bolt.rotation = angle;
			// Lightning flash with rapid tween sequence
			tween(bolt, {
				scaleX: template.scale * 0.5,
				alpha: 0.8
			}, {
				duration: 100 * performanceScale.duration,
				easing: tween.easeOut,
				onFinish: function (boltRef) {
					return function () {
						tween(boltRef, {
							scaleX: template.scale * 1.2,
							scaleY: template.scale * 3.0,
							alpha: 0.3
						}, {
							duration: 200 * performanceScale.duration,
							easing: tween.easeInOut,
							onFinish: function onFinish() {
								tween(boltRef, {
									scaleX: 0.1,
									scaleY: 0.1,
									alpha: 0
								}, {
									duration: 150 * performanceScale.duration,
									easing: tween.easeIn,
									onFinish: function onFinish() {
										self.returnEffectToPool(boltRef);
									}
								});
							}
						});
					};
				}(bolt)
			});
		}
	};
	// Helper method for pulsing tween animations
	self.createPulsingTween = function (effect, template, pulseCount, performanceScale) {
		var currentPulse = 0;
		function doPulse() {
			if (currentPulse >= pulseCount) {
				self.returnEffectToPool(effect);
				return;
			}
			tween(effect, {
				scaleX: template.scale * 1.2,
				scaleY: template.scale * 1.2,
				alpha: 0.8
			}, {
				duration: template.duration * 0.3 * performanceScale.duration,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(effect, {
						scaleX: template.scale * 0.7,
						scaleY: template.scale * 0.7,
						alpha: 0.4
					}, {
						duration: template.duration * 0.3 * performanceScale.duration,
						easing: tween.easeIn,
						onFinish: function onFinish() {
							currentPulse++;
							doPulse();
						}
					});
				}
			});
		}
		doPulse();
	};
	// Helper method for orbital tween animations
	self.createOrbitalTween = function (orb, target, startAngle, radius, template, performanceScale) {
		var currentAngle = startAngle;
		var duration = template.duration * performanceScale.duration;
		function updateOrbitalPosition() {
			orb.x = target.x + Math.cos(currentAngle) * radius;
			orb.y = target.y + Math.sin(currentAngle) * radius;
			currentAngle += 0.1;
			if (duration > 0) {
				duration -= 16; // Approximate frame time
				tween({}, {}, {
					duration: 16,
					onFinish: updateOrbitalPosition
				});
			} else {
				self.returnEffectToPool(orb);
			}
		}
		updateOrbitalPosition();
	};
	// Helper method to get effect from pool
	self.getEffectFromPool = function (type, target) {
		var effect = globalObjectPool ? globalObjectPool.getObject('effect', {
			x: target.x,
			y: target.y,
			scaleX: 0.3,
			scaleY: 0.3,
			anchorX: 0.5,
			anchorY: 0.5
		}) : null;
		if (!effect) {
			effect = game.addChild(LK.getAsset('projectileGlow', {
				anchorX: 0.5,
				anchorY: 0.5,
				x: target.x,
				y: target.y,
				scaleX: 0.3,
				scaleY: 0.3
			}));
		} else {
			game.addChild(effect);
		}
		return effect;
	};
	// Helper method to return effect to pool
	self.returnEffectToPool = function (effect) {
		if (effect.pooled && globalObjectPool) {
			globalObjectPool.returnObject(effect);
		} else if (effect.parent) {
			effect.destroy();
		}
	};
	return self;
});
// Unified Enemy class - handles all enemy types with streamlined configuration
var Enemy = Container.expand(function (type, config) {
	var self = Container.call(this);
	// Initialize properties
	self.enemyType = type || 'skeleton';
	self.currentFrame = 1;
	self.animationTimer = 0;
	self.animationState = 'walking';
	self.frozen = false;
	self.frozenTimer = 0;
	self.isDying = false;
	self.lastX = 0;
	self.speedTweenStarted = false;
	// Get and apply configuration
	self.typeConfig = GAME_CONFIG.createEnemyConfig(self.enemyType, config || {});
	self.animationSpeed = self.typeConfig.animationSpeed || 15;
	self.health = self.typeConfig.health || self.typeConfig.baseHealth;
	self.maxHealth = self.health;
	self.speed = self.typeConfig.speed || self.typeConfig.baseSpeed;
	// Create animation frames
	self.animationFrames = [];
	for (var i = 1; i <= 4; i++) {
		var frameGraphics = self.attachAsset(self.typeConfig.assetPrefix + i, {
			anchorX: 0.5,
			anchorY: 1.0,
			scaleX: self.typeConfig.scale,
			scaleY: self.typeConfig.scale
		});
		frameGraphics.visible = i === 1;
		if (self.typeConfig.tint) frameGraphics.tint = self.typeConfig.tint;
		self.animationFrames.push(frameGraphics);
	}
	// Create health bar for mini boss
	if (self.enemyType === 'miniBoss') {
		self.healthBarBg = game.addChild(LK.getAsset('miniBossHealthBarBg', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: GAME_CONFIG.ui.miniBossHealthBar.x,
			y: GAME_CONFIG.ui.miniBossHealthBar.y,
			scaleX: GAME_CONFIG.ui.miniBossHealthBar.bgScaleX,
			scaleY: GAME_CONFIG.ui.miniBossHealthBar.bgScaleY
		}));
		self.healthBarFg = game.addChild(LK.getAsset('miniBossHealthBar', {
			anchorX: 0.0,
			anchorY: 0.5,
			x: GAME_CONFIG.ui.miniBossHealthBar.x - 200,
			y: GAME_CONFIG.ui.miniBossHealthBar.y,
			scaleX: GAME_CONFIG.ui.miniBossHealthBar.fgScaleX,
			scaleY: GAME_CONFIG.ui.miniBossHealthBar.fgScaleY
		}));
		self.healthText = new Text2('Boss Health: ' + self.health + '/' + self.maxHealth, {
			size: GAME_CONFIG.ui.miniBossHealthBar.textSize,
			fill: 0xFFFFFF,
			font: "monospace"
		});
		self.healthText.anchor.set(0.5, 0.5);
		self.healthText.x = GAME_CONFIG.ui.miniBossHealthBar.x;
		self.healthText.y = GAME_CONFIG.ui.miniBossHealthBar.textY;
		game.addChild(self.healthText);
	}
	// Update health bar for mini boss
	self.updateHealthBar = function () {
		if (self.enemyType !== 'miniBoss' || !self.healthBarFg) return;
		var healthPercent = self.health / self.maxHealth;
		self.healthBarFg.scaleX = healthPercent;
		self.healthText.setText('Boss Health: ' + self.health + '/' + self.maxHealth);
		if (healthPercent > 0.6) {
			self.healthBarFg.tint = 0xff0000;
		} else if (healthPercent > 0.3) {
			self.healthBarFg.tint = 0xff4500;
		} else {
			self.healthBarFg.tint = 0x8B0000;
		}
	};
	// Optimized animation system with intelligent frame skipping
	self.updateAnimation = function () {
		self.animationTimer++;
		var frameSpeed = self.animationSpeed;
		// Apply performance-based frame speed adjustments
		if (globalAnimationManager && globalAnimationManager.skipConfig.skipLevel > 0) {
			var skipMultiplier = 1 + globalAnimationManager.skipConfig.skipLevel * 0.5;
			frameSpeed = Math.floor(frameSpeed * skipMultiplier);
		}
		if (self.animationState === 'attacking') frameSpeed = Math.floor(frameSpeed * 0.5);else if (self.animationState === 'dying') frameSpeed = Math.floor(frameSpeed * 1.3);else if (self.animationState === 'idle') frameSpeed = Math.floor(frameSpeed * 1.7);
		if (self.animationTimer >= frameSpeed) {
			self.animationTimer = 0;
			self.animationFrames[self.currentFrame - 1].visible = false;
			if (self.animationState === 'walking') {
				self.currentFrame++;
				if (self.currentFrame > 4) self.currentFrame = 1;
			} else if (self.animationState === 'attacking') {
				self.currentFrame++;
				if (self.currentFrame > 4) self.currentFrame = 2;
			} else if (self.animationState === 'dying') {
				if (self.currentFrame < 4) self.currentFrame++;
			} else if (self.animationState === 'idle') {
				self.currentFrame = self.currentFrame === 1 ? 2 : 1;
			}
			self.animationFrames[self.currentFrame - 1].visible = true;
		}
	};
	self.update = function () {
		if (tutorial && tutorial.isActive || self.isDying) return;
		// Animation and speed progression
		self.updateAnimation();
		if (!self.speedTweenStarted) {
			self.speedTweenStarted = true;
			tween(self, {
				speed: self.speed * 1.5
			}, {
				duration: 10000,
				easing: tween.easeOut
			});
		}
		// Handle frozen state
		if (self.frozen) {
			self.frozenTimer--;
			if (self.frozenTimer <= 0) self.frozen = false;
			return;
		}
		// Enhanced movement toward wizard with advanced tween smoothing
		if (wizard) {
			var dx = wizard.x - self.x;
			var dy = wizard.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance > 0) {
				var speedMult = self.timeSlowed ? self.timeSlowAmount : 1.0;
				var newX = self.x + dx / distance * self.speed * speedMult;
				var newY = self.y + dy / distance * self.speed * speedMult;
				// Enhanced tween-based movement system with performance adaptation
				var movementConfig = self.calculateMovementTweenConfig();
				if (movementConfig.useTween) {
					// Advanced movement tween with easing based on performance
					tween(self, {
						x: newX,
						y: newY
					}, {
						duration: movementConfig.duration,
						easing: movementConfig.easing
					});
				} else {
					// Direct assignment during critical performance issues
					self.x = newX;
					self.y = newY;
				}
				var flipScale = dx < 0 ? -self.typeConfig.scale : self.typeConfig.scale;
				// Enhanced scale transitions with performance-aware tweening
				self.applyEnhancedFlipAnimation(flipScale);
			} else {
				// Enhanced vertical movement fallback with adaptive smoothing
				var fallbackConfig = self.calculateFallbackMovementConfig();
				if (fallbackConfig.useTween) {
					tween(self, {
						y: self.y + self.speed
					}, {
						duration: fallbackConfig.duration,
						easing: fallbackConfig.easing
					});
				} else {
					self.y += self.speed;
				}
			}
		}
	};
	self.takeDamage = function (damage) {
		globalDamageHandler.applyDamage(self, damage, 'physical');
		if (self.enemyType === 'miniBoss') self.updateHealthBar();
		if (self.health <= 0) self.die();
	};
	self.down = function (x, y, obj) {
		if (tutorial && tutorial.isActive || self.isDying) return;
		if (wizard && wizard.attackCooldown > 0) {
			LK.effects.flashObject(self, 0xFF0000, 200);
			return;
		}
		// Vibration feedback
		if (typeof LK.vibrate === 'function') {
			if (Array.isArray(self.typeConfig.vibration)) {
				LK.vibrate(self.typeConfig.vibration);
			} else {
				LK.vibrate(self.typeConfig.vibration);
			}
		}
		selectedEnemy = self;
		LK.effects.flashObject(self, 0xFFFF00, 500);
		if (wizard && projectiles.length < 10) {
			var projectile = ProjectileFactory.createBasicAttack(wizard, self);
			projectile.targetEnemy = self;
			projectiles.push(projectile);
			LK.getSound('spellCast').play();
			wizard.attackCooldown = 30;
		}
	};
	self.die = function () {
		var arrayToUpdate = null;
		if (self.enemyType === 'skeleton') arrayToUpdate = enemies;else if (self.enemyType === 'ogre') arrayToUpdate = ogres;else if (self.enemyType === 'knight') arrayToUpdate = knights;else if (self.enemyType === 'miniBoss') arrayToUpdate = miniBosses;
		if (globalDeathHandler) {
			globalDeathHandler.executeEnemyDeath(self, arrayToUpdate);
		}
	};
	// Calculate optimal movement tween configuration based on performance
	self.calculateMovementTweenConfig = function () {
		var skipLevel = globalAnimationManager ? globalAnimationManager.skipConfig.skipLevel : 0;
		var avgFrameTime = globalAnimationManager ? globalAnimationManager.performanceMetrics.avgFrameTime : 16.67;
		// Base configuration for high performance
		var config = {
			useTween: true,
			duration: 16,
			easing: tween.linear
		};
		// Adjust based on performance metrics
		if (skipLevel === 0 && avgFrameTime < 20) {
			// Excellent performance: enhanced smoothing
			config.duration = 16;
			config.easing = tween.easeOut;
		} else if (skipLevel === 1 || avgFrameTime < 25) {
			// Good performance: standard smoothing
			config.duration = 20;
			config.easing = tween.linear;
		} else if (skipLevel === 2 || avgFrameTime < 33) {
			// Moderate performance: reduced smoothing
			config.duration = 32;
			config.easing = tween.linear;
		} else {
			// Critical performance: disable tweening
			config.useTween = false;
		}
		return config;
	};
	// Calculate fallback movement configuration for vertical movement
	self.calculateFallbackMovementConfig = function () {
		var skipLevel = globalAnimationManager ? globalAnimationManager.skipConfig.skipLevel : 0;
		return {
			useTween: skipLevel === 0,
			duration: skipLevel === 0 ? 16 : 32,
			easing: skipLevel === 0 ? tween.linear : tween.easeOut
		};
	};
	// Apply enhanced flip animation with performance-aware tweening
	self.applyEnhancedFlipAnimation = function (targetScale) {
		var flipConfig = self.calculateFlipAnimationConfig();
		for (var frameIdx = 0; frameIdx < self.animationFrames.length; frameIdx++) {
			var frame = self.animationFrames[frameIdx];
			var currentScale = frame.scaleX;
			if (Math.abs(currentScale - targetScale) > 0.1) {
				if (flipConfig.useTween) {
					// Enhanced flip animation with bounce effect for high performance
					tween(frame, {
						scaleX: targetScale * 1.1
					}, {
						duration: flipConfig.duration * 0.3,
						easing: tween.easeOut,
						onFinish: function (frameRef, finalScale) {
							return function () {
								tween(frameRef, {
									scaleX: finalScale
								}, {
									duration: flipConfig.duration * 0.7,
									easing: tween.bounceOut
								});
							};
						}(frame, targetScale)
					});
				} else {
					// Direct assignment for low performance
					frame.scaleX = targetScale;
				}
			} else {
				frame.scaleX = targetScale;
			}
		}
	};
	// Calculate flip animation configuration based on performance
	self.calculateFlipAnimationConfig = function () {
		var skipLevel = globalAnimationManager ? globalAnimationManager.skipConfig.skipLevel : 0;
		var avgFrameTime = globalAnimationManager ? globalAnimationManager.performanceMetrics.avgFrameTime : 16.67;
		// Enhanced flip animations for good performance
		if (skipLevel === 0 && avgFrameTime < 20) {
			return {
				useTween: true,
				duration: 300,
				useEnhancedEffects: true
			};
		}
		// Standard flip animations for moderate performance
		if (skipLevel <= 1 && avgFrameTime < 30) {
			return {
				useTween: true,
				duration: 200,
				useEnhancedEffects: false
			};
		}
		// Minimal animations for low performance
		return {
			useTween: false,
			duration: 0,
			useEnhancedEffects: false
		};
	};
	return self;
});
// Unified EnemyManager for streamlined enemy lifecycle management
var EnemyManager = Container.expand(function () {
	var self = Container.call(this);
	// Consolidated enemy arrays for efficient management
	self.enemyCollections = {
		skeleton: [],
		ogre: [],
		knight: [],
		miniBoss: []
	};
	// Unified enemy configuration templates
	self.enemyTemplates = {
		skeleton: {
			baseHealth: 100,
			baseSpeed: 3,
			damage: 20,
			coinReward: 1
		},
		ogre: {
			baseHealth: 200,
			baseSpeed: 2.5,
			damage: 30,
			coinReward: 1
		},
		knight: {
			baseHealth: 300,
			baseSpeed: 2,
			damage: 40,
			coinReward: 1
		},
		miniBoss: {
			baseHealth: 3000,
			baseSpeed: 4,
			damage: 75,
			coinReward: 5
		}
	};
	// Streamlined enemy creation with unified configuration
	self.createEnemy = function (type, difficulty, level, pathOverride) {
		var template = self.enemyTemplates[type];
		if (!template) return null;
		var config = GAME_CONFIG.createEnemyConfig(type, {
			health: template.baseHealth,
			speed: template.baseSpeed * (1 + level * 0.3)
		});
		var enemy = new Enemy(type, config);
		enemy.pathIndex = pathOverride || self.selectOptimalPath(type);
		self.positionEnemy(enemy, type);
		self.applyDifficultyModifications(enemy, type, difficulty);
		return enemy;
	};
	// Unified enemy positioning system
	self.positionEnemy = function (enemy, type) {
		var spawnPos = GAME_CONFIG.paths.spawnPositions[enemy.pathIndex];
		if (spawnPos) {
			enemy.x = Math.max(50, Math.min(1998, spawnPos.x));
			enemy.y = type === 'miniBoss' ? -200 : Math.max(-200, Math.min(2732 + 100, spawnPos.y));
			enemy.lastX = enemy.x;
		}
	};
	// Streamlined difficulty modifications
	self.applyDifficultyModifications = function (enemy, type, difficulty) {
		if (type === 'miniBoss') {
			enemy.updateHealthBar();
			LK.effects.flashScreen(0x8B0000, 1000);
		} else if (type === 'skeleton' && Math.random() < 0.3) {
			LK.getSound('enemyGrowl').play();
		}
		// Elite enemy system for hard difficulty
		if (difficulty === 'DIFICIL' && enemyKillCounter >= 20 && Math.random() < 0.15) {
			self.createEliteEnemy(enemy, type);
		}
	};
	// Unified elite enemy creation
	self.createEliteEnemy = function (enemy, type) {
		var eliteMultipliers = {
			health: 1.8,
			speed: 1.3,
			color: 0xFF6600
		};
		if (type === 'ogre') eliteMultipliers.color = 0xFF0000;
		if (type === 'knight') eliteMultipliers.color = 0xFFD700;
		if (type === 'miniBoss') eliteMultipliers.color = 0x8B0000;
		enemy.health *= eliteMultipliers.health;
		enemy.speed *= eliteMultipliers.speed;
		enemy.maxHealth = enemy.health;
		enemy.isElite = true;
		for (var i = 0; i < enemy.animationFrames.length; i++) {
			enemy.animationFrames[i].tint = eliteMultipliers.color;
		}
	};
	// Optimized path selection system
	self.selectOptimalPath = function (type) {
		if (type === 'skeleton' && enemyKillCounter < 5) return 0;
		if (type === 'miniBoss') return 0;
		var available = [];
		for (var i = 0; i < 5; i++) {
			if (pathConsecutiveSpawns[i] < 2) available.push(i);
		}
		if (available.length === 0) {
			for (var i = 0; i < 5; i++) pathConsecutiveSpawns[i] = 0;
			available = [0, 1, 2, 3, 4];
		}
		return available[Math.floor(Math.random() * available.length)];
	};
	// Unified enemy collection management
	self.addToCollection = function (enemy, type) {
		if (self.enemyCollections[type]) {
			self.enemyCollections[type].push(enemy);
		}
	};
	// Streamlined enemy removal system
	self.removeFromCollection = function (enemy, type) {
		var collection = self.enemyCollections[type];
		if (collection) {
			for (var i = collection.length - 1; i >= 0; i--) {
				if (collection[i] === enemy) {
					collection.splice(i, 1);
					break;
				}
			}
		}
	};
	// Get all enemies as unified array
	self.getAllEnemies = function () {
		var allEnemies = [];
		for (var type in self.enemyCollections) {
			allEnemies = allEnemies.concat(self.enemyCollections[type]);
		}
		return allEnemies;
	};
	return self;
});
var EnergyOrb = Container.expand(function () {
	var self = Container.call(this);
	// Create energy sphere visual
	var sphereGraphics = self.attachAsset('energySphere', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1.5,
		scaleY: 1.5
	});
	// Add glowing effect
	sphereGraphics.alpha = 0.8;
	self.attackTimer = 0;
	self.attackInterval = 180; // 3 seconds at 60fps
	self.orbitalAngle = 0;
	self.orbitalRadius = 120;
	self.update = function () {
		// Pause energy orb when tutorial is active
		if (tutorial && tutorial.isActive) {
			return;
		}
		// Upgrade menu removed - no pause needed
		// Keep sphere at wizard's position (stationary relative to wizard)
		if (wizard) {
			self.x = wizard.x + 140; // Position further to the right side of wizard
			self.y = wizard.y - 20; // Position slightly lower relative to wizard
		}
		// Pulsing glow effect
		var pulse = 1 + Math.sin(LK.ticks * 0.2) * 0.3;
		sphereGraphics.scaleX = 1.5 * pulse;
		sphereGraphics.scaleY = 1.5 * pulse;
		// Attack timer - keep original interval regardless of upgrades
		self.attackTimer++;
		if (self.attackTimer >= 180) {
			// Fixed at 3 seconds
			self.attackTimer = 0;
			self.attackClosestEnemy();
		}
	};
	self.attackClosestEnemy = function () {
		var closestEnemy = null;
		var closestDistance = Infinity;
		// Check all enemy types for closest one
		var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
		for (var i = 0; i < allEnemies.length; i++) {
			var enemy = allEnemies[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;
			}
		}
		// Attack closest enemy if found
		if (closestEnemy) {
			// Create energy beam projectile using unified factory
			var energyBeam = ProjectileFactory.createProjectile('energyBeam', self.x, self.y, closestEnemy.x, closestEnemy.y, {
				targetEnemy: closestEnemy
			});
			// Flash effect on sphere when attacking
			tween(sphereGraphics, {
				scaleX: 2.5,
				scaleY: 2.5,
				alpha: 1.0
			}, {
				duration: 200,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(sphereGraphics, {
						scaleX: 1.5,
						scaleY: 1.5,
						alpha: 0.8
					}, {
						duration: 200,
						easing: tween.easeIn
					});
				}
			});
			LK.getSound('spellCast').play();
		}
	};
	return self;
});
var GameMenu = Container.expand(function () {
	var self = Container.call(this);
	// Menu background image instead of cave background
	var menuBg = self.attachAsset('menuBackground', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 2732 / 2,
		scaleX: 25.0,
		scaleY: 35.0
	});
	menuBg.alpha = 1.0;
	// Title text
	var titleText = new Text2('WIZARD DEFENDER', {
		size: 150,
		fill: 0xFFD700,
		font: "monospace"
	});
	titleText.anchor.set(0.5, 0.5);
	titleText.x = 2048 / 2;
	titleText.y = 800;
	self.addChild(titleText);
	// Instructions text
	var instructionsText = new Text2('TAP ENEMIES TO ATTACK\nDEFEND YOUR CASTLE!', {
		size: 80,
		fill: 0xFFFFFF,
		font: "monospace"
	});
	instructionsText.anchor.set(0.5, 0.5);
	instructionsText.x = 2048 / 2;
	instructionsText.y = 1200;
	self.addChild(instructionsText);
	// Start button
	var startButton = self.attachAsset('wizard1', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 1500,
		scaleX: 2,
		scaleY: 2
	});
	var startButtonText = new Text2('START GAME', {
		size: 100,
		fill: 0x000000,
		font: "monospace"
	});
	startButtonText.anchor.set(0.5, 0.5);
	startButtonText.x = 2048 / 2;
	startButtonText.y = 1600;
	self.addChild(startButtonText);
	// Configuration button
	var configButton = self.attachAsset('pathSelector', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 1800,
		scaleX: 4,
		scaleY: 2
	});
	configButton.tint = 0x4169E1;
	var configButtonText = new Text2('CONFIGURACION', {
		size: 80,
		fill: 0xFFFFFF,
		font: "monospace"
	});
	configButtonText.anchor.set(0.5, 0.5);
	configButtonText.x = 2048 / 2;
	configButtonText.y = 1800;
	self.addChild(configButtonText);
	// Shop button
	var shopButton = self.attachAsset('pathSelector', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 1950,
		scaleX: 4,
		scaleY: 2
	});
	shopButton.tint = 0xFF6B35;
	var shopButtonText = new Text2('TIENDA', {
		size: 80,
		fill: 0xFFFFFF,
		font: "monospace"
	});
	shopButtonText.anchor.set(0.5, 0.5);
	shopButtonText.x = 2048 / 2;
	shopButtonText.y = 1950;
	self.addChild(shopButtonText);
	// Deck button
	var deckButton = self.attachAsset('pathSelector', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 2150,
		scaleX: 4,
		scaleY: 2
	});
	deckButton.tint = 0x8A2BE2;
	var deckButtonText = new Text2('DECK HECHIZOS', {
		size: 80,
		fill: 0xFFFFFF,
		font: "monospace"
	});
	deckButtonText.anchor.set(0.5, 0.5);
	deckButtonText.x = 2048 / 2;
	deckButtonText.y = 2150;
	self.addChild(deckButtonText);
	// Tutorial button (only show if tutorial was completed before)
	if (storage.tutorialCompleted) {
		var tutorialButton = self.attachAsset('pathSelector', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: 2048 / 2,
			y: 2350,
			scaleX: 4,
			scaleY: 2
		});
		tutorialButton.tint = 0x2E8B57;
		var tutorialButtonText = new Text2('TUTORIAL', {
			size: 80,
			fill: 0xFFFFFF,
			font: "monospace"
		});
		tutorialButtonText.anchor.set(0.5, 0.5);
		tutorialButtonText.x = 2048 / 2;
		tutorialButtonText.y = 2350;
		self.addChild(tutorialButtonText);
	}
	// Button interaction
	self.down = function (x, y, obj) {
		// Handle configuration menu interactions
		if (self.configMode) {
			// Music volume adjustment
			if (y >= 1150 && y <= 1250) {
				var currentMusicVolume = storage.musicVolume || 0.7;
				var newMusicVolume = Math.min(1.0, currentMusicVolume + 0.1);
				if (newMusicVolume > 1.0) newMusicVolume = 0.0;
				storage.musicVolume = newMusicVolume;
				self.musicVolumeText.setText('VOLUMEN MUSICA: ' + Math.round(newMusicVolume * 100) + '%');
				return;
			}
			// Sound volume adjustment
			if (y >= 1350 && y <= 1450) {
				var currentSoundVolume = storage.soundVolume || 1.0;
				var newSoundVolume = Math.min(1.0, currentSoundVolume + 0.1);
				if (newSoundVolume > 1.0) newSoundVolume = 0.0;
				storage.soundVolume = newSoundVolume;
				self.soundVolumeText.setText('VOLUMEN SONIDO: ' + Math.round(newSoundVolume * 100) + '%');
				return;
			}
			// Difficulty adjustment
			if (y >= 1550 && y <= 1650) {
				var currentDifficulty = storage.difficulty || 'NORMAL';
				var difficulties = ['FACIL', 'NORMAL', 'DIFICIL'];
				var currentIndex = difficulties.indexOf(currentDifficulty);
				var newIndex = (currentIndex + 1) % difficulties.length;
				var newDifficulty = difficulties[newIndex];
				storage.difficulty = newDifficulty;
				self.difficultyText.setText('DIFICULTAD: ' + newDifficulty);
				return;
			}
			// Back button
			if (y >= 1950 && y <= 2050) {
				self.hideConfigMenu();
				return;
			}
			// Block all other interactions when config menu is active
			return;
		}
		// Handle deck menu interactions
		if (self.deckMode) {
			// Check deck card clicks with better hit detection
			for (var i = 0; i < self.deckElements.length; i++) {
				var element = self.deckElements[i];
				if (element.spellId && element.isDeckCard) {
					var cardX = element.x;
					var cardY = element.y;
					if (x >= cardX - 175 && x <= cardX + 175 && y >= cardY - 225 && y <= cardY + 225) {
						// Visual feedback before removal
						LK.effects.flashObject(element, 0xFF0000, 300);
						// Remove from deck
						if (self.spellDeck.removeFromDeck(element.spellId)) {
							self.refreshDeckDisplay();
							LK.effects.flashScreen(0xFF8800, 200);
							// Show removal message
							var removeText = new Text2('HECHIZO REMOVIDO', {
								size: 60,
								fill: 0xFF6666,
								font: "monospace"
							});
							removeText.anchor.set(0.5, 0.5);
							removeText.x = 2048 / 2;
							removeText.y = 2200;
							self.addChild(removeText);
							// Animate and remove message
							tween(removeText, {
								alpha: 0,
								y: removeText.y - 100
							}, {
								duration: 1500,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									if (removeText.parent) removeText.destroy();
								}
							});
						} else {
							LK.effects.flashScreen(0xFF0000, 200);
						}
						return;
					}
				}
			}
			// Check available card clicks with better hit detection
			for (var i = 0; i < self.availableElements.length; i++) {
				var element = self.availableElements[i];
				if (element.spellId && !element.isDeckCard) {
					var cardX = element.x;
					var cardY = element.y;
					if (x >= cardX - 175 && x <= cardX + 175 && y >= cardY - 225 && y <= cardY + 225) {
						// Visual feedback before addition
						LK.effects.flashObject(element, 0x00FF00, 300);
						// Add to deck
						if (self.spellDeck.addToDeck(element.spellId)) {
							self.refreshDeckDisplay();
							LK.effects.flashScreen(0x00FF00, 200);
							// Show addition message
							var addText = new Text2('HECHIZO AÑADIDO', {
								size: 60,
								fill: 0x66FF66,
								font: "monospace"
							});
							addText.anchor.set(0.5, 0.5);
							addText.x = 2048 / 2;
							addText.y = 2200;
							self.addChild(addText);
							// Animate and remove message
							tween(addText, {
								alpha: 0,
								y: addText.y - 100
							}, {
								duration: 1500,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									if (addText.parent) addText.destroy();
								}
							});
						} else {
							LK.effects.flashScreen(0xFF0000, 200);
							// Show error message
							var errorText = new Text2('DECK LLENO (MAX 5)', {
								size: 50,
								fill: 0xFF6666,
								font: "monospace"
							});
							errorText.anchor.set(0.5, 0.5);
							errorText.x = 2048 / 2;
							errorText.y = 2200;
							self.addChild(errorText);
							// Animate and remove message
							tween(errorText, {
								alpha: 0,
								y: errorText.y - 100
							}, {
								duration: 2000,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									if (errorText.parent) errorText.destroy();
								}
							});
						}
						return;
					}
				}
			}
			// Deck back button
			if (y >= 2350 && y <= 2650) {
				self.hideDeck();
			}
			// Block all other interactions when deck menu is active
			return;
		}
		// Handle shop menu interactions
		if (self.shopMode) {
			// Shop item purchase buttons
			for (var i = 0; i < 3; i++) {
				var itemY = 1100 + i * 200;
				if (y >= itemY - 50 && y <= itemY + 50 && x >= 2048 / 2 + 200 && x <= 2048 / 2 + 400) {
					// Purchase item logic
					var shopItems = [{
						name: 'POCION SALUD',
						cost: 10
					}, {
						name: 'ESCUDO MAGICO',
						cost: 15
					}, {
						name: 'ESPADA MALDITA',
						cost: 20
					}];
					var item = shopItems[i];
					if (coinCounter >= item.cost) {
						coinCounter -= item.cost;
						// Apply item effect based on type
						if (i === 0) {
							// Health potion
							if (wizard) {
								wizard.health = Math.min(wizard.health + 50, wizard.maxHealth);
								updateHealthBar();
							}
						} else if (i === 1) {
							// Magic shield
							if (wizard) {
								wizard.shieldActive = true;
								wizard.maxShieldHits = 3;
								wizard.currentShieldHits = 0;
							}
						} else if (i === 2) {
							// Cursed sword - temporary damage boost
							if (wizard) {
								wizard.tempDamageBoost = true;
								wizard.tempDamageTimer = 1800; // 30 seconds at 60fps
							}
						}
						LK.effects.flashScreen(0x00FF00, 300);
					} else {
						LK.effects.flashScreen(0xFF0000, 300);
					}
					return;
				}
			}
			// Shop back button
			if (y >= 1950 && y <= 2050) {
				self.hideShop();
				return;
			}
			// Block all other interactions when shop menu is active
			return;
		}
		// Check if configuration button was clicked
		if (y >= 1700 && y <= 1900 && x >= 2048 / 2 - 200 && x <= 2048 / 2 + 200) {
			// Show configuration menu
			self.showConfigMenu();
		} else if (y >= 1850 && y <= 2050 && x >= 2048 / 2 - 200 && x <= 2048 / 2 + 200) {
			// Show shop menu
			self.showShop();
		} else if (y >= 2050 && y <= 2250 && x >= 2048 / 2 - 200 && x <= 2048 / 2 + 200) {
			// Show deck menu
			self.showDeck();
		} else if (storage.tutorialCompleted && y >= 2250 && y <= 2450 && x >= 2048 / 2 - 200 && x <= 2048 / 2 + 200) {
			// Show tutorial again
			if (tutorial) {
				self.visible = false;
				tutorial.startTutorial();
			}
		} else if (y >= 1450 && y <= 1650) {
			// Start the game by hiding menu
			self.startGame();
		}
	};
	self.showConfigMenu = function () {
		if (!self.configOverlay) {
			self.configOverlay = self.createMenuOverlay(0x000000);
			self.configTitle = self.createMenuText('CONFIGURACION', 2048 / 2, 800, 120, 0xFFD700);
			self.musicVolumeText = self.createMenuText('VOLUMEN MUSICA: ' + Math.round((storage.musicVolume || 0.7) * 100) + '%', 2048 / 2, 1200, 80, 0xFFFFFF);
			self.soundVolumeText = self.createMenuText('VOLUMEN SONIDO: ' + Math.round((storage.soundVolume || 1.0) * 100) + '%', 2048 / 2, 1400, 80, 0xFFFFFF);
			self.difficultyText = self.createMenuText('DIFICULTAD: ' + (storage.difficulty || 'NORMAL'), 2048 / 2, 1600, 80, 0xFFFFFF);
			self.backButton = self.createMenuButton('coin', 2048 / 2, 2000, 0x00FF00);
			self.backText = self.createMenuText('VOLVER', 2048 / 2, 2000, 80, 0xFFFFFF);
		}
		self.configOverlay.visible = true;
		self.configMode = true;
	};
	self.hideConfigMenu = function () {
		if (self.configOverlay) {
			self.configOverlay.destroy();
			self.configOverlay = null;
		}
		// Remove all configuration text elements
		if (self.musicVolumeText) {
			self.musicVolumeText.destroy();
			self.musicVolumeText = null;
		}
		if (self.soundVolumeText) {
			self.soundVolumeText.destroy();
			self.soundVolumeText = null;
		}
		if (self.difficultyText) {
			self.difficultyText.destroy();
			self.difficultyText = null;
		}
		// Remove back button elements
		if (self.backButton) {
			self.backButton.destroy();
			self.backButton = null;
		}
		if (self.backText) {
			self.backText.destroy();
			self.backText = null;
		}
		// Remove configuration title
		if (self.configTitle) {
			self.configTitle.destroy();
			self.configTitle = null;
		}
		// Remove all configuration children that were added
		for (var i = self.children.length - 1; i >= 0; i--) {
			var child = self.children[i];
			// Remove config-related elements (title, texts, buttons created in showConfigMenu)
			if (child.setText && child.text && (child.text.includes('CONFIGURACION') || child.text.includes('VOLUMEN') || child.text.includes('DIFICULTAD') || child.text.includes('VOLVER'))) {
				child.destroy();
			}
		}
		self.configMode = false;
		// Reset to show main menu elements
		self.visible = true;
	};
	self.showShop = function () {
		if (!self.shopOverlay) {
			self.shopOverlay = self.createMenuOverlay(0x000033);
			self.shopTitle = self.createMenuText('TIENDA', 2048 / 2, 800, 120, 0xFFD700);
			var shopItems = self.getShopItemsData();
			self.initializeShopArrays();
			self.createShopItems(shopItems);
			self.shopBackButton = self.createMenuButton('coin', 2048 / 2, 2000, 0x00FF00);
			self.shopBackText = self.createMenuText('VOLVER', 2048 / 2, 2000, 80, 0xFFFFFF);
		}
		self.shopOverlay.visible = true;
		self.shopMode = true;
	};
	self.hideShop = function () {
		if (self.shopOverlay) {
			self.shopOverlay.destroy();
			self.shopOverlay = null;
		}
		// Remove shop title
		if (self.shopTitle) {
			self.shopTitle.destroy();
			self.shopTitle = null;
		}
		// Remove shop back button elements
		if (self.shopBackButton) {
			self.shopBackButton.destroy();
			self.shopBackButton = null;
		}
		if (self.shopBackText) {
			self.shopBackText.destroy();
			self.shopBackText = null;
		}
		// Remove all shop icons
		if (self.shopIcons) {
			for (var i = 0; i < self.shopIcons.length; i++) {
				if (self.shopIcons[i]) {
					self.shopIcons[i].destroy();
				}
			}
			self.shopIcons = [];
		}
		// Remove all shop texts
		if (self.shopTexts) {
			for (var i = 0; i < self.shopTexts.length; i++) {
				if (self.shopTexts[i]) {
					self.shopTexts[i].destroy();
				}
			}
			self.shopTexts = [];
		}
		// Remove all shop buy buttons
		if (self.shopBuyButtons) {
			for (var i = 0; i < self.shopBuyButtons.length; i++) {
				if (self.shopBuyButtons[i]) {
					self.shopBuyButtons[i].destroy();
				}
			}
			self.shopBuyButtons = [];
		}
		// Remove all shop buy texts
		if (self.shopBuyTexts) {
			for (var i = 0; i < self.shopBuyTexts.length; i++) {
				if (self.shopBuyTexts[i]) {
					self.shopBuyTexts[i].destroy();
				}
			}
			self.shopBuyTexts = [];
		}
		// Remove all shop children that were added
		for (var i = self.children.length - 1; i >= 0; i--) {
			var child = self.children[i];
			// Remove shop-related elements
			if (child.setText && child.text && (child.text.includes('TIENDA') || child.text.includes('POCION') || child.text.includes('ESCUDO') || child.text.includes('ESPADA') || child.text.includes('COMPRAR'))) {
				child.destroy();
			}
		}
		self.shopMode = false;
		// Reset to show main menu elements
		self.visible = true;
	};
	self.showDeck = function () {
		if (!self.deckOverlay) {
			self.deckOverlay = self.createMenuOverlay(0x1a0a2e);
			self.deckTitle = self.createMenuText('DECK DE HECHIZOS', 2048 / 2, 600, 100, 0xFFD700);
			self.initializeDeckArrays();
			if (!self.spellDeck) self.spellDeck = new SpellDeck();
			self.refreshDeckDisplay();
			self.deckBackButton = self.createMenuButton('coin', 2048 / 2, 2500, 0x00FF00);
			self.deckBackText = self.createMenuText('VOLVER', 2048 / 2, 2500, 80, 0xFFFFFF);
		}
		self.deckOverlay.visible = true;
		self.deckMode = true;
		self.refreshDeckDisplay();
	};
	self.initializeDeckArrays = function () {
		if (!self.deckElements) self.deckElements = [];
		if (!self.availableElements) self.availableElements = [];
	};
	self.refreshDeckDisplay = function () {
		if (!self.spellDeck) return;
		// Clear existing deck elements
		for (var i = 0; i < self.deckElements.length; i++) {
			if (self.deckElements[i] && self.deckElements[i].parent) {
				self.deckElements[i].destroy();
			}
		}
		self.deckElements = [];
		// Clear existing available elements
		for (var i = 0; i < self.availableElements.length; i++) {
			if (self.availableElements[i] && self.availableElements[i].parent) {
				self.availableElements[i].destroy();
			}
		}
		self.availableElements = [];
		// Add helpful instructions at the top
		var instructionText = new Text2('TOCA CARTAS PARA AÑADIR/QUITAR DEL DECK', {
			size: 50,
			fill: 0x00FF00,
			font: "monospace"
		});
		instructionText.anchor.set(0.5, 0.5);
		instructionText.x = 2048 / 2;
		instructionText.y = 700;
		self.addChild(instructionText);
		self.deckElements.push(instructionText);
		// Display current deck (top section)
		var deckLabel = new Text2('MI DECK ACTUAL (' + self.spellDeck.currentDeck.length + '/5):', {
			size: 70,
			fill: 0xFFD700,
			font: "monospace"
		});
		deckLabel.anchor.set(0.5, 0.5);
		deckLabel.x = 2048 / 2;
		deckLabel.y = 800;
		self.addChild(deckLabel);
		self.deckElements.push(deckLabel);
		// Add deck instruction
		var deckInstruction = new Text2('TOCA PARA QUITAR', {
			size: 40,
			fill: 0xFF6666,
			font: "monospace"
		});
		deckInstruction.anchor.set(0.5, 0.5);
		deckInstruction.x = 2048 / 2;
		deckInstruction.y = 850;
		self.addChild(deckInstruction);
		self.deckElements.push(deckInstruction);
		// Display deck cards with better spacing
		for (var i = 0; i < 5; i++) {
			var cardX = 200 + i * 350;
			var cardY = 1050;
			if (i < self.spellDeck.currentDeck.length) {
				var spell = self.spellDeck.getSpell(self.spellDeck.currentDeck[i]);
				if (spell) {
					// Card background with glow effect
					var cardBg = self.attachAsset('spellCard', {
						anchorX: 0.5,
						anchorY: 0.5,
						x: cardX,
						y: cardY,
						scaleX: 3.5,
						scaleY: 4.5
					});
					cardBg.tint = self.spellDeck.getRarityColor(spell.rarity);
					cardBg.spellId = spell.id;
					cardBg.isDeckCard = true;
					cardBg.alpha = 0.9;
					self.deckElements.push(cardBg);
					// Add border glow
					var glowBorder = self.attachAsset('spellCardBg', {
						anchorX: 0.5,
						anchorY: 0.5,
						x: cardX,
						y: cardY,
						scaleX: 4,
						scaleY: 5
					});
					glowBorder.tint = 0x00FF00;
					glowBorder.alpha = 0.3;
					self.deckElements.push(glowBorder);
					// Card name
					var cardName = new Text2(spell.name, {
						size: 35,
						fill: 0xFFFFFF,
						font: "monospace"
					});
					cardName.anchor.set(0.5, 0.5);
					cardName.x = cardX;
					cardName.y = cardY - 60;
					self.addChild(cardName);
					self.deckElements.push(cardName);
					// Card description
					var cardDesc = new Text2(spell.description, {
						size: 25,
						fill: 0xCCCCCC,
						font: "monospace",
						wordWrap: true,
						wordWrapWidth: 250
					});
					cardDesc.anchor.set(0.5, 0.5);
					cardDesc.x = cardX;
					cardDesc.y = cardY + 20;
					self.addChild(cardDesc);
					self.deckElements.push(cardDesc);
					// Card stats
					var statsText = '';
					if (spell.damage) statsText += 'Daño: ' + spell.damage + '\n';
					if (spell.healing) statsText += 'Cura: ' + spell.healing + '\n';
					if (spell.manaCost) statsText += 'Mana: ' + spell.manaCost;
					if (statsText) {
						var cardStats = new Text2(statsText, {
							size: 20,
							fill: 0xFFD700,
							font: "monospace"
						});
						cardStats.anchor.set(0.5, 0.5);
						cardStats.x = cardX;
						cardStats.y = cardY + 80;
						self.addChild(cardStats);
						self.deckElements.push(cardStats);
					}
				}
			} else {
				// Empty slot
				var emptySlot = self.attachAsset('spellCardBg', {
					anchorX: 0.5,
					anchorY: 0.5,
					x: cardX,
					y: cardY,
					scaleX: 3.5,
					scaleY: 4.5
				});
				emptySlot.tint = 0x444444;
				emptySlot.alpha = 0.5;
				self.deckElements.push(emptySlot);
				var emptyText = new Text2('VACIO', {
					size: 40,
					fill: 0x666666,
					font: "monospace"
				});
				emptyText.anchor.set(0.5, 0.5);
				emptyText.x = cardX;
				emptyText.y = cardY;
				self.addChild(emptyText);
				self.deckElements.push(emptyText);
			}
		}
		// Display available spells (bottom section)
		var availableLabel = new Text2('HECHIZOS DISPONIBLES PARA AÑADIR:', {
			size: 60,
			fill: 0xFFD700,
			font: "monospace"
		});
		availableLabel.anchor.set(0.5, 0.5);
		availableLabel.x = 2048 / 2;
		availableLabel.y = 1350;
		self.addChild(availableLabel);
		self.availableElements.push(availableLabel);
		// Add available instruction
		var availableInstruction = new Text2('TOCA PARA AÑADIR A TU DECK', {
			size: 40,
			fill: 0x66FF66,
			font: "monospace"
		});
		availableInstruction.anchor.set(0.5, 0.5);
		availableInstruction.x = 2048 / 2;
		availableInstruction.y = 1400;
		self.addChild(availableInstruction);
		self.availableElements.push(availableInstruction);
		// Display available spell cards
		var availableSpells = [];
		for (var i = 0; i < self.spellDeck.availableSpells.length; i++) {
			var spell = self.spellDeck.availableSpells[i];
			if (spell.unlocked && self.spellDeck.currentDeck.indexOf(spell.id) === -1) {
				availableSpells.push(spell);
			}
		}
		if (availableSpells.length === 0) {
			var noSpellsText = new Text2('NO HAY HECHIZOS DISPONIBLES\nDESBLOQUEA MAS JUGANDO', {
				size: 50,
				fill: 0x888888,
				font: "monospace"
			});
			noSpellsText.anchor.set(0.5, 0.5);
			noSpellsText.x = 2048 / 2;
			noSpellsText.y = 1600;
			self.addChild(noSpellsText);
			self.availableElements.push(noSpellsText);
		}
		for (var i = 0; i < availableSpells.length && i < 8; i++) {
			var spell = availableSpells[i];
			var cardX = 150 + i % 4 * 450;
			var cardY = 1550 + Math.floor(i / 4) * 400;
			// Card background with hover effect
			var cardBg = self.attachAsset('spellCard', {
				anchorX: 0.5,
				anchorY: 0.5,
				x: cardX,
				y: cardY,
				scaleX: 3.2,
				scaleY: 4.2
			});
			cardBg.tint = self.spellDeck.getRarityColor(spell.rarity);
			cardBg.spellId = spell.id;
			cardBg.isDeckCard = false;
			cardBg.alpha = 0.8;
			self.availableElements.push(cardBg);
			// Add selection glow
			var selectionGlow = self.attachAsset('spellCardBg', {
				anchorX: 0.5,
				anchorY: 0.5,
				x: cardX,
				y: cardY,
				scaleX: 3.7,
				scaleY: 4.7
			});
			selectionGlow.tint = 0x00FFFF;
			selectionGlow.alpha = 0.2;
			self.availableElements.push(selectionGlow);
			// Card name
			var cardName = new Text2(spell.name, {
				size: 32,
				fill: 0xFFFFFF,
				font: "monospace"
			});
			cardName.anchor.set(0.5, 0.5);
			cardName.x = cardX;
			cardName.y = cardY - 60;
			self.addChild(cardName);
			self.availableElements.push(cardName);
			// Card description
			var cardDesc = new Text2(spell.description, {
				size: 22,
				fill: 0xCCCCCC,
				font: "monospace",
				wordWrap: true,
				wordWrapWidth: 280
			});
			cardDesc.anchor.set(0.5, 0.5);
			cardDesc.x = cardX;
			cardDesc.y = cardY + 10;
			self.addChild(cardDesc);
			self.availableElements.push(cardDesc);
			// Card stats
			var statsText = '';
			if (spell.damage) statsText += 'Daño: ' + spell.damage + '\n';
			if (spell.healing) statsText += 'Cura: ' + spell.healing + '\n';
			if (spell.manaCost) statsText += 'Mana: ' + spell.manaCost;
			if (statsText) {
				var cardStats = new Text2(statsText, {
					size: 18,
					fill: 0xFFD700,
					font: "monospace"
				});
				cardStats.anchor.set(0.5, 0.5);
				cardStats.x = cardX;
				cardStats.y = cardY + 70;
				self.addChild(cardStats);
				self.availableElements.push(cardStats);
			}
			// Rarity indicator
			var rarityText = new Text2(spell.rarity.toUpperCase(), {
				size: 20,
				fill: self.spellDeck.getRarityColor(spell.rarity),
				font: "monospace"
			});
			rarityText.anchor.set(0.5, 0.5);
			rarityText.x = cardX;
			rarityText.y = cardY + 100;
			self.addChild(rarityText);
			self.availableElements.push(rarityText);
		}
	};
	self.hideDeck = function () {
		if (self.deckOverlay) {
			self.deckOverlay.destroy();
			self.deckOverlay = null;
		}
		// Remove deck title
		if (self.deckTitle) {
			self.deckTitle.destroy();
			self.deckTitle = null;
		}
		// Remove deck back button elements
		if (self.deckBackButton) {
			self.deckBackButton.destroy();
			self.deckBackButton = null;
		}
		if (self.deckBackText) {
			self.deckBackText.destroy();
			self.deckBackText = null;
		}
		// Clear deck elements
		for (var i = 0; i < self.deckElements.length; i++) {
			if (self.deckElements[i] && self.deckElements[i].parent) {
				self.deckElements[i].destroy();
			}
		}
		self.deckElements = [];
		// Clear available elements
		for (var i = 0; i < self.availableElements.length; i++) {
			if (self.availableElements[i] && self.availableElements[i].parent) {
				self.availableElements[i].destroy();
			}
		}
		self.availableElements = [];
		// Remove all deck-related children
		for (var i = self.children.length - 1; i >= 0; i--) {
			var child = self.children[i];
			if (child.setText && child.text && (child.text.includes('DECK') || child.text.includes('HECHIZOS') || child.text.includes('ACTUAL') || child.text.includes('DISPONIBLES'))) {
				child.destroy();
			}
		}
		self.deckMode = false;
		self.visible = true;
	};
	// Unified menu element factory methods
	self.createMenuOverlay = function (tintColor) {
		var overlay = self.addChild(LK.getAsset('startMenuBackground', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: 2048 / 2,
			y: 2732 / 2,
			scaleX: 1.0,
			scaleY: 1.0
		}));
		overlay.alpha = 1.0;
		overlay.tint = tintColor;
		return overlay;
	};
	self.createMenuText = function (text, x, y, size, fill) {
		var textElement = new Text2(text, {
			size: size,
			fill: fill,
			font: "monospace"
		});
		textElement.anchor.set(0.5, 0.5);
		textElement.x = x;
		textElement.y = y;
		self.addChild(textElement);
		return textElement;
	};
	self.createMenuButton = function (asset, x, y, tintColor) {
		var button = self.attachAsset(asset, {
			anchorX: 0.5,
			anchorY: 0.5,
			x: x,
			y: y,
			scaleX: 2,
			scaleY: 2
		});
		button.tint = tintColor;
		return button;
	};
	self.getShopItemsData = function () {
		return [{
			name: 'POCION SALUD',
			description: 'Restaura 50 HP',
			cost: 10,
			icon: 'energySphere'
		}, {
			name: 'ESCUDO MAGICO',
			description: 'Bloquea 3 ataques',
			cost: 15,
			icon: 'shield'
		}, {
			name: 'ESPADA MALDITA',
			description: 'Daño x2 por 30s',
			cost: 20,
			icon: 'spell'
		}];
	};
	self.initializeShopArrays = function () {
		if (!self.shopIcons) self.shopIcons = [];
		if (!self.shopTexts) self.shopTexts = [];
		if (!self.shopBuyButtons) self.shopBuyButtons = [];
		if (!self.shopBuyTexts) self.shopBuyTexts = [];
	};
	self.createShopItems = function (shopItems) {
		for (var i = 0; i < shopItems.length; i++) {
			var item = shopItems[i];
			var yPos = 1100 + i * 200;
			var itemIcon = self.attachAsset(item.icon, {
				anchorX: 0.5,
				anchorY: 0.5,
				x: 2048 / 2 - 300,
				y: yPos,
				scaleX: 2,
				scaleY: 2
			});
			itemIcon.tint = 0xFFD700;
			self.shopIcons.push(itemIcon);
			var itemText = new Text2(item.name + '\n' + item.description + '\nCosto: ' + item.cost + ' monedas', {
				size: 60,
				fill: 0xFFFFFF,
				font: "monospace"
			});
			itemText.anchor.set(0, 0.5);
			itemText.x = 2048 / 2 - 200;
			itemText.y = yPos;
			self.addChild(itemText);
			self.shopTexts.push(itemText);
			var buyButton = self.attachAsset('coin', {
				anchorX: 0.5,
				anchorY: 0.5,
				x: 2048 / 2 + 300,
				y: yPos,
				scaleX: 2,
				scaleY: 2
			});
			buyButton.tint = 0x00FF00;
			buyButton.itemIndex = i;
			self.shopBuyButtons.push(buyButton);
			var buyText = new Text2('COMPRAR', {
				size: 50,
				fill: 0xFFFFFF,
				font: "monospace"
			});
			buyText.anchor.set(0.5, 0.5);
			buyText.x = 2048 / 2 + 300;
			buyText.y = yPos;
			self.addChild(buyText);
			self.shopBuyTexts.push(buyText);
		}
	};
	self.startGame = function () {
		// Check if this is a new player (no tutorial completed)
		if (!storage.tutorialCompleted && tutorial) {
			// Show tutorial for new players
			self.visible = false;
			// Small delay to ensure menu is hidden before tutorial starts
			tween({}, {}, {
				duration: 100,
				onFinish: function onFinish() {
					tutorial.startTutorial();
				}
			});
			// Tutorial started successfully
			return;
		}
		// Hide menu and start game normally
		self.visible = false;
		gameStarted = true;
		// Show cave background when game starts
		if (backgroundMap) {
			backgroundMap.visible = true;
		}
		// Show all game elements
		wizard.visible = true;
		for (var i = 0; i < paths.length; i++) {
			paths[i].visible = true;
		}
		// Show all stone path segments and make them visible
		for (var i = 0; i < game.children.length; i++) {
			var child = game.children[i];
			if (child.pathIndex !== undefined && child !== paths[child.pathIndex]) {
				child.visible = true;
				// Check if it's a stone path segment or path number
				if (child.alpha !== undefined && child.setText === undefined) {
					child.alpha = 0; // Keep stone paths invisible
				}
			}
		}
		coinText.visible = true;
		killCountText.visible = true;
		tapText.visible = true;
		healthBarBg.visible = true;
		healthBar.visible = true;
		healthText.visible = true;
		// Show spell UI
		if (manaBarBg) manaBarBg.visible = true;
		if (manaBar) manaBar.visible = true;
		if (manaText) manaText.visible = true;
		for (var i = 0; i < spellSlots.length; i++) {
			spellSlots[i].visible = true;
		}
		// Start medieval music with user's volume setting
		var musicVolume = storage.musicVolume || 0.7;
		LK.playMusic('medievalTheme', {
			volume: musicVolume,
			fade: {
				start: 0,
				end: musicVolume,
				duration: 2000
			}
		});
	};
	return self;
});
// Unified Object Pool system for streamlined memory management and performance optimization
var ObjectPool = Container.expand(function () {
	var self = Container.call(this);
	// Pool configurations for different object types
	self.poolConfig = {
		projectile: {
			maxSize: 50,
			createFn: function createFn() {
				return new Projectile('projectile');
			}
		},
		fireBall: {
			maxSize: 30,
			createFn: function createFn() {
				return new Projectile('fireBall');
			}
		},
		energyBeam: {
			maxSize: 20,
			createFn: function createFn() {
				return new Projectile('energyBeam');
			}
		},
		effect: {
			maxSize: 100,
			createFn: function createFn() {
				return LK.getAsset('projectileGlow', {
					anchorX: 0.5,
					anchorY: 0.5
				});
			}
		},
		damageText: {
			maxSize: 50,
			createFn: function createFn() {
				return new Text2('', {
					size: 120,
					fill: 0xFF4444,
					font: "monospace"
				});
			}
		},
		coin: {
			maxSize: 30,
			createFn: function createFn() {
				return new Coin();
			}
		}
	};
	// Active pools storage
	self.activePools = {};
	// Initialize all pools
	self.initializePools = function () {
		for (var type in self.poolConfig) {
			self.activePools[type] = {
				available: [],
				inUse: [],
				config: self.poolConfig[type]
			};
			// Pre-populate pool with initial objects
			var initialSize = Math.min(10, self.poolConfig[type].maxSize);
			for (var i = 0; i < initialSize; i++) {
				var obj = self.poolConfig[type].createFn();
				obj.poolType = type;
				obj.visible = false;
				obj.pooled = true;
				self.activePools[type].available.push(obj);
			}
		}
	};
	// Get object from pool
	self.getObject = function (type, initData) {
		var pool = self.activePools[type];
		if (!pool) return null;
		var obj;
		if (pool.available.length > 0) {
			// Reuse existing object
			obj = pool.available.pop();
			self.resetObject(obj, type);
		} else if (pool.inUse.length < pool.config.maxSize) {
			// Create new object if under limit
			obj = pool.config.createFn();
			obj.poolType = type;
			obj.pooled = true;
		} else {
			// Pool exhausted, reuse oldest in-use object
			obj = pool.inUse.shift();
			self.resetObject(obj, type);
		}
		// Initialize object with provided data
		if (initData) {
			for (var key in initData) {
				obj[key] = initData[key];
			}
		}
		obj.visible = true;
		obj.inPool = false;
		pool.inUse.push(obj);
		return obj;
	};
	// Return object to pool
	self.returnObject = function (obj) {
		if (!obj || !obj.pooled) return;
		var pool = self.activePools[obj.poolType];
		if (!pool) return;
		// Remove from in-use array
		var inUseIndex = pool.inUse.indexOf(obj);
		if (inUseIndex !== -1) {
			pool.inUse.splice(inUseIndex, 1);
		}
		// Clean up object
		obj.visible = false;
		obj.inPool = true;
		self.resetObject(obj, obj.poolType);
		// Return to available pool if not full
		if (pool.available.length < pool.config.maxSize) {
			pool.available.push(obj);
		} else {
			// Pool is full, destroy excess object
			if (obj.parent) obj.parent.removeChild(obj);
		}
	};
	// Reset object to default state
	self.resetObject = function (obj, type) {
		// Common reset properties
		obj.x = 0;
		obj.y = 0;
		obj.rotation = 0;
		obj.alpha = 1;
		obj.scaleX = 1;
		obj.scaleY = 1;
		obj.tint = 0xFFFFFF;
		// Type-specific resets
		switch (type) {
			case 'projectile':
			case 'fireBall':
			case 'energyBeam':
				obj.direction = {
					x: 0,
					y: 0
				};
				obj.targetEnemy = null;
				obj.hitEnemy = false;
				obj.damage = 100;
				break;
			case 'effect':
				// Remove any active tweens
				if (obj._tweens) {
					for (var i = 0; i < obj._tweens.length; i++) {
						obj._tweens[i].stop();
					}
					obj._tweens = [];
				}
				break;
			case 'damageText':
				obj.setText('');
				obj.anchor.set(0.5, 0.5);
				break;
			case 'coin':
				obj.bobOffset = Math.random() * Math.PI * 2;
				obj.initialY = 0;
				obj.isAnimating = false;
				break;
		}
	};
	// Clean up all pools
	self.cleanup = function () {
		for (var type in self.activePools) {
			var pool = self.activePools[type];
			// Destroy all available objects
			for (var i = 0; i < pool.available.length; i++) {
				if (pool.available[i].parent) {
					pool.available[i].destroy();
				}
			}
			// Return all in-use objects
			for (var i = pool.inUse.length - 1; i >= 0; i--) {
				self.returnObject(pool.inUse[i]);
			}
			pool.available = [];
			pool.inUse = [];
		}
	};
	// Get pool statistics for debugging
	self.getPoolStats = function () {
		var stats = {};
		for (var type in self.activePools) {
			var pool = self.activePools[type];
			stats[type] = {
				available: pool.available.length,
				inUse: pool.inUse.length,
				total: pool.available.length + pool.inUse.length,
				maxSize: pool.config.maxSize
			};
		}
		return stats;
	};
	// Initialize pools on creation
	self.initializePools();
	return self;
});
// All enemy types now use the unified Enemy class with type parameter
var Orb = Container.expand(function () {
	var self = Container.call(this);
	// Create orb visual using energy sphere
	var orbGraphics = self.attachAsset('energySphere', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.4,
		scaleY: 0.4
	});
	orbGraphics.tint = 0xFFD700; // Golden color for orbs
	orbGraphics.alpha = 0.9;
	self.orbitalAngle = 0; // Starting angle for this orb
	self.orbitalRadius = 880; // Distance from wizard - doubled again for even more separation
	self.rotationSpeed = 0.025; // How fast orbs rotate - halved for slower movement
	self.update = function () {
		// Pause orb when tutorial is active
		if (tutorial && tutorial.isActive) {
			return;
		}
		// Upgrade menu removed - no pause needed
		// Rotate around wizard
		if (wizard) {
			self.orbitalAngle += self.rotationSpeed;
			self.x = wizard.x + Math.cos(self.orbitalAngle) * self.orbitalRadius;
			self.y = wizard.y + Math.sin(self.orbitalAngle) * self.orbitalRadius - 240; // Position orb much higher up
		}
		// Add pulsing effect
		var pulse = 1 + Math.sin(LK.ticks * 0.3) * 0.2;
		orbGraphics.scaleX = 0.4 * pulse;
		orbGraphics.scaleY = 0.4 * pulse;
		// Category 3: Orb-enemy collisions (separate from projectile-enemy and enemy-wizard)
		self.processOrbEnemyCollisions();
	};
	return self;
});
// Create global death handler instance
var Projectile = Container.expand(function (type) {
	var self = Container.call(this);
	self.type = type || 'projectile';
	self.speed = 50;
	self.direction = {
		x: 0,
		y: 0
	};
	self.targetEnemy = null;
	self.damage = 100;
	self.hitEnemy = false;
	// Define local projectile configurations since GAME_CONFIG is not available yet
	var projectileConfigs = {
		projectile: {
			assetId: 'projectile',
			scale: 1.5,
			speed: 50,
			damage: 100,
			tint: 0x44aaff,
			glowTint: 0x44aaff,
			hasRotation: true
		},
		energyBeam: {
			assetId: 'projectileGlow',
			scale: 1.0,
			speed: 60,
			damage: 100,
			tint: 0x00ffff,
			glowTint: 0x00ffff,
			hasRotation: true
		},
		fireBall: {
			assetId: 'projectileGlow',
			scale: 1.5,
			speed: 40,
			damage: 150,
			tint: 0xFF4500,
			glowTint: 0xFF6600,
			hasRotation: true,
			hasFlicker: true
		}
	};
	// Get configuration from local configs
	var config = projectileConfigs[self.type];
	if (!config) {
		// Fallback to projectile config
		config = projectileConfigs.projectile;
	}
	self.speed = config.speed;
	self.damage = config.damage;
	// Create graphics based on type
	var assetId = config.assetId;
	self.graphics = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: config.scale,
		scaleY: config.scale
	});
	self.graphics.tint = config.tint;
	// Add glow for basic projectiles
	if (self.type === 'projectile') {
		var glow = self.attachAsset('projectileGlow', {
			anchorX: 0.5,
			anchorY: 0.5,
			scaleX: 2.0,
			scaleY: 2.0
		});
		glow.alpha = 0.3;
		glow.tint = config.glowTint;
	}
	self.update = function () {
		if (tutorial && tutorial.isActive) return;
		// Move projectile
		self.x += self.direction.x * self.speed;
		self.y += self.direction.y * self.speed;
		// Visual effects
		if (config.hasRotation) {
			var angle = Math.atan2(self.direction.y, self.direction.x);
			self.graphics.rotation = angle + Math.PI / 2;
		}
		if (config.hasFlicker) {
			var flicker = 1 + Math.sin(LK.ticks * 0.4) * 0.3;
			self.graphics.scaleX = config.scale * flicker;
			self.graphics.scaleY = config.scale * flicker;
		}
		// Remove if off screen
		if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
			// Remove from projectiles array before destroying
			ProjectileFactory.removeProjectile(self);
			return;
		}
		// Handle collisions
		self.checkCollisions();
	};
	self.checkCollisions = function () {
		if (self.hitEnemy) return;
		// Category 1: Area damage projectiles (fireball)
		if (self.type === 'fireBall') {
			self.processAreaDamageCollisions();
		} else {
			// Category 2: Single target projectiles
			self.processSingleTargetCollisions();
		}
	};
	// Separate collision processing for area damage projectiles
	self.processAreaDamageCollisions = function () {
		var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
		for (var i = 0; i < allEnemies.length; i++) {
			var enemy = allEnemies[i];
			if (enemy === wizard || enemy.isDying) continue;
			// Distance-based culling for fireball area damage
			var dx = enemy.x - self.x;
			var dy = enemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			var maxFireballRange = 120; // Fireball collision range including area effect
			if (distance <= maxFireballRange && self.intersects(enemy)) {
				enemy.takeDamage(self.damage);
				self.createExplosion(enemy);
				self.hitEnemy = true;
				// Remove from projectiles array before destroying
				ProjectileFactory.removeProjectile(self);
				return;
			}
		}
	};
	// Separate collision processing for single target projectiles  
	self.processSingleTargetCollisions = function () {
		if (self.targetEnemy && self.targetEnemy.parent && !self.targetEnemy.isDying) {
			// Distance-based culling for targeted projectiles
			var dx = self.targetEnemy.x - self.x;
			var dy = self.targetEnemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			var maxProjectileRange = 100; // Standard projectile collision range
			if (distance <= maxProjectileRange && self.intersects(self.targetEnemy)) {
				self.targetEnemy.takeDamage(self.damage);
				self.hitEnemy = true;
				// Remove from projectiles array before destroying
				ProjectileFactory.removeProjectile(self);
				return;
			}
		} else {
			// Target is invalid, remove projectile
			self.hitEnemy = true;
			// Remove from projectiles array before destroying
			ProjectileFactory.removeProjectile(self);
			return;
		}
	};
	self.createExplosion = function (enemy) {
		LK.effects.flashObject(enemy, 0xFF4500, 400);
		var explosion = game.addChild(LK.getAsset('projectileGlow', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: enemy.x,
			y: enemy.y,
			scaleX: 2,
			scaleY: 2
		}));
		explosion.tint = 0xFF6600;
		explosion.alpha = 0.8;
		tween(explosion, {
			scaleX: 5,
			scaleY: 5,
			alpha: 0
		}, {
			duration: 500,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				explosion.destroy();
			}
		});
	};
	return self;
});
var SpellDeck = Container.expand(function () {
	var self = Container.call(this);
	// Available spells in the game with enhanced mechanics
	self.availableSpells = [{
		id: 'fireball',
		name: 'FIREBALL',
		description: 'Launches a burning projectile',
		damage: 150,
		cooldown: 3000,
		manaCost: 30,
		unlocked: true,
		rarity: 'common',
		element: 'fire',
		chainTargets: 0,
		areaRadius: 0
	}, {
		id: 'iceShard',
		name: 'ICE SHARD',
		description: 'Freezes and damages enemies',
		damage: 100,
		cooldown: 2000,
		manaCost: 20,
		unlocked: true,
		rarity: 'common',
		element: 'ice',
		freezeDuration: 2000,
		slowAmount: 0.5
	}, {
		id: 'lightning',
		name: 'LIGHTNING',
		description: 'Chain lightning between enemies',
		damage: 200,
		cooldown: 4000,
		manaCost: 40,
		unlocked: false,
		rarity: 'rare',
		element: 'lightning',
		chainTargets: 3,
		chainRange: 200
	}, {
		id: 'heal',
		name: 'HEAL',
		description: 'Restores wizard health',
		healing: 50,
		cooldown: 5000,
		manaCost: 25,
		unlocked: true,
		rarity: 'common',
		element: 'light',
		healOverTime: 10,
		healDuration: 3000
	}, {
		id: 'shield',
		name: 'MAGIC SHIELD',
		description: 'Temporary damage immunity',
		duration: 3000,
		cooldown: 8000,
		manaCost: 50,
		unlocked: false,
		rarity: 'epic',
		element: 'arcane',
		shieldStrength: 3,
		reflectDamage: true
	}, {
		id: 'meteor',
		name: 'METEOR',
		description: 'Massive area damage',
		damage: 500,
		cooldown: 10000,
		manaCost: 80,
		unlocked: false,
		rarity: 'legendary',
		element: 'fire',
		areaRadius: 300,
		stunDuration: 1000
	}, {
		id: 'teleport',
		name: 'TELEPORT',
		description: 'Instantly move wizard',
		cooldown: 6000,
		manaCost: 35,
		unlocked: false,
		rarity: 'rare',
		element: 'arcane',
		teleportRange: 400,
		invulnDuration: 500
	}, {
		id: 'timeSlow',
		name: 'TIME SLOW',
		description: 'Slows all enemies',
		duration: 4000,
		cooldown: 12000,
		manaCost: 60,
		unlocked: false,
		rarity: 'epic',
		element: 'time',
		slowAmount: 0.3,
		damageBonus: 1.5
	}];
	// Current deck (max 5 spells)
	self.currentDeck = storage.spellDeck || ['fireball', 'iceShard', 'heal'];
	// Active spell cooldowns
	self.spellCooldowns = {};
	// Mana system
	self.maxMana = 100;
	self.currentMana = self.maxMana;
	self.manaRegenRate = 2; // Mana per second
	self.manaRegenTimer = 0;
	// Combo system
	self.lastSpellCast = 0;
	self.comboMultiplier = 1.0;
	self.comboTimer = 0;
	// Spell evolution system
	self.spellEvolutions = {};
	// Enhanced spell mechanics
	self.canCastSpell = function (spellId) {
		var spell = self.getSpell(spellId);
		if (!spell) return false;
		// Check mana
		if (self.currentMana < spell.manaCost) return false;
		// Check cooldown
		if (self.spellCooldowns[spellId] && self.spellCooldowns[spellId] > LK.ticks) return false;
		return true;
	};
	// Cast spell with enhanced mechanics
	self.castSpell = function (spellId, targetX, targetY) {
		if (!self.canCastSpell(spellId)) return false;
		var spell = self.getSpell(spellId);
		if (!spell) return false;
		// Consume mana
		self.currentMana -= spell.manaCost;
		// Set cooldown
		self.spellCooldowns[spellId] = LK.ticks + spell.cooldown / 1000 * 60; // Convert to ticks
		// Update combo system
		self.updateCombo();
		// Apply spell effects
		self.applySpellEffect(spell, targetX, targetY);
		// Update spell evolution
		self.updateSpellEvolution(spellId);
		return true;
	};
	// Update combo system
	self.updateCombo = function () {
		var currentTime = LK.ticks;
		if (currentTime - self.lastSpellCast < 180) {
			// Within 3 seconds
			self.comboMultiplier = Math.min(self.comboMultiplier + 0.2, 3.0);
			self.comboTimer = 180; // Reset combo timer
		} else {
			self.comboMultiplier = 1.0;
		}
		self.lastSpellCast = currentTime;
	};
	// Apply spell effects using unified factory pattern
	self.applySpellEffect = function (spell, targetX, targetY) {
		var spellConfig = GAME_CONFIG.spells[spell.id];
		if (!spellConfig) {
			console.error('Unknown spell configuration:', spell.id);
			return;
		}
		self.executeSpellEffect(spell, spellConfig, targetX, targetY);
	};
	// Unified spell effect execution method
	self.executeSpellEffect = function (spell, config, targetX, targetY) {
		var damage = config.baseDamage ? config.baseDamage * self.comboMultiplier : 0;
		var healing = config.baseHealing ? config.baseHealing * self.comboMultiplier : 0;
		// Play sound effect
		if (config.soundEffect) {
			LK.getSound(config.soundEffect).play();
		}
		// Execute based on target type
		switch (config.targetType) {
			case 'enemy':
				self.executeEnemyTargetSpell(spell, config, targetX, targetY, damage);
				break;
			case 'chain':
				self.executeChainSpell(spell, config, targetX, targetY, damage);
				break;
			case 'self':
				self.executeSelfTargetSpell(spell, config, healing);
				break;
			case 'area':
				self.executeAreaSpell(spell, config, targetX, targetY, damage);
				break;
			case 'position':
				self.executePositionSpell(spell, config, targetX, targetY);
				break;
			case 'all':
				self.executeAllTargetSpell(spell, config);
				break;
		}
	};
	// Execute enemy-targeted spells (fireball, iceShard)
	self.executeEnemyTargetSpell = function (spell, config, targetX, targetY, damage) {
		var projectile = ProjectileFactory.createSpellProjectile(spell.id, wizard, targetX, targetY);
		projectiles.push(projectile);
		// Apply status effects
		if (config.statusEffect) {
			projectile.statusEffect = config.statusEffect;
		}
	};
	// Streamlined spell execution using unified effect templates
	self.executeChainSpell = function (spell, config, targetX, targetY, damage) {
		var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
		var hitEnemies = [];
		var currentTarget = self.findClosestEnemy(allEnemies, targetX, targetY);
		for (var chain = 0; chain < config.chainTargets && currentTarget; chain++) {
			currentTarget.takeDamage(damage);
			hitEnemies.push(currentTarget);
			globalEffectManager.createVisualEffect('lightning', currentTarget, {});
			currentTarget = self.findNextChainTarget(allEnemies, hitEnemies, currentTarget, config.chainRange);
		}
	};
	// Streamlined self-target spells using effect manager
	self.executeSelfTargetSpell = function (spell, config, healing) {
		if (spell.id === 'heal') {
			wizard.health = Math.min(wizard.health + healing, wizard.maxHealth);
			updateHealthBar();
			globalEffectManager.createVisualEffect('heal', wizard, {});
		} else if (spell.id === 'shield') {
			wizard.shieldActive = true;
			wizard.maxShieldHits = config.shieldStrength;
			wizard.currentShieldHits = 0;
			wizard.shieldReflect = spell.reflectDamage;
			globalEffectManager.createVisualEffect('shield', wizard, {});
		}
	};
	// Streamlined area spells with efficient meteor effect
	self.executeAreaSpell = function (spell, config, targetX, targetY, damage) {
		var meteor = game.addChild(LK.getAsset('spell', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: targetX,
			y: targetY - 500,
			scaleX: 3,
			scaleY: 3
		}));
		meteor.tint = 0xFF4500;
		tween(meteor, {
			y: targetY,
			scaleX: 5,
			scaleY: 5
		}, {
			duration: 1000,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				self.executeAreaDamage(targetX, targetY, config.areaRadius, damage, config.stunDuration);
				LK.effects.flashScreen(0xFF4500, 500);
				meteor.destroy();
			}
		});
	};
	// Streamlined teleport with effect manager
	self.executePositionSpell = function (spell, config, targetX, targetY) {
		wizard.x = targetX;
		wizard.y = targetY;
		globalEffectManager.createFlashEffect(wizard, 0x8000FF, 300);
		wizard.teleportInvuln = true;
		tween({}, {}, {
			duration: config.invulnDuration,
			onFinish: function onFinish() {
				wizard.teleportInvuln = false;
			}
		});
	};
	// Streamlined time slow using screen flash
	self.executeAllTargetSpell = function (spell, config) {
		var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
		for (var i = 0; i < allEnemies.length; i++) {
			var enemy = allEnemies[i];
			enemy.timeSlowed = true;
			enemy.timeSlowAmount = config.slowAmount;
			enemy.timeSlowTimer = config.duration / 1000 * 60;
		}
		LK.effects.flashScreen(0x8000FF, 300);
	};
	// Helper methods for spell execution
	self.findClosestEnemy = function (allEnemies, targetX, targetY) {
		var closestEnemy = null;
		var closestDistance = Infinity;
		for (var i = 0; i < allEnemies.length; i++) {
			var enemy = allEnemies[i];
			var dx = enemy.x - targetX;
			var dy = enemy.y - targetY;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance < closestDistance) {
				closestDistance = distance;
				closestEnemy = enemy;
			}
		}
		return closestEnemy;
	};
	self.findNextChainTarget = function (allEnemies, hitEnemies, currentTarget, chainRange) {
		var nextTarget = null;
		var nextDistance = Infinity;
		for (var i = 0; i < allEnemies.length; i++) {
			var enemy = allEnemies[i];
			if (hitEnemies.indexOf(enemy) === -1) {
				var dx = enemy.x - currentTarget.x;
				var dy = enemy.y - currentTarget.y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				if (distance < chainRange && distance < nextDistance) {
					nextDistance = distance;
					nextTarget = enemy;
				}
			}
		}
		return nextTarget;
	};
	// Lightning effects now handled by unified effect manager
	self.executeAreaDamage = function (centerX, centerY, radius, damage, stunDuration) {
		var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
		for (var i = 0; i < allEnemies.length; i++) {
			var enemy = allEnemies[i];
			var dx = enemy.x - centerX;
			var dy = enemy.y - centerY;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance <= radius) {
				enemy.takeDamage(damage);
				enemy.frozen = true;
				enemy.frozenTimer = stunDuration / 1000 * 60;
			}
		}
	};
	// Individual spell implementations - REMOVED (replaced by unified system)
	self.castFireball = function (spell, targetX, targetY) {
		// DEPRECATED: Use executeSpellEffect instead
		self.executeSpellEffect(spell, GAME_CONFIG.spells.fireball, targetX, targetY);
	};
	// All individual spell casting methods have been replaced by the unified executeSpellEffect system
	// This reduces code duplication and centralizes spell logic in GAME_CONFIG.spells
	// Update mana regeneration
	self.updateMana = function () {
		self.manaRegenTimer++;
		if (self.manaRegenTimer >= 60) {
			// Every second
			self.manaRegenTimer = 0;
			self.currentMana = Math.min(self.currentMana + self.manaRegenRate, self.maxMana);
		}
	};
	// Update combo timer
	self.updateCombo = function () {
		if (self.comboTimer > 0) {
			self.comboTimer--;
			if (self.comboTimer <= 0) {
				self.comboMultiplier = 1.0;
			}
		}
	};
	// Update spell evolution
	self.updateSpellEvolution = function (spellId) {
		if (!self.spellEvolutions[spellId]) {
			self.spellEvolutions[spellId] = 0;
		}
		self.spellEvolutions[spellId]++;
		// Check for evolution milestones
		if (self.spellEvolutions[spellId] % 10 === 0) {
			self.evolveSpell(spellId);
		}
	};
	// Evolve spell
	self.evolveSpell = function (spellId) {
		var spell = self.getSpell(spellId);
		if (!spell) return;
		// Enhance spell based on usage
		switch (spellId) {
			case 'fireball':
				spell.damage += 25;
				spell.areaRadius += 20;
				break;
			case 'iceShard':
				spell.damage += 15;
				spell.freezeDuration += 500;
				break;
			case 'lightning':
				spell.chainTargets += 1;
				spell.chainRange += 50;
				break;
			case 'heal':
				spell.healing += 10;
				break;
		}
	};
	// Get spell evolution level
	self.getEvolutionLevel = function (spellId) {
		return Math.floor((self.spellEvolutions[spellId] || 0) / 10);
	};
	// Unlock spell based on achievements
	self.unlockSpell = function (spellId) {
		for (var i = 0; i < self.availableSpells.length; i++) {
			if (self.availableSpells[i].id === spellId) {
				self.availableSpells[i].unlocked = true;
				storage.unlockedSpells = storage.unlockedSpells || [];
				if (storage.unlockedSpells.indexOf(spellId) === -1) {
					storage.unlockedSpells.push(spellId);
				}
				break;
			}
		}
	};
	// Load unlocked spells from storage
	self.loadUnlockedSpells = function () {
		var unlockedSpells = storage.unlockedSpells || [];
		for (var i = 0; i < unlockedSpells.length; i++) {
			var spellId = unlockedSpells[i];
			for (var j = 0; j < self.availableSpells.length; j++) {
				if (self.availableSpells[j].id === spellId) {
					self.availableSpells[j].unlocked = true;
					break;
				}
			}
		}
	};
	// Add spell to deck
	self.addToDeck = function (spellId) {
		if (self.currentDeck.length >= 5) return false;
		if (self.currentDeck.indexOf(spellId) !== -1) return false;
		var spell = self.getSpell(spellId);
		if (spell && spell.unlocked) {
			self.currentDeck.push(spellId);
			storage.spellDeck = self.currentDeck;
			return true;
		}
		return false;
	};
	// Remove spell from deck
	self.removeFromDeck = function (spellId) {
		var index = self.currentDeck.indexOf(spellId);
		if (index !== -1) {
			self.currentDeck.splice(index, 1);
			storage.spellDeck = self.currentDeck;
			return true;
		}
		return false;
	};
	// Get spell data by ID
	self.getSpell = function (spellId) {
		for (var i = 0; i < self.availableSpells.length; i++) {
			if (self.availableSpells[i].id === spellId) {
				return self.availableSpells[i];
			}
		}
		return null;
	};
	// Get rarity color
	self.getRarityColor = function (rarity) {
		switch (rarity) {
			case 'common':
				return 0xFFFFFF;
			case 'rare':
				return 0x0080FF;
			case 'epic':
				return 0x8000FF;
			case 'legendary':
				return 0xFF8000;
			default:
				return 0xFFFFFF;
		}
	};
	// Initialize unlocked spells
	self.loadUnlockedSpells();
	return self;
});
var Tutorial = Container.expand(function () {
	var self = Container.call(this);
	// Tutorial state variables
	self.currentStep = 0;
	self.isActive = false;
	self.skipped = false; // Track if tutorial was skipped
	self.tutorialSteps = [];
	self.highlightElements = [];
	self.tutorialTexts = [];
	self.arrows = [];
	// Tutorial overlay background
	var tutorialOverlay = self.attachAsset('startMenuBackground', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 2732 / 2,
		scaleX: 1.0,
		scaleY: 1.0
	});
	tutorialOverlay.alpha = 0.8;
	tutorialOverlay.tint = 0x000000;
	tutorialOverlay.visible = false; // Initially hidden
	tutorialOverlay.zIndex = 1999; // Ensure proper layering
	tutorialOverlay.interactive = true; // Always interactive to block clicks
	// Define tutorial steps
	self.initializeTutorialSteps = function () {
		self.tutorialSteps = [{
			id: 'welcome',
			title: 'BIENVENIDO A WIZARD DEFENDER!',
			description: 'Eres un poderoso mago que debe defender su castillo. Toca directamente sobre los enemigos para atacarlos con hechizos.',
			duration: 3000,
			showSkip: true,
			highlightElement: 'screen',
			waitForTap: true
		}, {
			id: 'enemies_approach',
			title: 'ENEMIGOS Y MEJORAS',
			description: 'Los esqueletos vienen por 5 caminos diferentes. Toca directamente sobre cada enemigo para atacarlo. Gana monedas y desbloquea mejoras cada 12 enemigos.',
			duration: 3000,
			spawnDemoEnemy: true,
			highlightElement: 'coinCounter'
		}, {
			id: 'tutorial_complete',
			title: 'TUTORIAL COMPLETADO!',
			description: 'Recuerda: toca directamente sobre los enemigos para atacarlos. Cuida tu salud y sobrevive el mayor tiempo posible. ¡Buena suerte!',
			duration: 3000,
			startGame: true,
			highlightElement: 'healthBar'
		}];
	};
	// Start the tutorial
	self.startTutorial = function () {
		// Always show tutorial when explicitly called
		self.isActive = true;
		self.currentStep = 0;
		// Initialize tutorial steps first
		self.initializeTutorialSteps();
		// Make tutorial visible and properly layered
		self.visible = true;
		self.zIndex = 2000;
		// Configure tutorial overlay properly
		tutorialOverlay.visible = true;
		tutorialOverlay.alpha = 0.8;
		tutorialOverlay.tint = 0x000000;
		tutorialOverlay.interactive = true; // Block clicks to game below
		tutorialOverlay.zIndex = 1999; // Ensure proper layering
		// Hide game menu while tutorial is active
		if (gameMenu) {
			gameMenu.visible = false;
		}
		// Hide all game elements during tutorial
		if (wizard) wizard.visible = false;
		if (backgroundMap) backgroundMap.visible = false;
		coinText.visible = false;
		killCountText.visible = false;
		tapText.visible = false;
		healthBarBg.visible = false;
		healthBar.visible = false;
		healthText.visible = false;
		for (var i = 0; i < paths.length; i++) {
			paths[i].visible = false;
		}
		// Start first step
		self.showStep(0);
		return true; // Tutorial started
	};
	// Show a specific tutorial step
	self.showStep = function (stepIndex) {
		if (stepIndex >= self.tutorialSteps.length) {
			self.completeTutorial();
			return;
		}
		// Clear previous step elements
		self.clearStepElements();
		var step = self.tutorialSteps[stepIndex];
		self.currentStep = stepIndex;
		// Ensure tutorial is visible and on top
		self.visible = true;
		tutorialOverlay.visible = true;
		self.zIndex = 2000;
		// Create step title with proper sizing
		var titleText = new Text2(step.title, {
			size: 80,
			fill: 0xFFD700,
			font: "monospace",
			wordWrap: true,
			wordWrapWidth: 1600
		});
		titleText.anchor.set(0.5, 0.5);
		titleText.x = 2048 / 2;
		titleText.y = 900;
		self.addChild(titleText);
		self.tutorialTexts.push(titleText);
		// Create step description with proper text wrapping
		var descText = new Text2(step.description, {
			size: 60,
			fill: 0xFFFFFF,
			font: "monospace",
			wordWrap: true,
			wordWrapWidth: 1800
		});
		descText.anchor.set(0.5, 0.5);
		descText.x = 2048 / 2;
		descText.y = 1300;
		self.addChild(descText);
		self.tutorialTexts.push(descText);
		// Handle special step behaviors
		if (step.spawnDemoEnemy) {
			self.spawnDemoEnemy();
		}
		if (step.highlightElement) {
			self.highlightElement(step.highlightElement);
		}
		// Show continue button or wait for specific action
		if (step.waitForTap) {
			var tapPrompt = new Text2('TOCA LA PANTALLA PARA CONTINUAR', {
				size: 50,
				fill: 0x00FF00,
				font: "monospace",
				wordWrap: true,
				wordWrapWidth: 1400
			});
			tapPrompt.anchor.set(0.5, 0.5);
			tapPrompt.x = 2048 / 2;
			tapPrompt.y = 1800;
			self.addChild(tapPrompt);
			self.tutorialTexts.push(tapPrompt);
			// Add pulsing effect to tap prompt
			tween(tapPrompt, {
				scaleX: 1.2,
				scaleY: 1.2
			}, {
				duration: 800,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					tween(tapPrompt, {
						scaleX: 1.0,
						scaleY: 1.0
					}, {
						duration: 800,
						easing: tween.easeInOut
					});
				}
			});
		} else {
			// Always show continue prompt - no auto-advance
			var continuePrompt = new Text2('TOCA LA PANTALLA PARA CONTINUAR', {
				size: 50,
				fill: 0x00FF00,
				font: "monospace",
				wordWrap: true,
				wordWrapWidth: 1400
			});
			continuePrompt.anchor.set(0.5, 0.5);
			continuePrompt.x = 2048 / 2;
			continuePrompt.y = 1800;
			self.addChild(continuePrompt);
			self.tutorialTexts.push(continuePrompt);
			// Add pulsing effect to continue prompt
			tween(continuePrompt, {
				scaleX: 1.2,
				scaleY: 1.2
			}, {
				duration: 800,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					tween(continuePrompt, {
						scaleX: 1.0,
						scaleY: 1.0
					}, {
						duration: 800,
						easing: tween.easeInOut
					});
				}
			});
		}
		// Show skip button on first step
		if (step.showSkip) {
			var skipBtn = self.attachAsset('coin', {
				anchorX: 0.5,
				anchorY: 0.5,
				x: 2048 - 200,
				y: 200,
				scaleX: 1.5,
				scaleY: 1.5
			});
			skipBtn.tint = 0xFF4444;
			self.highlightElements.push(skipBtn);
			var skipText = new Text2('OMITIR', {
				size: 50,
				fill: 0xFFFFFF,
				font: "monospace"
			});
			skipText.anchor.set(0.5, 0.5);
			skipText.x = 2048 - 200;
			skipText.y = 200;
			self.addChild(skipText);
			self.tutorialTexts.push(skipText);
		}
	};
	// Highlight specific game elements
	self.highlightElement = function (elementType) {
		switch (elementType) {
			case 'healthBar':
				if (healthBarBg && healthBar) {
					// Show health UI temporarily
					healthBarBg.visible = true;
					healthBar.visible = true;
					healthText.visible = true;
					// Create highlight glow around health bar
					var healthGlow = game.addChild(LK.getAsset('projectileGlow', {
						anchorX: 0.5,
						anchorY: 0.5,
						x: 270,
						y: 110,
						scaleX: 3,
						scaleY: 1.5
					}));
					healthGlow.tint = 0x00FF00;
					healthGlow.alpha = 0.6;
					self.highlightElements.push(healthGlow);
					// Animate glow
					tween(healthGlow, {
						alpha: 0.3
					}, {
						duration: 1000,
						easing: tween.easeInOut
					});
				}
				break;
			case 'coinCounter':
				if (coinText) {
					// Show coin UI temporarily
					coinText.visible = true;
					coinText.setText('Coins: 15'); // Show example coins
					// Create highlight glow around coin counter
					var coinGlow = game.addChild(LK.getAsset('projectileGlow', {
						anchorX: 0.5,
						anchorY: 0.5,
						x: 270,
						y: 150,
						scaleX: 3,
						scaleY: 1.5
					}));
					coinGlow.tint = 0xFFD700;
					coinGlow.alpha = 0.6;
					self.highlightElements.push(coinGlow);
					// Animate glow
					tween(coinGlow, {
						alpha: 0.3
					}, {
						duration: 1000,
						easing: tween.easeInOut
					});
				}
				break;
			case 'screen':
				// Create large highlight overlay
				var screenGlow = game.addChild(LK.getAsset('projectileGlow', {
					anchorX: 0.5,
					anchorY: 0.5,
					x: 2048 / 2,
					y: 2732 / 2,
					scaleX: 20,
					scaleY: 25
				}));
				screenGlow.tint = 0x00FFFF;
				screenGlow.alpha = 0.2;
				self.highlightElements.push(screenGlow);
				// Animate screen glow
				tween(screenGlow, {
					alpha: 0.1
				}, {
					duration: 1500,
					easing: tween.easeInOut
				});
				// Create arrow pointing to center
				self.createArrow(2048 / 2, 2732 / 2 - 400, 2048 / 2, 2732 / 2);
				break;
		}
	};
	// Create pointing arrow
	self.createArrow = function (fromX, fromY, toX, toY) {
		var arrow = game.addChild(LK.getAsset('spell', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: fromX,
			y: fromY,
			scaleX: 3,
			scaleY: 3
		}));
		arrow.tint = 0xFFD700;
		arrow.alpha = 0.8;
		// Calculate arrow direction
		var dx = toX - fromX;
		var dy = toY - fromY;
		var angle = Math.atan2(dy, dx);
		arrow.rotation = angle;
		// Animate arrow bouncing
		tween(arrow, {
			x: toX,
			y: toY
		}, {
			duration: 1000,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(arrow, {
					x: fromX,
					y: fromY
				}, {
					duration: 1000,
					easing: tween.easeInOut
				});
			}
		});
		self.arrows.push(arrow);
	};
	// Spawn a demo enemy for tutorial
	self.spawnDemoEnemy = function () {
		// Create a slow-moving demo enemy
		var demoEnemy = game.addChild(new Enemy());
		demoEnemy.x = 2048 / 2;
		demoEnemy.y = -100;
		demoEnemy.speed = 1; // Very slow for demo
		demoEnemy.health = 1;
		demoEnemy.maxHealth = 1;
		demoEnemy.pathIndex = 0; // Center path
		// Make demo enemy more visible
		for (var frameIdx = 0; frameIdx < demoEnemy.animationFrames.length; frameIdx++) {
			demoEnemy.animationFrames[frameIdx].tint = 0xFF6600; // Orange tint
		}
		enemies.push(demoEnemy);
		// Create highlight around demo enemy
		var enemyGlow = game.addChild(LK.getAsset('projectileGlow', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: demoEnemy.x,
			y: demoEnemy.y,
			scaleX: 4,
			scaleY: 4
		}));
		enemyGlow.tint = 0xFF0000;
		enemyGlow.alpha = 0.5;
		// Make glow follow enemy
		var _glowFollower = function glowFollower() {
			if (demoEnemy && demoEnemy.parent && enemyGlow && enemyGlow.parent) {
				enemyGlow.x = demoEnemy.x;
				enemyGlow.y = demoEnemy.y;
				// Continue following
				tween({}, {}, {
					duration: 60,
					onFinish: _glowFollower
				});
			} else if (enemyGlow && enemyGlow.parent) {
				enemyGlow.destroy();
			}
		};
		_glowFollower();
		self.highlightElements.push(enemyGlow);
	};
	// Clear all tutorial step elements
	self.clearStepElements = function () {
		// Clear tutorial texts
		for (var i = 0; i < self.tutorialTexts.length; i++) {
			if (self.tutorialTexts[i] && self.tutorialTexts[i].parent) {
				self.tutorialTexts[i].destroy();
			}
		}
		self.tutorialTexts = [];
		// Clear highlight elements
		for (var i = 0; i < self.highlightElements.length; i++) {
			if (self.highlightElements[i] && self.highlightElements[i].parent) {
				self.highlightElements[i].destroy();
			}
		}
		self.highlightElements = [];
		// Clear arrows
		for (var i = 0; i < self.arrows.length; i++) {
			if (self.arrows[i] && self.arrows[i].parent) {
				self.arrows[i].destroy();
			}
		}
		self.arrows = [];
	};
	// Advance to next tutorial step
	self.nextStep = function () {
		self.currentStep++;
		if (self.currentStep < self.tutorialSteps.length) {
			self.showStep(self.currentStep);
		} else {
			// Tutorial completed naturally (not skipped)
			self.skipped = false;
			self.completeTutorial();
		}
	};
	// Complete the tutorial
	self.completeTutorial = function () {
		// Mark tutorial as completed
		storage.tutorialCompleted = true;
		// Clear all tutorial elements
		self.clearStepElements();
		// Hide tutorial completely
		tutorialOverlay.visible = false;
		tutorialOverlay.interactive = false; // Remove interactivity
		self.visible = false;
		self.isActive = false;
		// Only auto-start game if tutorial was completed naturally (not skipped)
		if (!self.skipped) {
			// Start game immediately without showing menu
			if (gameMenu) {
				gameMenu.startGame();
			}
		} else {
			// If skipped, show the menu
			if (gameMenu) {
				gameMenu.visible = true;
			}
		}
		// Reset skipped flag for next time
		self.skipped = false;
	};
	// Handle tutorial interactions
	self.down = function (x, y, obj) {
		if (!self.isActive) return;
		var step = self.tutorialSteps[self.currentStep];
		// Handle skip button (top-right corner)
		if (step.showSkip && x >= 2048 - 300 && x <= 2048 - 100 && y >= 100 && y <= 300) {
			self.skipped = true; // Mark as skipped
			self.completeTutorial();
			return;
		}
		// For any tap anywhere on screen, advance to next step
		if (step.id === 'tap_to_attack') {
			// Simulate spell casting for demo
			if (wizard) {
				wizard.attack(0); // Attack center path
			}
			// Wait a moment then advance
			tween({}, {}, {
				duration: 1000,
				onFinish: function onFinish() {
					self.nextStep();
				}
			});
		} else {
			// For all other steps, advance immediately on any tap
			self.nextStep();
		}
	};
	return self;
});
// Impact effect function now handled by BaseDamageHandler
// Unified death handler for all enemy types using enemy configuration
var UnifiedDeathHandler = Container.expand(function () {
	var self = Container.call(this);
	// Execute enemy death with consolidated coin and reward logic
	self.executeEnemyDeath = function (enemy, enemyArray) {
		enemy.animationState = 'dying';
		enemy.currentFrame = 3;
		LK.getSound('painSound').play();
		enemy.isDying = true;
		// Use enemy's own type configuration for death properties
		var config = enemy.typeConfig;
		var deathRotation = config.deathRotation || Math.PI * 0.5;
		var numCoins = config.coinReward || 1;
		// Special cleanup for mini boss UI elements
		if (enemy.enemyType === 'miniBoss') {
			self.cleanupMiniBossUI(enemy);
		}
		// Execute unified death animation
		tween(enemy, {
			alpha: 0,
			scaleX: 0.3,
			scaleY: 0.3,
			rotation: deathRotation
		}, {
			duration: 800,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				self.handleDeathRewards(enemy, numCoins);
				self.updateProgression(enemy);
				self.cleanupEnemy(enemy, enemyArray);
			}
		});
	};
	// Clean up mini boss UI elements
	self.cleanupMiniBossUI = function (enemy) {
		if (enemy.healthBarBg && enemy.healthBarBg.parent) {
			enemy.healthBarBg.destroy();
		}
		if (enemy.healthBarFg && enemy.healthBarFg.parent) {
			enemy.healthBarFg.destroy();
		}
		if (enemy.healthText && enemy.healthText.parent) {
			enemy.healthText.destroy();
		}
	};
	// Handle coin drops and difficulty-based rewards using pooled coins
	self.handleDeathRewards = function (enemy, numCoins) {
		var selectedDifficulty = storage.difficulty || 'NORMAL';
		for (var coinIdx = 0; coinIdx < numCoins; coinIdx++) {
			// Get coin from pool
			var coin = globalObjectPool.getObject('coin', {
				x: enemy.x + (enemy.enemyType === 'miniBoss' ? (Math.random() - 0.5) * 200 : 0),
				y: enemy.y - 50 + (enemy.enemyType === 'miniBoss' ? (Math.random() - 0.5) * 100 : 0),
				isAnimating: true
			});
			if (!coin) {
				// Fallback to direct creation if pool fails
				coin = game.addChild(new Coin());
				coin.x = enemy.x + (enemy.enemyType === 'miniBoss' ? (Math.random() - 0.5) * 200 : 0);
				coin.y = enemy.y - 50 + (enemy.enemyType === 'miniBoss' ? (Math.random() - 0.5) * 100 : 0);
				coin.isAnimating = true;
			} else {
				game.addChild(coin);
			}
			coins.push(coin);
			var coinTargetX = 120 + coinText.width / 2;
			var coinTargetY = 90 + coinText.height / 2;
			tween(coin, {
				x: coinTargetX,
				y: coinTargetY,
				scaleX: 0.5,
				scaleY: 0.5
			}, {
				duration: 1000 + (enemy.enemyType === 'miniBoss' ? coinIdx * 200 : 0),
				easing: tween.easeOut,
				onFinish: function onFinish() {
					self.processCoinReward(enemy, selectedDifficulty, coin);
				}
			});
		}
	};
	// Process coin rewards with difficulty modifiers
	self.processCoinReward = function (enemy, selectedDifficulty, coin) {
		var coinReward = enemy.enemyType === 'miniBoss' ? 10 : 1;
		if (selectedDifficulty === 'FACIL') {
			coinReward = Math.floor(coinReward * 1.5);
		} else if (selectedDifficulty === 'DIFICIL') {
			coinReward = Math.max(1, Math.floor(coinReward * 0.75));
		}
		coinCounter += coinReward;
		coinText.setText('Coins: ' + coinCounter);
		// Easy difficulty healing bonus
		if (selectedDifficulty === 'FACIL' && Math.random() < 0.15) {
			wizard.health = Math.min(wizard.health + 5, wizard.maxHealth);
			updateHealthBar();
			LK.effects.flashObject(wizard, 0x00FF00, 200);
		}
		// Remove coin from tracking array
		for (var i = coins.length - 1; i >= 0; i--) {
			if (coins[i] === coin) {
				coins.splice(i, 1);
				break;
			}
		}
		// Return coin to pool instead of destroying
		if (coin.pooled) {
			globalObjectPool.returnObject(coin);
		} else {
			coin.destroy();
		}
	};
	// Update kill counter and experience progression
	self.updateProgression = function (enemy) {
		var killIncrement = enemy.enemyType === 'miniBoss' ? 10 : 1;
		enemyKillCounter += killIncrement;
		killCountText.setText('Puntuacion: ' + enemyKillCounter);
		wizard.gainExperience(enemy.enemyType === 'miniBoss' ? 250 : 25);
		if (selectedEnemy === enemy) {
			selectedEnemy = null;
		}
	};
	// Clean up enemy from arrays and game
	self.cleanupEnemy = function (enemy, enemyArray) {
		// Remove from appropriate array
		for (var i = enemyArray.length - 1; i >= 0; i--) {
			if (enemyArray[i] === enemy) {
				enemyArray.splice(i, 1);
				break;
			}
		}
		// Also remove from global enemy manager collections
		globalEnemyManager.removeFromCollection(enemy, enemy.enemyType);
		// Remove from all legacy arrays to ensure proper cleanup
		var allArrays = [enemies, ogres, knights, miniBosses];
		for (var arrayIdx = 0; arrayIdx < allArrays.length; arrayIdx++) {
			var array = allArrays[arrayIdx];
			for (var i = array.length - 1; i >= 0; i--) {
				if (array[i] === enemy) {
					array.splice(i, 1);
					break;
				}
			}
		}
		enemy.destroy();
		LK.setScore(LK.getScore() + enemy.typeConfig.scoreReward);
	};
	return self;
});
// UpgradeMenu class removed - using spell deck system instead
// Unified Projectile Factory using consolidated GAME_CONFIG.projectiles
var Wizard = Container.expand(function () {
	var self = Container.call(this);
	// Animation system for wizard
	self.currentFrame = 1;
	self.animationTimer = 0;
	self.animationSpeed = 18; // Change frame every 18 ticks (300ms at 60fps)
	// Create all wizard graphics frames and store them
	self.wizardFrames = [];
	for (var i = 1; i <= 4; i++) {
		var frameGraphics = self.attachAsset('wizard' + i, {
			anchorX: 0.5,
			anchorY: 1.0,
			scaleX: 2.5,
			scaleY: 2.5
		});
		frameGraphics.visible = i === 1; // Only show first frame initially
		self.wizardFrames.push(frameGraphics);
	}
	// Create invisible hitbox with much smaller size for more precise collision
	var hitbox = self.attachAsset('wizard1', {
		anchorX: 0.3,
		anchorY: 1.0,
		scaleX: 0.25,
		// Much smaller size for very precise collision
		scaleY: 0.3 // Much smaller size for very precise collision
	});
	hitbox.alpha = 0; // Make hitbox invisible
	// Position hitbox slightly to the right to reduce left side
	hitbox.x = 15; // Offset hitbox to the right
	// Create shield visual effect
	self.shieldGraphics = self.attachAsset('shield', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 3,
		scaleY: 3
	});
	self.shieldGraphics.alpha = 0.7;
	self.shieldGraphics.visible = false;
	self.attackCooldown = 0;
	self.level = 1;
	self.experience = 0;
	self.health = 100;
	self.maxHealth = 100;
	self.shieldActive = false; // Track shield status
	// Upgrade system removed - simplified wizard properties
	// Override intersects method to use smaller hitbox
	self.intersects = function (other) {
		return hitbox.intersects(other);
	};
	self.update = function () {
		// Pause wizard when tutorial is active
		if (tutorial && tutorial.isActive) {
			return;
		}
		// Upgrade menu removed - no pause needed
		if (self.attackCooldown > 0) {
			self.attackCooldown--;
		}
		// Update shield visibility based on shield status
		self.shieldGraphics.visible = self.shieldActive;
		if (self.shieldActive) {
			// Animate shield with pulsing effect
			var pulse = 1 + Math.sin(LK.ticks * 0.15) * 0.2;
			self.shieldGraphics.scaleX = 3 * pulse;
			self.shieldGraphics.scaleY = 3 * pulse;
			// Slowly rotate shield
			self.shieldGraphics.rotation += 0.03;
			// Add glowing effect
			self.shieldGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.1) * 0.2;
		}
		// Upgrade-based abilities removed - using spell deck system instead
		// Optimized animation system with performance awareness
		self.animationTimer++;
		var adjustedSpeed = self.animationSpeed;
		// Apply performance-based animation adjustments
		if (globalAnimationManager && globalAnimationManager.skipConfig.skipLevel > 0) {
			var skipMultiplier = 1 + globalAnimationManager.skipConfig.skipLevel * 0.3;
			adjustedSpeed = Math.floor(adjustedSpeed * skipMultiplier);
		}
		if (self.animationTimer >= adjustedSpeed) {
			self.animationTimer = 0;
			// Calculate advanced frame transition configuration
			var transitionConfig = self.calculateFrameTransitionConfig(adjustedSpeed);
			var currentFrame = self.wizardFrames[self.currentFrame - 1];
			var nextFrameIndex = self.currentFrame >= 4 ? 0 : self.currentFrame;
			var nextFrame = self.wizardFrames[nextFrameIndex];
			// Advanced frame transition system with multiple tween effects
			if (transitionConfig.useAdvancedTransition) {
				self.performAdvancedFrameTransition(currentFrame, nextFrame, transitionConfig);
			} else if (transitionConfig.useBasicTransition) {
				self.performBasicFrameTransition(currentFrame, nextFrame, transitionConfig);
			} else {
				// Instant transition for low performance
				currentFrame.visible = false;
				nextFrame.visible = true;
			}
			// Move to next frame (walking state)
			self.currentFrame++;
			if (self.currentFrame > 4) {
				self.currentFrame = 1;
			}
		}
	};
	self.attack = function (direction) {
		if (self.attackCooldown <= 0) {
			// Default direction if none specified
			if (direction === undefined) {
				direction = 0; // Default to center path
			}
			// Get attack angle based on path direction
			var attackAngle = pathAngles[direction];
			var attackDistance = 100;
			// Calculate spell position based on attack direction
			var spellX = self.x + Math.cos(attackAngle) * attackDistance;
			var spellY = self.y + Math.sin(attackAngle) * attackDistance;
			// Create spell effect
			var spell = game.addChild(LK.getAsset('spell', {
				anchorX: 0.5,
				anchorY: 0.5,
				x: spellX,
				y: spellY,
				scaleX: 0.5,
				scaleY: 0.5
			}));
			// Animate spell with magical effects
			tween(spell, {
				scaleX: 2,
				scaleY: 2,
				alpha: 0
			}, {
				duration: 500,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					spell.destroy();
				}
			});
			// Add rotation animation to spell
			tween(spell, {
				rotation: Math.PI * 2
			}, {
				duration: 500,
				easing: tween.linear
			});
			self.attackCooldown = 30; // 0.5 seconds at 60fps
			LK.getSound('spellCast').play();
			// Base damage for wizard attack
			var totalDamage = 1;
			// Attack enemies in the specified direction/path
			for (var i = enemies.length - 1; i >= 0; i--) {
				var enemy = enemies[i];
				if (enemy.pathIndex === direction) {
					// Only hit enemies on exact same path - no distance validation
					enemy.takeDamage(totalDamage);
				}
			}
			// Attack ogres in the specified direction/path
			for (var i = ogres.length - 1; i >= 0; i--) {
				var ogre = ogres[i];
				if (ogre.pathIndex === direction) {
					// Only hit ogres on exact same path - no distance validation
					ogre.takeDamage(totalDamage);
				}
			}
			// Attack knights in the specified direction/path
			for (var i = knights.length - 1; i >= 0; i--) {
				var knight = knights[i];
				if (knight.pathIndex === direction) {
					// Only hit knights on exact same path - no distance validation
					knight.takeDamage(totalDamage);
				}
			}
			return true;
		}
		return false;
	};
	self.gainExperience = function (amount) {
		self.experience += amount;
		var expNeeded = self.level * 100;
		if (self.experience >= expNeeded) {
			self.levelUp();
		}
	};
	self.levelUp = function () {
		self.level++;
		self.experience = 0;
		// Visual level up effect
		LK.effects.flashObject(self, 0xFFD700, 500);
	};
	self.takeDamage = function (damage) {
		// Check if teleport invulnerability is active
		if (self.teleportInvuln) {
			globalDamageHandler.createFlashEffect(self, 0x8000FF, 200);
			return;
		}
		// Check if shield is active
		if (self.shieldActive) {
			// Initialize shield properties if not set
			if (self.maxShieldHits === undefined) {
				self.maxShieldHits = 1;
				self.currentShieldHits = 0;
			}
			// Increment shield hits
			self.currentShieldHits++;
			// Visual feedback for shield use
			globalDamageHandler.createFlashEffect(self, 0x00BFFF, 300);
			// Check if shield is depleted
			if (self.currentShieldHits >= self.maxShieldHits) {
				self.shieldActive = false;
				// Start shield regeneration timer
				var regenTime = self.shieldRegen ? 5000 : 10000; // Faster regen if improved
				tween({}, {}, {
					duration: regenTime,
					onFinish: function onFinish() {
						// Regenerate shield
						self.shieldActive = true;
						self.currentShieldHits = 0;
						// Visual feedback for shield regeneration
						globalDamageHandler.createFlashEffect(self, 0x00BFFF, 500);
						// Add shield regeneration animation
						tween(self.shieldGraphics, {
							scaleX: 5,
							scaleY: 5,
							alpha: 1.0
						}, {
							duration: 600,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								tween(self.shieldGraphics, {
									scaleX: 3,
									scaleY: 3,
									alpha: 0.7
								}, {
									duration: 400,
									easing: tween.easeIn
								});
							}
						});
					}
				});
			}
			// No damage taken, shield absorbed it
			return;
		}
		// Use unified damage handler for core damage logic
		self.health -= damage;
		globalDamageHandler.createFlashEffect(self, 0xFF0000, 200);
		if (self.health <= 0) {
			self.health = 0;
			// 10% chance to revive when dying
			var reviveChance = Math.random();
			if (reviveChance < 0.10) {
				// Revival successful!
				self.health = Math.floor(self.maxHealth * 0.5); // Revive with 50% health
				// Destroy ALL enemies when revival activates (no distance restriction)
				var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
				for (var enemyIdx = allEnemies.length - 1; enemyIdx >= 0; enemyIdx--) {
					var enemy = allEnemies[enemyIdx];
					// Create destruction effect for each enemy
					globalDamageHandler.createFlashEffect(enemy, 0xFFD700, 500);
					// Create golden explosion particles
					globalDamageHandler.createVisualEffect('explosion', enemy, {
						explosionColor: 0xFFD700,
						explosionScale: 4.0
					});
					// Kill ALL enemies instantly by calling die() method
					enemy.die();
				}
				// Visual effects for revival
				LK.effects.flashScreen(0x00FF00, 1500); // Green flash for revival
				globalDamageHandler.createFlashEffect(self, 0xFFD700, 1000); // Golden flash on wizard
				// Create healing aura effect
				globalDamageHandler.createVisualEffect('explosion', self, {
					explosionColor: 0x00FF00,
					explosionScale: 8.0
				});
				// Play spell cast sound for revival
				LK.getSound('spellCast').play();
				// Update health bar to show revival
				updateHealthBar();
			} else {
				// Game over when health reaches 0 and no revival
				LK.effects.flashScreen(0xFF0000, 1000);
				LK.showGameOver();
			}
		}
		// Update health bar
		updateHealthBar();
		// Simplified screen shake for better performance
		var shakeIntensity = 8;
		var originalX = game.x;
		var originalY = game.y;
		// Simple single shake effect
		tween(game, {
			x: originalX + shakeIntensity,
			y: originalY + shakeIntensity * 0.5
		}, {
			duration: 100,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(game, {
					x: originalX,
					y: originalY
				}, {
					duration: 100,
					easing: tween.easeIn
				});
			}
		});
	};
	self.activateForcePush = function () {
		// Visual effect for force push activation
		LK.effects.flashScreen(0x8A2BE2, 300); // Purple flash
		LK.effects.flashObject(self, 0x8A2BE2, 500); // Purple flash on wizard
		// Push back all enemies with improved effects
		var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
		for (var i = 0; i < allEnemies.length; i++) {
			var enemy = allEnemies[i];
			// Calculate direction from wizard to enemy
			var dx = enemy.x - self.x;
			var dy = enemy.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance > 0) {
				// Improved force push: stronger push and damage
				var pushDistance = upgradeLevels.forcePush > 1 ? 300 : 200; // Stronger push
				var pushX = dx / distance * pushDistance;
				var pushY = dy / distance * pushDistance;
				// Calculate new position
				var newX = enemy.x + pushX;
				var newY = enemy.y + pushY;
				// Ensure enemies don't go off screen
				newX = Math.max(50, Math.min(1998, newX));
				newY = Math.max(-100, Math.min(2732, newY));
				// Animate the push effect
				tween(enemy, {
					x: newX,
					y: newY
				}, {
					duration: 300,
					easing: tween.easeOut
				});
				// Improved force push: deal damage
				if (upgradeLevels.forcePush > 1) {
					enemy.takeDamage(50);
				}
				// Visual effect on each enemy
				LK.effects.flashObject(enemy, 0x8A2BE2, 200);
			}
		}
	};
	self.activateFreezePulse = function () {
		// Visual effect for freeze pulse activation
		LK.effects.flashScreen(0x87CEEB, 500); // Light blue flash
		LK.effects.flashObject(self, 0x87CEEB, 700); // Light blue flash on wizard
		// Play freeze sound effect
		LK.getSound('iceFreeze').play();
		// Freeze all enemies with improved effects
		var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
		for (var i = 0; i < allEnemies.length; i++) {
			var enemy = allEnemies[i];
			// Improved freeze: longer duration and damage
			var freezeDuration = upgradeLevels.freezePulse > 1 ? 120 : 60; // 2s vs 1s
			enemy.frozen = true;
			enemy.frozenTimer = freezeDuration;
			// Improved freeze: deal damage
			if (upgradeLevels.freezePulse > 1) {
				enemy.takeDamage(30);
			}
			// Visual freeze effect - tint enemy light blue
			tween(enemy, {
				tint: 0x87CEEB
			}, {
				duration: 100,
				easing: tween.easeOut
			});
			// Reduced ice crystal particles for better performance
			if (i % 2 === 0) {
				// Only create effects for every other enemy
				for (var iceIdx = 0; iceIdx < 3; iceIdx++) {
					var iceCrystal = game.addChild(LK.getAsset('spell', {
						anchorX: 0.5,
						anchorY: 0.5,
						x: enemy.x + (Math.random() - 0.5) * 60,
						y: enemy.y + (Math.random() - 0.5) * 60,
						scaleX: 1.0,
						scaleY: 1.0
					}));
					iceCrystal.tint = 0x87CEEB;
					iceCrystal.alpha = 0.9;
					// Create floating ice effect
					tween(iceCrystal, {
						y: iceCrystal.y - 30,
						scaleX: 0.3,
						scaleY: 0.3,
						alpha: 0
					}, {
						duration: 600,
						easing: tween.easeOut,
						onFinish: function onFinish() {
							iceCrystal.destroy();
						}
					});
				}
			}
			// Remove freeze tint after frozen state ends
			var visualDuration = upgradeLevels.freezePulse > 1 ? 2000 : 1000;
			tween({}, {}, {
				duration: visualDuration,
				onFinish: function onFinish() {
					if (enemy && enemy.parent) {
						// Remove freeze tint after frozen effect ends
						tween(enemy, {
							tint: 0xFFFFFF
						}, {
							duration: 200,
							easing: tween.easeIn
						});
					}
				}
			});
		}
	};
	self.activateThorns = function () {
		// Visual effect for thorns activation
		LK.effects.flashScreen(0x8B4513, 300); // Brown flash
		LK.effects.flashObject(self, 0x8B4513, 500); // Brown flash on wizard
		// Find the closest enemy to the wizard
		var closestEnemy = null;
		var closestDistance = Infinity;
		var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
		for (var i = 0; i < allEnemies.length; i++) {
			var enemy = allEnemies[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;
			}
		}
		// Only create spikes if there is a closest enemy
		if (!closestEnemy) {
			LK.getSound('spellCast').play();
			return;
		}
		// Create spikes only along the closest enemy's path
		var pathIdx = closestEnemy.pathIndex;
		var pathAngle = pathAngles[pathIdx];
		// Calculate spawn position for this path (same as enemy spawning)
		var spawnX, spawnY;
		if (pathIdx === 0) {
			// Center path - spawn at top edge
			spawnX = 2048 / 2;
			spawnY = -100;
		} else if (pathIdx === 1) {
			// Path 2 - spawn at top right edge
			spawnX = 2048 + 50;
			spawnY = -50;
		} else if (pathIdx === 2) {
			// Path 3 - spawn at top left edge
			spawnX = -50;
			spawnY = -50;
		} else if (pathIdx === 3) {
			// Path 4 - spawn at left edge
			spawnX = -100;
			spawnY = 2732 / 2 + 400;
		} else if (pathIdx === 4) {
			// Path 5 - spawn at right edge
			spawnX = 2048 + 100;
			spawnY = 2732 / 2 + 400;
		}
		// Calculate wizard position (same as enemy targeting)
		var wizardX = self.x;
		var wizardY = self.y;
		// Calculate path distance and divide into 3 sections with gaps
		var pathDistance = Math.sqrt((spawnX - wizardX) * (spawnX - wizardX) + (spawnY - wizardY) * (spawnY - wizardY));
		var sectionLength = pathDistance / 5; // Each section is 1/5 of total path
		var gapLength = pathDistance / 10; // Gaps are 1/10 of total path
		// Define 3 sections along the path with gaps between them
		var sections = [{
			start: 0.1,
			end: 0.3
		},
		// First section: 10% to 30% along path
		{
			start: 0.45,
			end: 0.65
		},
		// Second section: 45% to 65% along path
		{
			start: 0.8,
			end: 1.0
		} // Third section: 80% to 100% along path
		];
		// Create spikes in reverse sequential order: last section, then middle, then first
		var sectionOrder = [2, 1, 0]; // Create sections starting from farthest outward toward wizard
		for (var orderIdx = 0; orderIdx < sectionOrder.length; orderIdx++) {
			var sectionIdx = sectionOrder[orderIdx];
			var section = sections[sectionIdx];
			var sectionStartDistance = pathDistance * section.start;
			var sectionEndDistance = pathDistance * section.end;
			var spikeSpacing = 150; // Distance between spikes within each section
			// Calculate number of spikes in this section
			var sectionLength = sectionEndDistance - sectionStartDistance;
			var numSpikesInSection = Math.floor(sectionLength / spikeSpacing);
			// Calculate delay for sequential appearance
			var baseDelay = orderIdx * 300; // 300ms delay between sections
			// Create spikes within this section with sequential timing
			for (var s = 0; s < numSpikesInSection; s++) {
				var spikeDistanceInSection = s * spikeSpacing + spikeSpacing / 2;
				var totalSpikeDistance = sectionStartDistance + spikeDistanceInSection;
				var progress = totalSpikeDistance / pathDistance;
				var spikeX = spawnX + (wizardX - spawnX) * progress;
				var spikeY = spawnY + (wizardY - spawnY) * progress;
				// Only create spike if position is within game bounds
				if (spikeX >= 0 && spikeX <= 2048 && spikeY >= 0 && spikeY <= 2732) {
					// Create spike with delay
					(function (delayTime, spikeX, spikeY, pathIdx) {
						tween({}, {}, {
							duration: delayTime,
							onFinish: function onFinish() {
								var spike = game.addChild(LK.getAsset('spell', {
									anchorX: 0.5,
									anchorY: 0.5,
									x: spikeX,
									y: spikeY,
									scaleX: 0.1,
									scaleY: 0.1
								}));
								spike.tint = 0x8B4513; // Brown color for thorns
								spike.pathIndex = pathIdx;
								// Initialize hit tracking for this spike
								spike.hitEnemies = [];
								// Set spike to be visible immediately
								spike.alpha = 1.0;
								spike.scaleX = 1.5;
								spike.scaleY = 1.5;
								// Animate spike emerging from ground
								tween(spike, {
									scaleX: 2.5,
									scaleY: 2.5,
									alpha: 1.0
								}, {
									duration: 200,
									easing: tween.easeOut,
									onFinish: function onFinish() {
										// Spike stays for a moment then disappears
										tween(spike, {
											scaleX: 0.1,
											scaleY: 0.1,
											alpha: 0
										}, {
											duration: 800,
											easing: tween.easeIn,
											onFinish: function onFinish() {
												spike.destroy();
											}
										});
									}
								});
							}
						});
					})(baseDelay + s * 50, spikeX, spikeY, pathIdx); // 50ms delay between spikes in same section
				}
			}
		}
		LK.getSound('spellCast').play();
	};
	self.launchFireBall = function () {
		// Visual effect for fire ball launch
		LK.effects.flashScreen(0xFF4500, 300); // Orange flash
		LK.effects.flashObject(self, 0xFF4500, 500); // Orange flash on wizard
		// Find closest enemy to target
		var closestEnemy = null;
		var closestDistance = Infinity;
		var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
		for (var i = 0; i < allEnemies.length; i++) {
			var enemy = allEnemies[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;
			}
		}
		// Create fire ball projectile using unified factory
		var targetX = closestEnemy ? closestEnemy.x : self.x;
		var targetY = closestEnemy ? closestEnemy.y : self.y - 100;
		var fireBall = ProjectileFactory.createProjectile('fireBall', self.x, self.y, targetX, targetY);
		LK.getSound('spellCast').play();
		LK.getSound('fireWhoosh').play();
	};
	// Calculate frame transition configuration based on performance metrics
	self.calculateFrameTransitionConfig = function (adjustedSpeed) {
		var skipLevel = globalAnimationManager ? globalAnimationManager.skipConfig.skipLevel : 0;
		var avgFrameTime = globalAnimationManager ? globalAnimationManager.performanceMetrics.avgFrameTime : 16.67;
		var config = {
			useAdvancedTransition: false,
			useBasicTransition: false,
			duration: adjustedSpeed * 0.3,
			easing: tween.easeOut
		};
		// Determine transition complexity based on performance
		if (skipLevel === 0 && avgFrameTime < 18) {
			// Excellent performance: advanced transitions with multiple effects
			config.useAdvancedTransition = true;
			config.duration = adjustedSpeed * 0.4;
			config.easing = tween.easeInOut;
		} else if (skipLevel <= 1 && avgFrameTime < 25) {
			// Good performance: basic smooth transitions
			config.useBasicTransition = true;
			config.duration = adjustedSpeed * 0.3;
			config.easing = tween.easeOut;
		}
		return config;
	};
	// Perform advanced frame transition with sophisticated tween effects
	self.performAdvancedFrameTransition = function (currentFrame, nextFrame, config) {
		// Phase 1: Current frame fade and scale out
		tween(currentFrame, {
			alpha: 0,
			scaleX: currentFrame.scaleX * 0.95,
			scaleY: currentFrame.scaleY * 0.95
		}, {
			duration: config.duration * 0.5,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				currentFrame.visible = false;
				currentFrame.alpha = 1;
				currentFrame.scaleX = 2.5; // Reset scale
				currentFrame.scaleY = 2.5;
			}
		});
		// Phase 2: Next frame scale and fade in
		nextFrame.visible = true;
		nextFrame.alpha = 0;
		nextFrame.scaleX = 2.5 * 1.05; // Start slightly larger
		nextFrame.scaleY = 2.5 * 1.05;
		tween(nextFrame, {
			alpha: 1,
			scaleX: 2.5,
			scaleY: 2.5
		}, {
			duration: config.duration * 0.7,
			easing: tween.bounceOut,
			delay: config.duration * 0.3 // Start after current frame begins fading
		});
		// Phase 3: Subtle magical sparkle effect for enhanced visual appeal
		self.createFrameTransitionSparkle(nextFrame, config);
	};
	// Perform basic frame transition with smooth fade effect
	self.performBasicFrameTransition = function (currentFrame, nextFrame, config) {
		// Smooth fade out current frame
		tween(currentFrame, {
			alpha: 0
		}, {
			duration: config.duration,
			easing: config.easing,
			onFinish: function onFinish() {
				currentFrame.visible = false;
				currentFrame.alpha = 1;
			}
		});
		// Smooth fade in next frame
		nextFrame.visible = true;
		nextFrame.alpha = 0;
		tween(nextFrame, {
			alpha: 1
		}, {
			duration: config.duration,
			easing: tween.easeIn
		});
	};
	// Create subtle sparkle effect for frame transitions
	self.createFrameTransitionSparkle = function (frame, config) {
		var sparkleCount = 3;
		for (var i = 0; i < sparkleCount; i++) {
			var sparkle = globalObjectPool ? globalObjectPool.getObject('effect', {
				x: frame.x + (Math.random() - 0.5) * 40,
				y: frame.y + (Math.random() - 0.5) * 40,
				scaleX: 0.1,
				scaleY: 0.1,
				anchorX: 0.5,
				anchorY: 0.5
			}) : null;
			if (!sparkle) {
				sparkle = game.addChild(LK.getAsset('spell', {
					anchorX: 0.5,
					anchorY: 0.5,
					x: frame.x + (Math.random() - 0.5) * 40,
					y: frame.y + (Math.random() - 0.5) * 40,
					scaleX: 0.1,
					scaleY: 0.1
				}));
			} else {
				game.addChild(sparkle);
			}
			sparkle.tint = 0xFFD700;
			sparkle.alpha = 0.8;
			// Animate sparkle with delayed start
			var delay = i * 100;
			tween({}, {}, {
				duration: delay,
				onFinish: function (sparkleRef) {
					return function () {
						tween(sparkleRef, {
							scaleX: 0.5,
							scaleY: 0.5,
							alpha: 1.0,
							rotation: Math.PI * 2
						}, {
							duration: 400,
							easing: tween.easeOut,
							onFinish: function onFinish() {
								tween(sparkleRef, {
									scaleX: 0.1,
									scaleY: 0.1,
									alpha: 0
								}, {
									duration: 200,
									easing: tween.easeIn,
									onFinish: function onFinish() {
										if (sparkleRef.pooled && globalObjectPool) {
											globalObjectPool.returnObject(sparkleRef);
										} else if (sparkleRef.parent) {
											sparkleRef.destroy();
										}
									}
								});
							}
						});
					};
				}(sparkle)
			});
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000 // Black background for pixel art
});
/**** 
* Game Code
****/ 
// Helper functions now integrated into EnemyFactory
function _typeof4(o) {
	"@babel/helpers - typeof";
	return _typeof4 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
		return typeof o;
	} : function (o) {
		return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
	}, _typeof4(o);
}
function _typeof3(o) {
	"@babel/helpers - typeof";
	return _typeof3 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
		return typeof o;
	} : function (o) {
		return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
	}, _typeof3(o);
}
function _typeof2(o) {
	"@babel/helpers - typeof";
	return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
		return typeof o;
	} : function (o) {
		return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
	}, _typeof2(o);
}
// Create global object pool instance for optimized memory management
var globalObjectPool = new ObjectPool();
// Create global animation manager for intelligent frame skipping
var globalAnimationManager = new AnimationManager();
var ProjectileFactory = {
	activeProjectiles: [],
	createProjectile: function createProjectile(type, startX, startY, targetX, targetY, overrides) {
		// Get projectile from pool instead of creating new one
		var projectile = globalObjectPool.getObject(type, {
			x: startX,
			y: startY
		});
		if (!projectile) {
			// Fallback to old method if pool fails
			projectile = game.addChild(new Projectile(type));
			projectile.x = startX;
			projectile.y = startY;
		} else {
			// Add pooled projectile to game
			game.addChild(projectile);
		}
		// Apply overrides
		if (overrides) {
			for (var key in overrides) {
				projectile[key] = overrides[key];
			}
		}
		// Calculate direction
		if (targetX !== undefined && targetY !== undefined) {
			var dx = targetX - startX;
			var dy = targetY - startY;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance > 0) {
				projectile.direction.x = dx / distance;
				projectile.direction.y = dy / distance;
			}
		}
		this.activeProjectiles.push(projectile);
		projectiles.push(projectile);
		return projectile;
	},
	createSpellProjectile: function createSpellProjectile(spellId, wizard, targetX, targetY) {
		var damage = 100;
		var type = 'projectile';
		switch (spellId) {
			case 'fireball':
				type = 'fireBall';
				damage = 150 * (activeSpellDeck.comboMultiplier || 1);
				break;
			case 'iceShard':
				damage = 100 * (activeSpellDeck.comboMultiplier || 1);
				break;
			case 'energyBeam':
				type = 'energyBeam';
				damage = 100;
				break;
		}
		return this.createProjectile(type, wizard.x, wizard.y, targetX, targetY, {
			damage: damage
		});
	},
	createBasicAttack: function createBasicAttack(wizard, enemy) {
		return this.createProjectile('projectile', wizard.x, wizard.y, enemy.x, enemy.y, {
			targetEnemy: enemy,
			damage: 100
		});
	},
	removeProjectile: function removeProjectile(projectile) {
		// Remove from tracking arrays first
		for (var i = this.activeProjectiles.length - 1; i >= 0; i--) {
			if (this.activeProjectiles[i] === projectile) {
				this.activeProjectiles.splice(i, 1);
				break;
			}
		}
		for (var i = projectiles.length - 1; i >= 0; i--) {
			if (projectiles[i] === projectile) {
				projectiles.splice(i, 1);
				break;
			}
		}
		// Return projectile to pool or destroy it
		if (projectile.pooled) {
			globalObjectPool.returnObject(projectile);
		} else if (projectile.parent) {
			projectile.destroy();
		}
	}
};
var globalEffectManager = new EffectManager();
var globalDamageHandler = globalEffectManager; // Backward compatibility alias
function _typeof(o) {
	"@babel/helpers - typeof";
	return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
		return typeof o;
	} : function (o) {
		return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
	}, _typeof(o);
}
// Unified GAME_CONFIG with centralized enemy configurations and factory systems
var GAME_CONFIG = {
	// Spell configurations for factory pattern
	spells: {
		fireball: {
			projectileType: 'fireBall',
			baseDamage: 150,
			soundEffect: 'fireWhoosh',
			visualEffect: 'fire',
			targetType: 'enemy'
		},
		iceShard: {
			projectileType: 'projectile',
			baseDamage: 100,
			soundEffect: 'iceFreeze',
			visualEffect: 'ice',
			targetType: 'enemy',
			statusEffect: {
				type: 'freeze',
				duration: 2000
			}
		},
		lightning: {
			baseDamage: 200,
			soundEffect: 'spellCast',
			visualEffect: 'lightning',
			targetType: 'chain',
			chainTargets: 3,
			chainRange: 200
		},
		heal: {
			baseHealing: 50,
			soundEffect: 'spellCast',
			visualEffect: 'heal',
			targetType: 'self'
		},
		shield: {
			duration: 3000,
			soundEffect: 'spellCast',
			visualEffect: 'shield',
			targetType: 'self',
			shieldStrength: 3
		},
		meteor: {
			baseDamage: 500,
			soundEffect: 'spellCast',
			visualEffect: 'meteor',
			targetType: 'area',
			areaRadius: 300,
			stunDuration: 1000
		},
		teleport: {
			soundEffect: 'spellCast',
			visualEffect: 'teleport',
			targetType: 'position',
			invulnDuration: 500
		},
		timeSlow: {
			duration: 4000,
			soundEffect: 'spellCast',
			visualEffect: 'timeSlow',
			targetType: 'all',
			slowAmount: 0.3
		}
	},
	// Streamlined enemy configurations with essential properties only
	enemies: {
		skeleton: {
			assetPrefix: 'esqueleto',
			scale: 3.0,
			baseHealth: 100,
			baseSpeed: 3,
			animationSpeed: 15,
			vibration: 50,
			damageTextColor: 0xFF4444,
			impactScale: 1.5,
			deathRotation: Math.PI * 0.5,
			scoreReward: 10,
			startThreshold: 0,
			coinReward: 1,
			damage: 20,
			spawnInterval: {
				FACIL: {
					base: 120,
					min: 60,
					scaling: 5
				},
				NORMAL: {
					base: 90,
					min: 40,
					scaling: 6
				},
				DIFICIL: {
					base: 90,
					min: 40,
					scaling: 6
				}
			},
			maxOnScreen: 15,
			eliteChance: 0.20,
			soundOnSpawn: 0.3
		},
		ogre: {
			assetPrefix: 'ogre',
			scale: 3.0,
			baseHealth: 200,
			baseSpeed: 2.5,
			animationSpeed: 20,
			vibration: 75,
			damageTextColor: 0xFF6600,
			impactScale: 2.0,
			deathRotation: Math.PI * 1.2,
			scoreReward: 15,
			startThreshold: 15,
			coinReward: 1,
			damage: 30,
			spawnInterval: {
				FACIL: 240,
				NORMAL: 180,
				DIFICIL: 120
			},
			maxOnScreen: 4,
			eliteChance: 0.15
		},
		knight: {
			assetPrefix: 'knight',
			scale: 3.0,
			baseHealth: 300,
			baseSpeed: 2,
			animationSpeed: 22,
			vibration: 100,
			damageTextColor: 0xFFD700,
			impactScale: 1.8,
			deathRotation: Math.PI * 0.8,
			scoreReward: 20,
			startThreshold: 20,
			coinReward: 1,
			damage: 40,
			spawnInterval: {
				FACIL: 420,
				NORMAL: 300,
				DIFICIL: 240
			},
			maxOnScreen: 3,
			eliteChance: 0.10
		},
		miniBoss: {
			assetPrefix: 'knight',
			scale: 5.0,
			baseHealth: 3000,
			baseSpeed: 4,
			animationSpeed: 12,
			vibration: [100, 50, 100],
			damageTextColor: 0xFF0000,
			impactScale: 2.5,
			deathRotation: Math.PI * 2,
			scoreReward: 100,
			tint: 0x8B0000,
			startThreshold: 80,
			endThreshold: 85,
			spawnChance: 0.02,
			coinReward: 5,
			damage: 75,
			maxOnScreen: 1
		}
	},
	// Unified enemy configuration factory
	createEnemyConfig: function createEnemyConfig(type, overrides) {
		var base = this.enemies[type];
		if (!base) {
			console.error('Enemy type not found:', type);
			return this.enemies.skeleton; // fallback to skeleton
		}
		var config = {};
		// Deep copy base configuration
		for (var key in base) {
			if (_typeof(base[key]) === 'object' && base[key] !== null && !Array.isArray(base[key])) {
				config[key] = {};
				for (var subKey in base[key]) {
					config[key][subKey] = base[key][subKey];
				}
			} else {
				config[key] = base[key];
			}
		}
		// Apply overrides
		if (overrides) {
			for (var key in overrides) {
				if (_typeof(overrides[key]) === 'object' && overrides[key] !== null && !Array.isArray(overrides[key])) {
					if (!config[key]) config[key] = {};
					for (var subKey in overrides[key]) {
						config[key][subKey] = overrides[key][subKey];
					}
				} else {
					config[key] = overrides[key];
				}
			}
		}
		return config;
	},
	// Path configurations
	paths: {
		count: 5,
		angles: [-Math.PI / 2, -Math.PI / 3, -2 * Math.PI / 3, Math.PI / 6, 5 * Math.PI / 6],
		spawnPositions: [{
			x: 2048 / 2,
			y: -100
		},
		// Center path
		{
			x: 2048 + 50,
			y: -50
		},
		// Top right
		{
			x: -50,
			y: -50
		},
		// Top left
		{
			x: -100,
			y: 2732 / 2 + 400
		},
		// Left edge
		{
			x: 2048 + 100,
			y: 2732 / 2 + 400
		} // Right edge
		]
	},
	// Gameplay configurations with difficulty scaling
	gameplay: {
		maxEnemiesOnScreen: 25,
		pathCooldown: 300,
		upgradeMenuTriggers: [12, 35, 50, 70],
		baseUpgradeCost: 5,
		upgradeCostIncrease: 5,
		attackCooldown: 30,
		projectileSpeed: 50,
		wizardAnimationSpeed: 18,
		segmentSize: 120,
		difficultyScaling: {
			FACIL: {
				healthMult: 0.8,
				speedMult: 0.9,
				bonusCoins: true,
				healingChance: 0.15
			},
			NORMAL: {
				healthMult: 1.0,
				speedMult: 1.0,
				standardRewards: true
			},
			DIFICIL: {
				healthMult: 1.2,
				speedMult: 1.1,
				eliteEnemies: true,
				reducedCoins: true
			}
		}
	},
	// Optimized projectile configurations
	projectiles: {
		projectile: {
			assetId: 'projectile',
			scale: 1.5,
			speed: 50,
			damage: 100,
			tint: 0x44aaff,
			glowTint: 0x44aaff,
			hasRotation: true
		},
		energyBeam: {
			assetId: 'projectileGlow',
			scale: 1.0,
			speed: 60,
			damage: 100,
			tint: 0x00ffff,
			glowTint: 0x00ffff,
			hasRotation: true
		},
		fireBall: {
			assetId: 'projectileGlow',
			scale: 1.5,
			speed: 40,
			damage: 150,
			tint: 0xFF4500,
			glowTint: 0xFF6600,
			hasRotation: true,
			hasFlicker: true
		}
	},
	// UI management
	ui: {
		healthBar: {
			x: 120,
			y: 20,
			scaleX: 1.0,
			scaleY: 1.0
		},
		healthBarBg: {
			x: 120,
			y: 20,
			scaleX: 1.0,
			scaleY: 1.0
		},
		coinText: {
			x: 120,
			y: 90,
			size: 60,
			fill: 0xFFD700,
			font: "monospace"
		},
		killText: {
			x: 120,
			y: 150,
			size: 60,
			fill: 0xFF6B6B,
			font: "monospace"
		},
		healthText: {
			x: 120,
			y: 50,
			size: 50,
			fill: 0xFFFFFF,
			font: "monospace"
		},
		tapText: {
			size: 100,
			yOffset: -200,
			fill: 0xFF6B6B,
			font: "monospace"
		},
		manaBar: {
			x: -300,
			y: 20,
			scaleX: 2,
			scaleY: 0.5
		},
		manaBarBg: {
			x: -300,
			y: 20,
			scaleX: 2,
			scaleY: 0.5
		},
		manaText: {
			x: -300,
			y: 50,
			size: 40,
			fill: 0x4169E1,
			font: "monospace"
		},
		spellSlots: {
			startX: -200,
			spacing: 100,
			y: -100,
			scaleX: 1.5,
			scaleY: 1.5,
			count: 5
		},
		miniBossHealthBar: {
			x: 2048 / 2,
			y: 200,
			bgScaleX: 1.0,
			bgScaleY: 1.0,
			fgScaleX: 1.0,
			fgScaleY: 1.0,
			textSize: 40,
			textY: 150
		}
	}
};
// Game state variables
var gameStarted = false;
var gameMenu;
// Upgrade menu variables removed
var selectedEnemy = null; // Track currently selected enemy for projectile targeting
var energySphere = null; // Track energy sphere instance
// Upgrade system removed - using spell deck system instead
// Upgrade system removed - using spell deck system instead
// Game arrays to track objects
var enemies = [];
var ogres = [];
var knights = [];
var miniBosses = [];
var coins = [];
var projectiles = [];
// Removed combo system variables
// Create tutorial system first (initially hidden)
var tutorial = game.addChild(new Tutorial());
tutorial.visible = false;
// Create and show game menu
gameMenu = game.addChild(new GameMenu());
// Create active spell deck system
var activeSpellDeck = new SpellDeck();
var spellSlots = [];
var manaBar, manaBarBg, manaText;
// Create spell UI
function createSpellUI() {
	// Mana bar
	manaBarBg = LK.getAsset('manaBarBg', {
		anchorX: 0,
		anchorY: 0,
		scaleX: GAME_CONFIG.ui.manaBarBg.scaleX,
		scaleY: GAME_CONFIG.ui.manaBarBg.scaleY
	});
	LK.gui.topRight.addChild(manaBarBg);
	manaBarBg.x = GAME_CONFIG.ui.manaBarBg.x;
	manaBarBg.y = GAME_CONFIG.ui.manaBarBg.y;
	manaBarBg.visible = false;
	manaBar = LK.getAsset('manaBar', {
		anchorX: 0,
		anchorY: 0,
		scaleX: GAME_CONFIG.ui.manaBar.scaleX,
		scaleY: GAME_CONFIG.ui.manaBar.scaleY
	});
	LK.gui.topRight.addChild(manaBar);
	manaBar.x = GAME_CONFIG.ui.manaBar.x;
	manaBar.y = GAME_CONFIG.ui.manaBar.y;
	manaBar.visible = false;
	manaText = new Text2('Mana: 100/100', {
		size: GAME_CONFIG.ui.manaText.size,
		fill: GAME_CONFIG.ui.manaText.fill,
		font: GAME_CONFIG.ui.manaText.font
	});
	manaText.anchor.set(0, 0);
	LK.gui.topRight.addChild(manaText);
	manaText.x = GAME_CONFIG.ui.manaText.x;
	manaText.y = GAME_CONFIG.ui.manaText.y;
	manaText.visible = false;
	// Spell slots
	for (var i = 0; i < GAME_CONFIG.ui.spellSlots.count; i++) {
		var slot = LK.getAsset('spellSlot', {
			anchorX: 0.5,
			anchorY: 0.5,
			scaleX: GAME_CONFIG.ui.spellSlots.scaleX,
			scaleY: GAME_CONFIG.ui.spellSlots.scaleY
		});
		LK.gui.bottom.addChild(slot);
		slot.x = GAME_CONFIG.ui.spellSlots.startX + i * GAME_CONFIG.ui.spellSlots.spacing;
		slot.y = GAME_CONFIG.ui.spellSlots.y;
		slot.visible = false;
		slot.slotIndex = i;
		// Add spell icon if spell exists
		if (i < activeSpellDeck.currentDeck.length) {
			var spellId = activeSpellDeck.currentDeck[i];
			var spell = activeSpellDeck.getSpell(spellId);
			if (spell) {
				var spellIcon = LK.getAsset('spell', {
					anchorX: 0.5,
					anchorY: 0.5
				});
				slot.addChild(spellIcon);
				spellIcon.tint = activeSpellDeck.getRarityColor(spell.rarity);
				spellIcon.scaleX = 0.8;
				spellIcon.scaleY = 0.8;
				slot.spellId = spellId;
				slot.spellIcon = spellIcon;
			}
		}
		// Add click handler for spell casting
		slot.down = function (x, y, obj) {
			if (obj.spellId && activeSpellDeck.canCastSpell(obj.spellId)) {
				// Cast spell at wizard position or target
				var spell = activeSpellDeck.getSpell(obj.spellId);
				if (spell) {
					var targetX = wizard.x;
					var targetY = wizard.y - 100;
					// Find nearest enemy for targeted spells
					if (spell.id === 'fireball' || spell.id === 'iceShard' || spell.id === 'lightning') {
						var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
						var nearestEnemy = null;
						var nearestDistance = Infinity;
						for (var e = 0; e < allEnemies.length; e++) {
							var enemy = allEnemies[e];
							var dx = enemy.x - wizard.x;
							var dy = enemy.y - wizard.y;
							var distance = Math.sqrt(dx * dx + dy * dy);
							if (distance < nearestDistance) {
								nearestDistance = distance;
								nearestEnemy = enemy;
							}
						}
						if (nearestEnemy) {
							targetX = nearestEnemy.x;
							targetY = nearestEnemy.y;
						}
					}
					activeSpellDeck.castSpell(obj.spellId, targetX, targetY);
					LK.effects.flashObject(obj, 0x00FF00, 200);
				}
			} else {
				LK.effects.flashObject(obj, 0xFF0000, 200);
			}
		};
		spellSlots.push(slot);
	}
}
// Update mana bar
function updateManaBar() {
	if (!manaBar || !manaText) return;
	var manaPercent = activeSpellDeck.currentMana / activeSpellDeck.maxMana;
	manaBar.scaleX = manaPercent * 2;
	manaText.setText('Mana: ' + Math.floor(activeSpellDeck.currentMana) + '/' + activeSpellDeck.maxMana);
}
// Update spell slot cooldowns
function updateSpellSlots() {
	for (var i = 0; i < spellSlots.length; i++) {
		var slot = spellSlots[i];
		if (slot.spellId) {
			var spell = activeSpellDeck.getSpell(slot.spellId);
			if (spell) {
				var cooldownEnd = activeSpellDeck.spellCooldowns[slot.spellId] || 0;
				var isOnCooldown = cooldownEnd > LK.ticks;
				// Update visual state
				if (isOnCooldown) {
					slot.alpha = 0.5;
					// Show cooldown overlay
					if (!slot.cooldownOverlay) {
						slot.cooldownOverlay = LK.getAsset('cooldownOverlay', {
							anchorX: 0.5,
							anchorY: 0.5
						});
						slot.addChild(slot.cooldownOverlay);
						slot.cooldownOverlay.alpha = 0.7;
					}
					// Update cooldown progress
					var remaining = cooldownEnd - LK.ticks;
					var total = spell.cooldown / 1000 * 60;
					var progress = 1 - remaining / total;
					slot.cooldownOverlay.scaleY = 1 - progress;
				} else {
					slot.alpha = 1.0;
					if (slot.cooldownOverlay) {
						slot.cooldownOverlay.destroy();
						slot.cooldownOverlay = null;
					}
				}
			}
		}
	}
}
// Initialize spell UI
createSpellUI();
// Initialize spell unlocking system
var lastUnlockCheck = 0;
function checkSpellUnlocks() {
	if (!gameMenu.spellDeck) {
		gameMenu.spellDeck = new SpellDeck();
	}
	// Only check unlocks when kill counter changes
	if (enemyKillCounter === lastUnlockCheck) return;
	lastUnlockCheck = enemyKillCounter;
	// Unlock spells based on achievements with messages
	if (enemyKillCounter >= 10 && !storage.lightningUnlocked) {
		storage.lightningUnlocked = true;
		gameMenu.spellDeck.unlockSpell('lightning');
		LK.effects.flashScreen(0x00FFFF, 500);
		showSpellUnlockMessage('LIGHTNING', 'Cadena de rayos entre enemigos');
	}
	if (enemyKillCounter >= 25 && !storage.shieldUnlocked) {
		storage.shieldUnlocked = true;
		gameMenu.spellDeck.unlockSpell('shield');
		LK.effects.flashScreen(0x0080FF, 500);
		showSpellUnlockMessage('MAGIC SHIELD', 'Inmunidad temporal al daño');
	}
	if (enemyKillCounter >= 50 && !storage.teleportUnlocked) {
		storage.teleportUnlocked = true;
		gameMenu.spellDeck.unlockSpell('teleport');
		LK.effects.flashScreen(0x8000FF, 500);
		showSpellUnlockMessage('TELEPORT', 'Mueve instantáneamente al mago');
	}
	if (enemyKillCounter >= 75 && !storage.timeSlowUnlocked) {
		storage.timeSlowUnlocked = true;
		gameMenu.spellDeck.unlockSpell('timeSlow');
		LK.effects.flashScreen(0xFF8000, 500);
		showSpellUnlockMessage('TIME SLOW', 'Ralentiza todos los enemigos');
	}
	if (enemyKillCounter >= 100 && !storage.meteorUnlocked) {
		storage.meteorUnlocked = true;
		gameMenu.spellDeck.unlockSpell('meteor');
		LK.effects.flashScreen(0xFF0000, 500);
		showSpellUnlockMessage('METEOR', 'Daño masivo en área');
	}
}
function showSpellUnlockMessage(spellName, description) {
	var unlockText = new Text2('NUEVO HECHIZO DESBLOQUEADO!\n' + spellName + '\n' + description, {
		size: 60,
		fill: 0xFFD700,
		font: "monospace"
	});
	unlockText.anchor.set(0.5, 0.5);
	unlockText.x = 2048 / 2;
	unlockText.y = 2732 / 2;
	game.addChild(unlockText);
	// Animate unlock message
	tween(unlockText, {
		scaleX: 1.2,
		scaleY: 1.2,
		alpha: 0.8
	}, {
		duration: 2000,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			tween(unlockText, {
				alpha: 0,
				y: unlockText.y - 200
			}, {
				duration: 1000,
				easing: tween.easeIn,
				onFinish: function onFinish() {
					if (unlockText.parent) unlockText.destroy();
				}
			});
		}
	});
}
// Upgrade system removed - using spell deck system instead
// Create unified path system - all 5 paths at once
var paths = [];
var knightX = 2048 / 2;
var knightY = 2732 - 250;
var pathAngles = [-Math.PI / 2, -Math.PI / 3, -2 * Math.PI / 3, Math.PI / 6, 5 * Math.PI / 6];
var wizardX = knightX;
var wizardY = 2732 - 600;
// Create knight reference for backward compatibility
var knight = wizard;
// Unified path creation function
function createUnifiedPaths() {
	var spawnPositions = GAME_CONFIG.paths.spawnPositions;
	for (var p = 0; p < GAME_CONFIG.paths.count; p++) {
		var angle = GAME_CONFIG.paths.angles[p];
		var spawnPos = spawnPositions[p];
		var actualPathLength = Math.sqrt((spawnPos.x - wizardX) * (spawnPos.x - wizardX) + (spawnPos.y - wizardY) * (spawnPos.y - wizardY));
		// Create stone segments
		var segmentSize = GAME_CONFIG.gameplay.segmentSize;
		var numSegments = Math.floor(actualPathLength / segmentSize);
		for (var s = 0; s < numSegments; s++) {
			var segmentDistance = s * segmentSize + segmentSize / 2;
			var segmentX = spawnPos.x - Math.cos(angle) * segmentDistance;
			var segmentY = spawnPos.y - Math.sin(angle) * segmentDistance;
			if (segmentX >= -100 && segmentX <= 2148 && segmentY >= -100 && segmentY <= 2832) {
				var stoneSegment = game.addChild(LK.getAsset('stonePath', {
					anchorX: 0.5,
					anchorY: 0.5,
					x: segmentX,
					y: segmentY,
					scaleX: 2.0,
					scaleY: 2.0,
					rotation: angle + Math.PI / 2
				}));
				stoneSegment.alpha = 0;
				stoneSegment.visible = false;
				stoneSegment.pathIndex = p;
			}
		}
		// Create collision area
		var centerX = (spawnPos.x + wizardX) / 2;
		var centerY = (spawnPos.y + wizardY) / 2;
		var path = game.addChild(LK.getAsset('pathSelector', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: centerX,
			y: centerY,
			scaleX: 4,
			scaleY: actualPathLength / 60,
			rotation: angle + Math.PI / 2
		}));
		path.alpha = 0;
		path.visible = false;
		path.pathIndex = p;
		// Add path number
		var pathNumber = new Text2((p + 1).toString(), {
			size: 120,
			fill: 0xFFD700,
			font: "monospace"
		});
		pathNumber.anchor.set(0.5, 0.5);
		pathNumber.x = spawnPos.x;
		pathNumber.y = spawnPos.y - 80;
		pathNumber.visible = false;
		pathNumber.pathIndex = p;
		game.addChild(pathNumber);
		// Add touch handler
		path.down = function (x, y, obj) {
			wizard.attack(obj.pathIndex);
		};
		paths.push(path);
	}
}
// Create all paths
createUnifiedPaths();
// Pixel art scaling handled by engine automatically
// Set fondodelacueva as the actual game background
var backgroundMap = game.addChild(LK.getAsset('fondodelacueva', {
	anchorX: 0,
	anchorY: 0,
	scaleX: 19.5,
	scaleY: 26.0,
	x: 0,
	y: 0
}));
// Send background to the back but use a less extreme z-index
backgroundMap.zIndex = -100;
// Hide background initially during menu
backgroundMap.visible = false;
backgroundMap.alpha = 1.0;
// Create wizard early to ensure it's available for other classes
var wizard = game.addChild(new Wizard());
wizard.x = knightX;
wizard.y = 2732 - 600; // Position wizard higher on screen
wizard.visible = false;
// UI Elements
// Removed scoreText and levelText to eliminate stray characters in top right
var coinCounter = 0;
var enemyKillCounter = 0;
var coinText = new Text2('Coins: 0', {
	size: GAME_CONFIG.ui.coinText.size,
	fill: GAME_CONFIG.ui.coinText.fill,
	font: GAME_CONFIG.ui.coinText.font
});
coinText.anchor.set(0, 0);
LK.gui.topLeft.addChild(coinText);
coinText.x = GAME_CONFIG.ui.coinText.x;
coinText.y = GAME_CONFIG.ui.coinText.y;
coinText.visible = false;
var killCountText = new Text2('Puntuacion: 0', {
	size: GAME_CONFIG.ui.killText.size,
	fill: GAME_CONFIG.ui.killText.fill,
	font: GAME_CONFIG.ui.killText.font
});
killCountText.anchor.set(0, 0);
LK.gui.topLeft.addChild(killCountText);
killCountText.x = GAME_CONFIG.ui.killText.x;
killCountText.y = GAME_CONFIG.ui.killText.y;
killCountText.visible = false;
var tapText = new Text2('TAP ENEMIES TO ATTACK!', {
	size: GAME_CONFIG.ui.tapText.size,
	fill: GAME_CONFIG.ui.tapText.fill,
	font: GAME_CONFIG.ui.tapText.font
});
tapText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(tapText);
tapText.y = GAME_CONFIG.ui.tapText.yOffset;
tapText.visible = false;
// Health bar UI
var healthBarBg = LK.getAsset('healthBarBg', {
	anchorX: 0,
	anchorY: 0,
	scaleX: GAME_CONFIG.ui.healthBarBg.scaleX,
	scaleY: GAME_CONFIG.ui.healthBarBg.scaleY
});
LK.gui.topLeft.addChild(healthBarBg);
healthBarBg.x = GAME_CONFIG.ui.healthBarBg.x;
healthBarBg.y = GAME_CONFIG.ui.healthBarBg.y;
healthBarBg.visible = false;
var healthBar = LK.getAsset('healthBar', {
	anchorX: 0,
	anchorY: 0,
	scaleX: GAME_CONFIG.ui.healthBar.scaleX,
	scaleY: GAME_CONFIG.ui.healthBar.scaleY
});
LK.gui.topLeft.addChild(healthBar);
healthBar.x = GAME_CONFIG.ui.healthBar.x;
healthBar.y = GAME_CONFIG.ui.healthBar.y;
healthBar.visible = false;
var healthText = new Text2('Health: 100/100', {
	size: GAME_CONFIG.ui.healthText.size,
	fill: GAME_CONFIG.ui.healthText.fill,
	font: GAME_CONFIG.ui.healthText.font
});
healthText.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthText);
healthText.x = GAME_CONFIG.ui.healthText.x;
healthText.y = GAME_CONFIG.ui.healthText.y;
healthText.visible = false;
function updateHealthBar() {
	var healthPercent = wizard.health / wizard.maxHealth;
	healthBar.scaleX = healthPercent;
	healthText.setText('Health: ' + wizard.health + '/' + wizard.maxHealth);
	// Change color based on health
	if (healthPercent > 0.6) {
		healthBar.tint = 0x00ff00; // Green
	} else if (healthPercent > 0.3) {
		healthBar.tint = 0xffff00; // Yellow
	} else {
		healthBar.tint = 0xff0000; // Red
	}
}
// Enemy spawning variables
var enemySpawnTimer = 0;
var lastSpawnedPath = -1; // Track the last spawned path
var consecutiveSpawns = 0; // Track consecutive spawns from same path
// Cooldown system variables
var pathLastSpawnTime = [-1, -1, -1, -1, -1]; // Track last spawn time for each path
var pathConsecutiveSpawns = [0, 0, 0, 0, 0]; // Track consecutive spawns per path
var pathCooldownDuration = 300; // 5 seconds at 60fps
// Unified SpawnManager for streamlined spawn control and enemy lifecycle
var SpawnManager = {
	// Consolidated spawn configuration
	spawnConfig: {
		skeleton: {
			interval: 90,
			maxCount: 15,
			startAt: 0
		},
		ogre: {
			interval: 180,
			maxCount: 4,
			startAt: 15
		},
		knight: {
			interval: 300,
			maxCount: 3,
			startAt: 30
		},
		miniBoss: {
			interval: 60,
			maxCount: 1,
			startAt: 80,
			endAt: 85,
			chance: 0.02
		}
	},
	// Unified spawn timers
	spawnTimers: {
		skeleton: 0,
		ogre: 0,
		knight: 0,
		miniBoss: 0
	},
	// Streamlined spawn validation
	canSpawnEnemy: function canSpawnEnemy(type, difficulty, totalEnemies) {
		var config = this.spawnConfig[type];
		if (!config) return false;
		var collection = globalEnemyManager.enemyCollections[type];
		var timer = this.spawnTimers[type];
		// Get threshold from GAME_CONFIG instead of local config
		var gameConfigThreshold = GAME_CONFIG.enemies[type].startThreshold;
		var threshold = _typeof4(gameConfigThreshold) === 'object' ? gameConfigThreshold[difficulty] : gameConfigThreshold;
		// Universal spawn conditions with type-specific rules
		var baseConditions = timer >= config.interval && enemyKillCounter >= threshold && collection.length < config.maxCount && totalEnemies < 25;
		// Special conditions for specific types
		if (type === 'miniBoss') {
			return baseConditions && enemyKillCounter <= config.endAt && globalEnemyManager.enemyCollections.miniBoss.length === 0 && Math.random() < config.chance;
		}
		return baseConditions && globalEnemyManager.enemyCollections.miniBoss.length === 0;
	},
	// Unified spawn execution
	executeSpawn: function executeSpawn(type, difficulty, level) {
		var totalEnemies = globalEnemyManager.getAllEnemies().length;
		if (!this.canSpawnEnemy(type, difficulty, totalEnemies)) return null;
		var enemy = globalEnemyManager.createEnemy(type, difficulty, level);
		if (enemy) {
			game.addChild(enemy);
			globalEnemyManager.addToCollection(enemy, type);
			// Legacy array compatibility
			if (type === 'skeleton') enemies.push(enemy);else if (type === 'ogre') ogres.push(enemy);else if (type === 'knight') knights.push(enemy);else if (type === 'miniBoss') miniBosses.push(enemy);
			this.spawnTimers[type] = 0;
			// Update path tracking for skeleton spawns
			if (type === 'skeleton') {
				pathConsecutiveSpawns[enemy.pathIndex]++;
				pathLastSpawnTime[enemy.pathIndex] = LK.ticks;
				lastSpawnedPath = enemy.pathIndex;
			}
		}
		return enemy;
	},
	// Streamlined interval updates
	updateSpawnIntervals: function updateSpawnIntervals(difficulty, level) {
		var base = GAME_CONFIG.enemies.skeleton.spawnInterval[difficulty];
		this.spawnConfig.skeleton.interval = Math.max(base.min, base.base - level * base.scaling);
		this.spawnConfig.ogre.interval = GAME_CONFIG.enemies.ogre.spawnInterval[difficulty];
		this.spawnConfig.knight.interval = GAME_CONFIG.enemies.knight.spawnInterval[difficulty];
	},
	// Unified timer updates
	updateTimers: function updateTimers() {
		for (var type in this.spawnTimers) {
			this.spawnTimers[type]++;
		}
		// Check if all paths are in cooldown and reset if needed
		var allPathsInCooldown = true;
		for (var pathIdx = 0; pathIdx < 5; pathIdx++) {
			if (pathConsecutiveSpawns[pathIdx] < 2) {
				allPathsInCooldown = false;
				break;
			}
		}
		if (allPathsInCooldown) {
			// Reset all path cooldowns to prevent spawn deadlock
			for (var pathIdx = 0; pathIdx < 5; pathIdx++) {
				pathConsecutiveSpawns[pathIdx] = 0;
				pathLastSpawnTime[pathIdx] = -1;
			}
		}
	},
	// Streamlined spawn cycle for all enemy types
	processSpawnCycle: function processSpawnCycle(difficulty, level) {
		this.updateSpawnIntervals(difficulty, level);
		this.updateTimers();
		// Clean up any null/destroyed enemies from collections first
		this.cleanupDestroyedEnemies();
		var enemyTypes = ['skeleton', 'ogre', 'knight', 'miniBoss'];
		for (var i = 0; i < enemyTypes.length; i++) {
			this.executeSpawn(enemyTypes[i], difficulty, level);
		}
	},
	// Add cleanup method for destroyed enemies
	cleanupDestroyedEnemies: function cleanupDestroyedEnemies() {
		// Clean up legacy arrays
		var allArrays = [enemies, ogres, knights, miniBosses];
		for (var arrayIdx = 0; arrayIdx < allArrays.length; arrayIdx++) {
			var array = allArrays[arrayIdx];
			for (var i = array.length - 1; i >= 0; i--) {
				if (!array[i] || !array[i].parent || array[i].isDying) {
					array.splice(i, 1);
				}
			}
		}
		// Clean up manager collections
		for (var type in globalEnemyManager.enemyCollections) {
			var collection = globalEnemyManager.enemyCollections[type];
			for (var i = collection.length - 1; i >= 0; i--) {
				if (!collection[i] || !collection[i].parent || collection[i].isDying) {
					collection.splice(i, 1);
				}
			}
		}
	}
};
// Game input handling
game.down = function (x, y, obj) {
	// Tap-to-attack is now handled directly by individual enemies
	// No need for path-based attacks since enemies handle their own tap events
};
// Initialize unified management systems for streamlined game architecture
var globalEnemyManager = new EnemyManager();
var globalDeathHandler = new UnifiedDeathHandler();
// Unified death animation function for all enemy types
function createEnemyDeathAnimation(enemy, enemyType, enemyArray) {
	globalDeathHandler.executeEnemyDeath(enemy, enemyArray);
}
// Main game update loop
game.update = function () {
	// Sort children by z-index to ensure proper rendering order
	game.children.sort(function (a, b) {
		return (a.zIndex || 0) - (b.zIndex || 0);
	});
	// Pause game when tutorial is active
	if (tutorial && tutorial.isActive) {
		return;
	}
	// Only update game logic if game has started
	if (!gameStarted) {
		return;
	}
	// Change music to epic battle theme at 10 enemies killed
	if (enemyKillCounter === 10) {
		LK.playMusic('epicBattle', {
			volume: 0.8,
			fade: {
				start: 0,
				end: 0.8,
				duration: 1500
			}
		});
	}
	// Change to mystical ambient music at 25 enemies killed
	if (enemyKillCounter === 25) {
		LK.playMusic('mysticalAmbient', {
			volume: 0.6,
			fade: {
				start: 0,
				end: 0.6,
				duration: 2000
			}
		});
	}
	// Upgrade menus removed - using spell deck system instead
	// Reset consecutive spawns for paths that have cooled down (runs every frame)
	for (var pathIdx = 0; pathIdx < 5; pathIdx++) {
		// Check if enough time has passed since last spawn (cooldown expired)
		if (pathLastSpawnTime[pathIdx] !== -1 && LK.ticks - pathLastSpawnTime[pathIdx] > pathCooldownDuration) {
			// Reset consecutive spawns for this path due to cooldown
			pathConsecutiveSpawns[pathIdx] = 0;
		}
	}
	// Get stored difficulty setting
	var selectedDifficulty = storage.difficulty || 'NORMAL';
	var difficultyLevel = Math.floor(enemyKillCounter / 10); // Every 10 kills increases difficulty
	// Apply unique difficulty modifiers
	var currentSpawnRate, enemyHealthMultiplier, enemySpeedMultiplier;
	var specialMechanics = {};
	if (selectedDifficulty === 'FACIL') {
		// EASY: Slower enemies, less health, longer spawn intervals
		currentSpawnRate = Math.max(60, 120 - difficultyLevel * 5); // Much slower spawning
		enemyHealthMultiplier = 1; // No health scaling over time
		enemySpeedMultiplier = 1 + difficultyLevel * 0.20; // 20% speed increase per level
		specialMechanics.bonusCoins = true; // 50% more coins
		specialMechanics.healingChance = 0.15; // 15% chance to heal 5 HP on enemy kill
	} else if (selectedDifficulty === 'NORMAL') {
		// NORMAL: Balanced progression
		currentSpawnRate = Math.max(40, 90 - difficultyLevel * 6); // Standard spawning
		enemyHealthMultiplier = 1; // No health scaling over time
		enemySpeedMultiplier = 1 + difficultyLevel * 0.30; // 30% speed increase per level
		specialMechanics.standardRewards = true;
	} else if (selectedDifficulty === 'DIFICIL') {
		// HARD: Faster enemies, more health, shorter spawn intervals, special enemy abilities
		currentSpawnRate = Math.max(20, 60 - difficultyLevel * 4); // Much faster spawning
		enemyHealthMultiplier = 1; // No health scaling over time
		enemySpeedMultiplier = 1 + difficultyLevel * 0.50; // 50% speed increase per level
		specialMechanics.eliteEnemies = true; // 20% chance for elite enemies with double stats
		specialMechanics.aggressiveAI = true; // Enemies move more directly toward wizard
		specialMechanics.reducedCoins = true; // 25% fewer coins
	}
	// Helper functions now integrated into EnemyFactory
	// Unified spawn management system
	SpawnManager.processSpawnCycle(selectedDifficulty, difficultyLevel);
	// Reset path cooldowns for optimized path management  
	for (var pathIdx = 0; pathIdx < 5; pathIdx++) {
		if (pathLastSpawnTime[pathIdx] !== -1 && LK.ticks - pathLastSpawnTime[pathIdx] > pathCooldownDuration) {
			pathConsecutiveSpawns[pathIdx] = 0;
		}
	}
	// Unified CollisionManager for streamlined collision detection and response
	var CollisionManager = {
		// Consolidated collision configurations
		collisionConfig: {
			skeleton: {
				damage: 20,
				removeOnHit: true
			},
			ogre: {
				damage: 30,
				removeOnHit: true
			},
			knight: {
				damage: 40,
				removeOnHit: true
			},
			miniBoss: {
				damage: 75,
				removeOnHit: false
			}
		},
		// Streamlined enemy collision processing with categorized collision types
		processEnemyCollisions: function processEnemyCollisions() {
			var allEnemies = globalEnemyManager.getAllEnemies();
			// Category 1: Off-screen cleanup (non-collision processing)
			this.processOffScreenCleanup(allEnemies);
			// Category 2: Enemy-wizard collisions
			this.processEnemyWizardCollisions(allEnemies);
		},
		// Separate processing for off-screen enemy cleanup
		processOffScreenCleanup: function processOffScreenCleanup(allEnemies) {
			for (var i = allEnemies.length - 1; i >= 0; i--) {
				var enemy = allEnemies[i];
				if (this.isOffScreen(enemy)) {
					this.removeEnemyFromGame(enemy);
				}
			}
		},
		// Separate processing for enemy-wizard collisions
		processEnemyWizardCollisions: function processEnemyWizardCollisions(allEnemies) {
			for (var i = 0; i < allEnemies.length; i++) {
				var enemy = allEnemies[i];
				if (!enemy.isDying && enemy.parent) {
					this.checkWizardCollision(enemy);
				}
			}
		},
		// Efficient off-screen detection
		isOffScreen: function isOffScreen(enemy) {
			return enemy.y > 2732 + 100;
		},
		// Unified enemy removal system
		removeEnemyFromGame: function removeEnemyFromGame(enemy) {
			// Remove from manager collections
			for (var type in globalEnemyManager.enemyCollections) {
				globalEnemyManager.removeFromCollection(enemy, type);
			}
			// Legacy array cleanup for compatibility
			this.removeFromLegacyArrays(enemy);
			enemy.destroy();
		},
		// Legacy array compatibility cleanup
		removeFromLegacyArrays: function removeFromLegacyArrays(enemy) {
			var arrays = [enemies, ogres, knights, miniBosses];
			for (var a = 0; a < arrays.length; a++) {
				var array = arrays[a];
				for (var i = array.length - 1; i >= 0; i--) {
					if (array[i] === enemy) {
						array.splice(i, 1);
						break;
					}
				}
			}
		},
		// Streamlined wizard collision detection with distance-based culling
		checkWizardCollision: function checkWizardCollision(enemy) {
			// Initialize collision tracking
			if (enemy.lastIntersecting === undefined) {
				enemy.lastIntersecting = false;
			}
			// Distance-based culling: Skip expensive intersection test if objects are too far apart
			var dx = enemy.x - wizard.x;
			var dy = enemy.y - wizard.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			var maxCollisionDistance = 150; // Approximate maximum collision distance based on sprite sizes
			var currentIntersecting = false;
			if (distance <= maxCollisionDistance) {
				// Only perform expensive intersection test if objects are close enough
				currentIntersecting = wizard.intersects(enemy);
			}
			// Check collision transition
			if (!enemy.lastIntersecting && currentIntersecting && !enemy.isDying) {
				var config = this.getEnemyConfig(enemy);
				wizard.takeDamage(config.damage);
				// Handle enemy removal based on type
				if (config.removeOnHit) {
					this.removeEnemyFromGame(enemy);
					return;
				}
			}
			// Update collision state
			enemy.lastIntersecting = currentIntersecting;
		},
		// Get enemy configuration by type
		getEnemyConfig: function getEnemyConfig(enemy) {
			return this.collisionConfig[enemy.enemyType] || this.collisionConfig.skeleton;
		}
	};
	// Replace the old collision function call
	function checkAllEnemyCollisions() {
		CollisionManager.processEnemyCollisions();
	}
	// Call the unified collision detection function
	checkAllEnemyCollisions();
	// Check thorns spike collisions with all enemies continuously
	var allSpikes = [];
	for (var childIdx = 0; childIdx < game.children.length; childIdx++) {
		var child = game.children[childIdx];
		// Check if this child is a spike (has hitEnemies array and brown tint)
		if (child.hitEnemies && child.tint === 0x8B4513) {
			allSpikes.push(child);
		}
	}
	for (var spikeIdx = 0; spikeIdx < allSpikes.length; spikeIdx++) {
		var spike = allSpikes[spikeIdx];
		var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
		for (var enemyIdx = 0; enemyIdx < allEnemies.length; enemyIdx++) {
			var enemy = allEnemies[enemyIdx];
			// Only hit enemies that haven't been hit by this spike yet and are not dying
			if (spike.intersects(enemy) && spike.hitEnemies.indexOf(enemy) === -1 && !enemy.isDying) {
				var thornDamage = 100; // Always deal 100 damage
				enemy.takeDamage(thornDamage);
				LK.effects.flashObject(enemy, 0x8B4513, 300);
				// Mark this enemy as hit by this spike
				spike.hitEnemies.push(enemy);
			}
		}
	}
	// Update optimized animation system
	if (globalAnimationManager) {
		globalAnimationManager.updateAnimations();
	}
	// Update spell deck system
	if (activeSpellDeck && gameStarted) {
		activeSpellDeck.updateMana();
		activeSpellDeck.updateCombo();
		updateManaBar();
		updateSpellSlots();
	}
	// Optimized time slow effects processing with batch management
	var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
	// Use batch processing for large enemy groups to improve performance
	if (allEnemies.length > 10 && globalAnimationManager) {
		globalAnimationManager.processBatchAnimations(allEnemies, 'enemies');
	}
	for (var i = 0; i < allEnemies.length; i++) {
		var enemy = allEnemies[i];
		if (enemy.timeSlowed) {
			enemy.timeSlowTimer--;
			if (enemy.timeSlowTimer <= 0) {
				enemy.timeSlowed = false;
				enemy.timeSlowAmount = 1.0;
			}
		}
	}
	// Make tap text pulse
	var pulse = 1 + Math.sin(LK.ticks * 0.1) * 0.2;
	tapText.scale.set(pulse, pulse);
	// Check for spell unlocks
	checkSpellUnlocks();
	// Clean up any orphaned projectiles that may not have been properly removed
	for (var i = projectiles.length - 1; i >= 0; i--) {
		var projectile = projectiles[i];
		if (!projectile || !projectile.parent || projectile.hitEnemy) {
			projectiles.splice(i, 1);
		}
	}
	// Ensure ProjectileFactory activeProjectiles array stays synchronized
	for (var i = ProjectileFactory.activeProjectiles.length - 1; i >= 0; i--) {
		var projectile = ProjectileFactory.activeProjectiles[i];
		if (!projectile || !projectile.parent || projectile.hitEnemy) {
			ProjectileFactory.activeProjectiles.splice(i, 1);
		}
	}
};
// Remove tap text after 5 seconds
tween({}, {}, {
	duration: 5000,
	onFinish: function onFinish() {
		if (tapText && tapText.parent) {
			tapText.destroy();
		}
	}
});
// Separate collision processing for orb-enemy interactions
self.processOrbEnemyCollisions = function () {
	var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
	for (var i = 0; i < allEnemies.length; i++) {
		var enemy = allEnemies[i];
		// Skip collision check with wizard
		if (enemy === wizard) {
			continue;
		}
		// Initialize collision tracking for this enemy if not exists
		if (!self.lastIntersecting) {
			self.lastIntersecting = {};
		}
		if (self.lastIntersecting[i] === undefined) {
			self.lastIntersecting[i] = false;
		}
		// Distance-based culling for orb collisions
		var dx = enemy.x - self.x;
		var dy = enemy.y - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		var maxOrbRange = 80; // Orb collision range
		var currentIntersecting = false;
		if (distance <= maxOrbRange) {
			// Only check intersection if enemy is close enough
			currentIntersecting = self.intersects(enemy);
		}
		if (!self.lastIntersecting[i] && currentIntersecting) {
			// Deal damage to enemy on contact transition (first contact only)
			enemy.takeDamage(200);
			// Visual effect for orb hit
			LK.effects.flashObject(self, 0xFFFFFF, 200);
			// Create orb impact effect
			var orbImpact = game.addChild(LK.getAsset('energySphere', {
				anchorX: 0.5,
				anchorY: 0.5,
				x: enemy.x,
				y: enemy.y,
				scaleX: 0.3,
				scaleY: 0.3
			}));
			orbImpact.tint = 0xFFD700;
			orbImpact.alpha = 0.8;
			// Animate orb impact
			tween(orbImpact, {
				scaleX: 1.5,
				scaleY: 1.5,
				alpha: 0
			}, {
				duration: 250,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					orbImpact.destroy();
				}
			});
		}
		// Update collision state for this enemy
		self.lastIntersecting[i] = currentIntersecting;
	}
}; ===================================================================
--- original.js
+++ change.js
@@ -2601,65 +2601,10 @@
 		// Add pulsing effect
 		var pulse = 1 + Math.sin(LK.ticks * 0.3) * 0.2;
 		orbGraphics.scaleX = 0.4 * pulse;
 		orbGraphics.scaleY = 0.4 * pulse;
-		// Check collision with enemies using collision state tracking (but never with wizard)
-		var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
-		for (var i = 0; i < allEnemies.length; i++) {
-			var enemy = allEnemies[i];
-			// Skip collision check with wizard
-			if (enemy === wizard) {
-				continue;
-			}
-			// Initialize collision tracking for this enemy if not exists
-			if (!self.lastIntersecting) {
-				self.lastIntersecting = {};
-			}
-			if (self.lastIntersecting[i] === undefined) {
-				self.lastIntersecting[i] = false;
-			}
-			// Distance-based culling for orb collisions
-			var dx = enemy.x - self.x;
-			var dy = enemy.y - self.y;
-			var distance = Math.sqrt(dx * dx + dy * dy);
-			var maxOrbRange = 80; // Orb collision range
-			var currentIntersecting = false;
-			if (distance <= maxOrbRange) {
-				// Only check intersection if enemy is close enough
-				currentIntersecting = self.intersects(enemy);
-			}
-			if (!self.lastIntersecting[i] && currentIntersecting) {
-				// Deal damage to enemy on contact transition (first contact only)
-				enemy.takeDamage(200);
-				// Visual effect for orb hit
-				LK.effects.flashObject(self, 0xFFFFFF, 200);
-				// Create orb impact effect
-				var orbImpact = game.addChild(LK.getAsset('energySphere', {
-					anchorX: 0.5,
-					anchorY: 0.5,
-					x: enemy.x,
-					y: enemy.y,
-					scaleX: 0.3,
-					scaleY: 0.3
-				}));
-				orbImpact.tint = 0xFFD700;
-				orbImpact.alpha = 0.8;
-				// Animate orb impact
-				tween(orbImpact, {
-					scaleX: 1.5,
-					scaleY: 1.5,
-					alpha: 0
-				}, {
-					duration: 250,
-					easing: tween.easeOut,
-					onFinish: function onFinish() {
-						orbImpact.destroy();
-					}
-				});
-			}
-			// Update collision state for this enemy
-			self.lastIntersecting[i] = currentIntersecting;
-		}
+		// Category 3: Orb-enemy collisions (separate from projectile-enemy and enemy-wizard)
+		self.processOrbEnemyCollisions();
 	};
 	return self;
 });
 // Create global death handler instance
@@ -2758,52 +2703,60 @@
 		self.checkCollisions();
 	};
 	self.checkCollisions = function () {
 		if (self.hitEnemy) return;
+		// Category 1: Area damage projectiles (fireball)
 		if (self.type === 'fireBall') {
-			// Area damage for fireball with distance culling
-			var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
-			for (var i = 0; i < allEnemies.length; i++) {
-				var enemy = allEnemies[i];
-				if (enemy === wizard || enemy.isDying) continue;
-				// Distance-based culling for fireball area damage
-				var dx = enemy.x - self.x;
-				var dy = enemy.y - self.y;
-				var distance = Math.sqrt(dx * dx + dy * dy);
-				var maxFireballRange = 120; // Fireball collision range including area effect
-				if (distance <= maxFireballRange && self.intersects(enemy)) {
-					enemy.takeDamage(self.damage);
-					self.createExplosion(enemy);
-					self.hitEnemy = true;
-					// Remove from projectiles array before destroying
-					ProjectileFactory.removeProjectile(self);
-					return;
-				}
-			}
+			self.processAreaDamageCollisions();
 		} else {
-			// Single target collision with distance culling
-			if (self.targetEnemy && self.targetEnemy.parent && !self.targetEnemy.isDying) {
-				// Distance-based culling for targeted projectiles
-				var dx = self.targetEnemy.x - self.x;
-				var dy = self.targetEnemy.y - self.y;
-				var distance = Math.sqrt(dx * dx + dy * dy);
-				var maxProjectileRange = 100; // Standard projectile collision range
-				if (distance <= maxProjectileRange && self.intersects(self.targetEnemy)) {
-					self.targetEnemy.takeDamage(self.damage);
-					self.hitEnemy = true;
-					// Remove from projectiles array before destroying
-					ProjectileFactory.removeProjectile(self);
-					return;
-				}
-			} else {
-				// Target is invalid, remove projectile
+			// Category 2: Single target projectiles
+			self.processSingleTargetCollisions();
+		}
+	};
+	// Separate collision processing for area damage projectiles
+	self.processAreaDamageCollisions = function () {
+		var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
+		for (var i = 0; i < allEnemies.length; i++) {
+			var enemy = allEnemies[i];
+			if (enemy === wizard || enemy.isDying) continue;
+			// Distance-based culling for fireball area damage
+			var dx = enemy.x - self.x;
+			var dy = enemy.y - self.y;
+			var distance = Math.sqrt(dx * dx + dy * dy);
+			var maxFireballRange = 120; // Fireball collision range including area effect
+			if (distance <= maxFireballRange && self.intersects(enemy)) {
+				enemy.takeDamage(self.damage);
+				self.createExplosion(enemy);
 				self.hitEnemy = true;
 				// Remove from projectiles array before destroying
 				ProjectileFactory.removeProjectile(self);
 				return;
 			}
 		}
 	};
+	// Separate collision processing for single target projectiles  
+	self.processSingleTargetCollisions = function () {
+		if (self.targetEnemy && self.targetEnemy.parent && !self.targetEnemy.isDying) {
+			// Distance-based culling for targeted projectiles
+			var dx = self.targetEnemy.x - self.x;
+			var dy = self.targetEnemy.y - self.y;
+			var distance = Math.sqrt(dx * dx + dy * dy);
+			var maxProjectileRange = 100; // Standard projectile collision range
+			if (distance <= maxProjectileRange && self.intersects(self.targetEnemy)) {
+				self.targetEnemy.takeDamage(self.damage);
+				self.hitEnemy = true;
+				// Remove from projectiles array before destroying
+				ProjectileFactory.removeProjectile(self);
+				return;
+			}
+		} else {
+			// Target is invalid, remove projectile
+			self.hitEnemy = true;
+			// Remove from projectiles array before destroying
+			ProjectileFactory.removeProjectile(self);
+			return;
+		}
+	};
 	self.createExplosion = function (enemy) {
 		LK.effects.flashObject(enemy, 0xFF4500, 400);
 		var explosion = game.addChild(LK.getAsset('projectileGlow', {
 			anchorX: 0.5,
@@ -5831,22 +5784,34 @@
 				damage: 75,
 				removeOnHit: false
 			}
 		},
-		// Streamlined enemy collision processing
+		// Streamlined enemy collision processing with categorized collision types
 		processEnemyCollisions: function processEnemyCollisions() {
 			var allEnemies = globalEnemyManager.getAllEnemies();
+			// Category 1: Off-screen cleanup (non-collision processing)
+			this.processOffScreenCleanup(allEnemies);
+			// Category 2: Enemy-wizard collisions
+			this.processEnemyWizardCollisions(allEnemies);
+		},
+		// Separate processing for off-screen enemy cleanup
+		processOffScreenCleanup: function processOffScreenCleanup(allEnemies) {
 			for (var i = allEnemies.length - 1; i >= 0; i--) {
 				var enemy = allEnemies[i];
-				// Unified off-screen cleanup
 				if (this.isOffScreen(enemy)) {
 					this.removeEnemyFromGame(enemy);
-					continue;
 				}
-				// Streamlined collision detection
-				this.checkWizardCollision(enemy);
 			}
 		},
+		// Separate processing for enemy-wizard collisions
+		processEnemyWizardCollisions: function processEnemyWizardCollisions(allEnemies) {
+			for (var i = 0; i < allEnemies.length; i++) {
+				var enemy = allEnemies[i];
+				if (!enemy.isDying && enemy.parent) {
+					this.checkWizardCollision(enemy);
+				}
+			}
+		},
 		// Efficient off-screen detection
 		isOffScreen: function isOffScreen(enemy) {
 			return enemy.y > 2732 + 100;
 		},
@@ -5991,5 +5956,64 @@
 		if (tapText && tapText.parent) {
 			tapText.destroy();
 		}
 	}
-});
\ No newline at end of file
+});
+// Separate collision processing for orb-enemy interactions
+self.processOrbEnemyCollisions = function () {
+	var allEnemies = enemies.concat(ogres).concat(knights).concat(miniBosses);
+	for (var i = 0; i < allEnemies.length; i++) {
+		var enemy = allEnemies[i];
+		// Skip collision check with wizard
+		if (enemy === wizard) {
+			continue;
+		}
+		// Initialize collision tracking for this enemy if not exists
+		if (!self.lastIntersecting) {
+			self.lastIntersecting = {};
+		}
+		if (self.lastIntersecting[i] === undefined) {
+			self.lastIntersecting[i] = false;
+		}
+		// Distance-based culling for orb collisions
+		var dx = enemy.x - self.x;
+		var dy = enemy.y - self.y;
+		var distance = Math.sqrt(dx * dx + dy * dy);
+		var maxOrbRange = 80; // Orb collision range
+		var currentIntersecting = false;
+		if (distance <= maxOrbRange) {
+			// Only check intersection if enemy is close enough
+			currentIntersecting = self.intersects(enemy);
+		}
+		if (!self.lastIntersecting[i] && currentIntersecting) {
+			// Deal damage to enemy on contact transition (first contact only)
+			enemy.takeDamage(200);
+			// Visual effect for orb hit
+			LK.effects.flashObject(self, 0xFFFFFF, 200);
+			// Create orb impact effect
+			var orbImpact = game.addChild(LK.getAsset('energySphere', {
+				anchorX: 0.5,
+				anchorY: 0.5,
+				x: enemy.x,
+				y: enemy.y,
+				scaleX: 0.3,
+				scaleY: 0.3
+			}));
+			orbImpact.tint = 0xFFD700;
+			orbImpact.alpha = 0.8;
+			// Animate orb impact
+			tween(orbImpact, {
+				scaleX: 1.5,
+				scaleY: 1.5,
+				alpha: 0
+			}, {
+				duration: 250,
+				easing: tween.easeOut,
+				onFinish: function onFinish() {
+					orbImpact.destroy();
+				}
+			});
+		}
+		// Update collision state for this enemy
+		self.lastIntersecting[i] = currentIntersecting;
+	}
+};
\ No newline at end of file