| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488 |
- using UnityEngine;
- using System.Collections.Generic;
- using System.Linq;
- /// <summary>
- /// Main travel event system that manages when and where events occur during travel
- /// Integrates with the existing TeamTravelSystem
- /// </summary>
- 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<TravelEvent> availableEvents = new List<TravelEvent>();
- [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<TeamTravelSystem>();
- mapMaker = FindFirstObjectByType<MapMaker2>();
- teamPlacement = FindFirstObjectByType<SimpleTeamPlacement>();
- eventUI = FindFirstObjectByType<TravelEventUI>();
- // Enhanced system will be found after compilation
- // enhancedEventSystem = FindFirstObjectByType<EnhancedTravelEventSystem>();
- 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;
- }
- }
- /// <summary>
- /// Main method to check if a travel event should occur
- /// </summary>
- 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);
- }
- }
- /// <summary>
- /// Force a specific event to occur (for testing or story purposes)
- /// </summary>
- public void TriggerSpecificEvent(TravelEvent eventToTrigger)
- {
- if (eventToTrigger == null) return;
- currentContext = CreateCurrentContext();
- if (currentContext == null) return;
- ExecuteEvent(eventToTrigger, currentContext);
- }
- /// <summary>
- /// Trigger a random event based on current context
- /// </summary>
- 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);
- }
- }
- /// <summary>
- /// Execute a travel event and handle its results
- /// </summary>
- 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);
- }
- /// <summary>
- /// Handle the results of a travel event
- /// </summary>
- 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);
- }
- }
- /// <summary>
- /// Create travel event context from current game state
- /// </summary>
- 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;
- }
- /// <summary>
- /// Calculate the threshold for events to occur based on context
- /// </summary>
- 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);
- }
- /// <summary>
- /// Get all events that can occur in the current context
- /// </summary>
- private List<TravelEvent> GetPossibleEvents(TravelEventContext context)
- {
- return availableEvents.Where(e => e != null && e.CanOccur(context)).ToList();
- }
- /// <summary>
- /// Select an event based on weighted probabilities
- /// </summary>
- private TravelEvent SelectWeightedEvent(List<TravelEvent> 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
- }
- /// <summary>
- /// Apply resource changes from event results
- /// </summary>
- 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}");
- }
- }
- /// <summary>
- /// Handle battle events by setting up battle data
- /// </summary>
- 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
- });
- }
- */
- }
- }
- /// <summary>
- /// Handle trading events by opening shop interface
- /// </summary>
- 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
- }
- /// <summary>
- /// Display event message to player
- /// </summary>
- 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);
- }
- }
- /// <summary>
- /// Load default events if none are assigned in inspector
- /// </summary>
- private void LoadDefaultEvents()
- {
- // Load default events from Resources folder
- TravelEvent[] defaultEvents = Resources.LoadAll<TravelEvent>("TravelEvents");
- availableEvents.AddRange(defaultEvents);
- if (showDebugLogs)
- {
- Debug.Log($"🔄 Loaded {defaultEvents.Length} default events from Resources");
- }
- }
- /// <summary>
- /// Debug method to show event distribution
- /// </summary>
- 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");
- }
- }
- /// <summary>
- /// Public method to trigger event check manually (for testing)
- /// </summary>
- [ContextMenu("Trigger Event Check")]
- public void TriggerEventCheck()
- {
- forceNextEvent = true;
- CheckForTravelEvent();
- }
- /// <summary>
- /// Reset event history (useful for testing)
- /// </summary>
- [ContextMenu("Reset Event History")]
- public void ResetEventHistory()
- {
- globalEventHistory = new TravelEventHistory();
- tilesTraveledSinceLastCheck = 0;
- Debug.Log("🔄 Event history reset");
- }
- }
|