using UnityEngine; /// /// Combat encounter events - ambushes, bandits, wild animals, etc. /// More likely in forests and mountains, less likely on roads /// [CreateAssetMenu(fileName = "New Combat Event", menuName = "RPG/Travel Events/Combat Event")] public class CombatTravelEvent : TravelEvent { [Header("Combat Event Settings")] public int minEnemies = 1; public int maxEnemies = 3; [Tooltip("Drag EnemyCharacterData assets here")] public EnemyCharacterData[] possibleEnemies = new EnemyCharacterData[0]; [Header("Escape Configuration")] public bool allowRunningAway = true; [Range(0f, 1f)] public float runAwaySuccessChance = 0.75f; public int runAwayHealthPenalty = 5; [Header("Run Away Messages")] [TextArea(2, 4)] public string[] successfulRunAwayMessages = { "Your party successfully escapes from the enemies!", "Quick thinking allows your party to avoid the confrontation!", "Your party slips away unnoticed by the enemies." }; [TextArea(2, 4)] public string[] failedRunAwayMessages = { "The enemies catch up to your party! You take {damage} damage while trying to escape.", "Your escape attempt fails! The enemies pursue and wound your party for {damage} damage.", "The enemies block your escape route! Your party suffers {damage} damage in the failed attempt." }; [Header("Combat Event Descriptions")] [TextArea(2, 4)] public string[] encounterDescriptions = { "Your party is ambushed by {enemyType}s!", "A group of {enemyType}s blocks your path!", "You stumble upon a {enemyType} camp!" }; public override EventResult ExecuteEvent(TravelEventContext context) { int enemyCount = Random.Range(minEnemies, maxEnemies + 1); // Ensure we have valid enemies configured if (possibleEnemies == null || possibleEnemies.Length == 0) { Debug.LogError($"No enemies configured for combat event: {eventName}"); return EventResult.NoEvent(); } // Filter out null entries var validEnemies = System.Array.FindAll(possibleEnemies, e => e != null); if (validEnemies.Length == 0) { Debug.LogError($"All enemy references are null for combat event: {eventName}"); return EventResult.NoEvent(); } // Select random enemy EnemyCharacterData selectedEnemy = validEnemies[Random.Range(0, validEnemies.Length)]; string enemyType = selectedEnemy.enemyName; // Generate description string description = encounterDescriptions[Random.Range(0, encounterDescriptions.Length)]; description = description.Replace("{enemyType}", enemyType); // First try to find it by component type var integrationComponents = FindObjectsByType(FindObjectsSortMode.None); var combatIntegration = System.Array.Find(integrationComponents, comp => comp.GetType().Name == "CombatEventIntegration"); if (combatIntegration == null) { // Try the reflection approach as fallback var type = System.Type.GetType("CombatEventIntegration"); if (type != null) { combatIntegration = FindFirstObjectByType(type) as MonoBehaviour; } } if (combatIntegration != null) { // Create battle data for the popup var battleData = new BattleEventData { enemyCount = enemyCount, enemyType = enemyType, enemyCharacterData = selectedEnemy }; // Use reflection to call ShowCombatChoicePopup with the new signature var method = combatIntegration.GetType().GetMethod("ShowCombatChoicePopup"); if (method != null) { method.Invoke(combatIntegration, new object[] { battleData, context, description, this }); // Return a special result that indicates popup is handling the choice return new EventResult("Combat encounter detected...") { shouldStopTravel = true, // Stop travel while popup is showing startBattle = false, // Don't start battle yet - popup will handle it suppressMessage = true, // Don't show default message - popup handles display eventOccurred = true }; } else { Debug.LogError("❌ ShowCombatChoicePopup method not found on CombatEventIntegration"); } } else { Debug.LogWarning("⚠️ No CombatEventIntegration component found in scene"); } // Fallback to immediate battle if no integration found Debug.LogWarning("⚠️ No CombatEventIntegration found, proceeding with immediate battle"); var result = EventResult.SimpleBattle(description, enemyCount, enemyType); result.battleData.enemyCharacterData = selectedEnemy; return result; } /// /// Handle escape attempt for this specific combat event /// public EventResult HandleEscapeAttempt(TravelEventContext context) { if (!allowRunningAway) { Debug.LogWarning($"🚫 Running away is not allowed for this combat event: {eventName}"); return null; // Force battle } // Roll for escape success bool escapeSuccessful = Random.value <= runAwaySuccessChance; if (escapeSuccessful) { return CreateSuccessfulEscapeResult(); } else { return CreateFailedEscapeResult(context); } } /// /// Create result for successful escape /// private EventResult CreateSuccessfulEscapeResult() { string message = successfulRunAwayMessages[Random.Range(0, successfulRunAwayMessages.Length)]; return new EventResult(message) { shouldStopTravel = false, // Don't stop travel for successful escape startBattle = false, eventOccurred = true }; } /// /// Create result for failed escape /// private EventResult CreateFailedEscapeResult(TravelEventContext context) { string message = failedRunAwayMessages[Random.Range(0, failedRunAwayMessages.Length)]; message = message.Replace("{damage}", runAwayHealthPenalty.ToString()); var result = new EventResult(message) { shouldStopTravel = true, // Stop travel for failed escape startBattle = false, // Don't start battle, just apply penalty eventOccurred = true, healthChange = -runAwayHealthPenalty // Apply health penalty through EventResult system }; return result; } void OnEnable() { // Set default values for combat events eventType = EventType.Combat; rarity = EventRarity.Common; // Combat events are more likely in dangerous terrain forestChance = 0.8f; mountainChance = 0.9f; plainsChance = 0.4f; roadChance = 0.2f; // Much less likely on roads townChance = 0.1f; // Very unlikely in towns villageChance = 0.3f; } }