using UnityEngine; using System.Collections.Generic; using System.Linq; /// /// Main travel event system that manages when and where events occur during travel /// Integrates with the existing TeamTravelSystem /// public class TravelEventSystem : MonoBehaviour { [Header("Event System Settings")] public bool enableEvents = true; [Range(0f, 1f)] public float baseEventChance = 0.15f; // 15% chance per tile by default [Range(1, 10)] public int tilesPerEventCheck = 3; // Check for events every N tiles [Header("Event Collections")] public List availableEvents = new List(); [Header("Debug")] public bool showDebugLogs = true; public bool forceNextEvent = false; // For testing // Event tracking private TravelEventHistory globalEventHistory; private int tilesTraveledSinceLastCheck = 0; private TravelEventContext currentContext; // Component references private TeamTravelSystem travelSystem; private MapMaker2 mapMaker; private SimpleTeamPlacement teamPlacement; private TravelEventUI eventUI; // Enhanced system will be linked after compilation private object enhancedEventSystem; void Start() { // Find required components travelSystem = FindFirstObjectByType(); mapMaker = FindFirstObjectByType(); teamPlacement = FindFirstObjectByType(); eventUI = FindFirstObjectByType(); // Enhanced system will be found after compilation // enhancedEventSystem = FindFirstObjectByType(); globalEventHistory = new TravelEventHistory(); if (showDebugLogs) { Debug.Log($"🎲 Travel Event System initialized with {availableEvents.Count} events"); if (eventUI == null) Debug.LogWarning("⚠️ TravelEventUI not found. Event messages will only appear in console."); LogEventDistribution(); } // Load default events if none are assigned if (availableEvents.Count == 0) { LoadDefaultEvents(); } } void Update() { if (!enableEvents || travelSystem == null || !travelSystem.IsTraveling()) return; // Check if we should evaluate for events tilesTraveledSinceLastCheck++; if (tilesTraveledSinceLastCheck >= tilesPerEventCheck) { CheckForTravelEvent(); tilesTraveledSinceLastCheck = 0; } } /// /// Main method to check if a travel event should occur /// public void CheckForTravelEvent() { if (!enableEvents) return; // Get current travel context currentContext = CreateCurrentContext(); if (currentContext == null) return; // Calculate if an event should occur float eventRoll = Random.value; float eventThreshold = CalculateEventThreshold(currentContext); // Force event for testing if (forceNextEvent) { forceNextEvent = false; eventRoll = 0f; // Guarantee event eventThreshold = 1f; } if (eventRoll <= eventThreshold) { TriggerRandomEvent(currentContext); } } /// /// Force a specific event to occur (for testing or story purposes) /// public void TriggerSpecificEvent(TravelEvent eventToTrigger) { if (eventToTrigger == null) return; currentContext = CreateCurrentContext(); if (currentContext == null) return; ExecuteEvent(eventToTrigger, currentContext); } /// /// Trigger a random event based on current context /// private void TriggerRandomEvent(TravelEventContext context) { var possibleEvents = GetPossibleEvents(context); if (possibleEvents.Count == 0) { if (showDebugLogs) Debug.Log("🎲 No valid events found for current context"); return; } // Select event based on weighted chances TravelEvent selectedEvent = SelectWeightedEvent(possibleEvents, context); if (selectedEvent != null) { ExecuteEvent(selectedEvent, context); } } /// /// Execute a travel event and handle its results /// private void ExecuteEvent(TravelEvent travelEvent, TravelEventContext context) { if (showDebugLogs) { Debug.Log($"🎭 Executing event: {travelEvent.eventName} at {context.currentPosition}"); } // Execute the event EventResult result = travelEvent.ExecuteEvent(context); if (!result.eventOccurred) { if (showDebugLogs) Debug.Log($"🎭 Event {travelEvent.eventName} chose not to occur"); return; } // Record the event globalEventHistory.RecordEvent(travelEvent, context); // Display event message if (eventUI != null) { eventUI.ShowEventResult(result); } else { ShowEventMessage(result.resultMessage); } // Handle the event result HandleEventResult(result, context); } /// /// Handle the results of a travel event /// private void HandleEventResult(EventResult result, TravelEventContext context) { // Apply resource changes ApplyResourceChanges(result); // Handle special event types if (result.shouldStopTravel) { if (travelSystem != null) { // Stop current travel using the existing cancellation system travelSystem.CancelJourney(); Debug.Log("🛑 Travel stopped due to event"); } } if (result.startBattle) { HandleBattleEvent(result.battleData, context); } if (result.openTrading) { HandleTradingEvent(result.tradingData, context); } } /// /// Create travel event context from current game state /// private TravelEventContext CreateCurrentContext() { if (teamPlacement == null || mapMaker == null || travelSystem == null) return null; Vector2Int currentPos = teamPlacement.GetCurrentTeamPosition(); var mapData = mapMaker.GetMapData(); var currentTile = mapData.GetTile(currentPos.x, currentPos.y); var currentRoute = travelSystem.GetCurrentRoute(); var context = new TravelEventContext(currentPos, currentTile, currentRoute) { dayOfJourney = 1, // This could be tracked elsewhere timeOfDay = 12f, // This could be from a day/night system teamGold = 100, // This should come from actual team resources teamFood = 50, eventHistory = globalEventHistory }; // Set travel context if (currentRoute != null) { context.destination = travelSystem.GetPlannedDestination() ?? currentPos; context.isOnMainRoad = currentTile.featureType == FeatureType.Road; } return context; } /// /// Calculate the threshold for events to occur based on context /// private float CalculateEventThreshold(TravelEventContext context) { float threshold = baseEventChance; // Modify based on terrain (some areas are more eventful) switch (context.currentTile.terrainType) { case TerrainType.Forest: threshold *= 1.3f; // More events in forests break; case TerrainType.Mountain: threshold *= 1.4f; // Even more in mountains break; case TerrainType.Plains: threshold *= 0.8f; // Fewer in plains break; } // Modify based on features switch (context.currentTile.featureType) { case FeatureType.Road: threshold *= 0.7f; // Fewer events on roads (safer travel) break; case FeatureType.Town: case FeatureType.Village: threshold *= 0.5f; // Much fewer in settlements break; } return Mathf.Clamp01(threshold); } /// /// Get all events that can occur in the current context /// private List GetPossibleEvents(TravelEventContext context) { return availableEvents.Where(e => e != null && e.CanOccur(context)).ToList(); } /// /// Select an event based on weighted probabilities /// private TravelEvent SelectWeightedEvent(List events, TravelEventContext context) { if (events.Count == 0) return null; if (events.Count == 1) return events[0]; // Calculate weights var weights = events.Select(e => e.GetEventChance(context.currentTile)).ToList(); float totalWeight = weights.Sum(); if (totalWeight <= 0) return null; // Select based on weight float randomValue = Random.value * totalWeight; float currentWeight = 0f; for (int i = 0; i < events.Count; i++) { currentWeight += weights[i]; if (randomValue <= currentWeight) { return events[i]; } } return events.Last(); // Fallback } /// /// Apply resource changes from event results /// private void ApplyResourceChanges(EventResult result) { if (result.goldChange != 0) { // Apply gold change to team resources // This would integrate with your resource system Debug.Log($"💰 Gold changed by {result.goldChange}"); } if (result.healthChange != 0) { // Apply health change to team // This would integrate with your character health system Debug.Log($"❤️ Health changed by {result.healthChange}"); } if (result.foodChange != 0) { // Apply food change Debug.Log($"🍖 Food changed by {result.foodChange}"); } } /// /// Handle battle events by setting up battle data /// private void HandleBattleEvent(BattleEventData battleData, TravelEventContext context) { if (battleData == null) return; // Try to use enhanced event system for player choice popup var enhancedSystem = FindFirstObjectByType(System.Type.GetType("EnhancedTravelEventSystem")); if (enhancedSystem != null) { Debug.Log("🎭 Using Enhanced Travel Event System for combat popup"); // Use reflection to call the enhanced handler var method = enhancedSystem.GetType().GetMethod("HandleEnhancedBattleEvent"); if (method != null) { string eventDescription = $"Your party encounters {battleData.enemyCount} {battleData.enemyType}!"; method.Invoke(enhancedSystem, new object[] { battleData, context, eventDescription }); return; } } // Fallback to original battle handling Debug.Log($"⚔️ Setting up battle: {battleData.enemyCount} {battleData.enemyType}(s)"); // Enhanced battle setup using EnemyCharacterData if available if (battleData.enemyCharacterData != null) { Debug.Log($"🎯 Using enemy data: {battleData.enemyCharacterData.enemyName}"); Debug.Log($"📊 Enemy stats: HP={battleData.enemyCharacterData.maxHealth}, " + $"AC={battleData.enemyCharacterData.armorClass}, " + $"Threat={battleData.enemyCharacterData.threatLevel}"); // TODO: Enhanced battle setup with actual enemy data /* BattleSetupData.enemySelections.Clear(); for (int i = 0; i < battleData.enemyCount; i++) { var enemyData = battleData.enemyCharacterData; BattleSetupData.enemySelections.Add(new CharacterSelection { characterName = $"{enemyData.enemyName}_{i+1}", weaponType = enemyData.preferredWeapon != null ? enemyData.preferredWeapon.weaponType.ToString() : "Sword", // Could also include: // health = enemyData.maxHealth, // armorClass = enemyData.armorClass, // threatLevel = enemyData.threatLevel }); } */ } else { // Fallback to string-based system Debug.Log("⚠️ No EnemyCharacterData found, using legacy string-based setup"); /* BattleSetupData.enemySelections.Clear(); for (int i = 0; i < battleData.enemyCount; i++) { BattleSetupData.enemySelections.Add(new CharacterSelection { characterName = $"{battleData.enemyType}_{i+1}", weaponType = "Sword" // Could be randomized }); } */ } } /// /// Handle trading events by opening shop interface /// private void HandleTradingEvent(TradingEventData tradingData, TravelEventContext context) { if (tradingData == null) return; Debug.Log($"🛒 Opening trading with {tradingData.merchantType}"); // This would open your shop system // You could modify shop inventory based on merchantType and hasRareItems } /// /// Display event message to player /// private void ShowEventMessage(string message) { if (string.IsNullOrEmpty(message)) return; Debug.Log($"📜 EVENT: {message}"); // Use UI system if available if (eventUI != null) { eventUI.ShowEventMessage(message); } } /// /// Load default events if none are assigned in inspector /// private void LoadDefaultEvents() { // Load default events from Resources folder TravelEvent[] defaultEvents = Resources.LoadAll("TravelEvents"); availableEvents.AddRange(defaultEvents); if (showDebugLogs) { Debug.Log($"🔄 Loaded {defaultEvents.Length} default events from Resources"); } } /// /// Debug method to show event distribution /// private void LogEventDistribution() { if (!showDebugLogs) return; var eventsByType = availableEvents.GroupBy(e => e.eventType); foreach (var group in eventsByType) { Debug.Log($"📊 {group.Key}: {group.Count()} events"); } } /// /// Public method to trigger event check manually (for testing) /// [ContextMenu("Trigger Event Check")] public void TriggerEventCheck() { forceNextEvent = true; CheckForTravelEvent(); } /// /// Reset event history (useful for testing) /// [ContextMenu("Reset Event History")] public void ResetEventHistory() { globalEventHistory = new TravelEventHistory(); tilesTraveledSinceLastCheck = 0; Debug.Log("🔄 Event history reset"); } }