CombatEventIntegration.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. using UnityEngine;
  2. /// <summary>
  3. /// Integration manager that connects TravelEventSystem with CombatEventPopup
  4. /// Handles the choice between battle and escape when combat events occur
  5. /// </summary>
  6. public class CombatEventIntegration : MonoBehaviour
  7. {
  8. [Header("Combat Popup Integration")]
  9. [Tooltip("Use either the original CombatEventPopup or the new CombatEventPopupUXML")]
  10. public CombatEventPopup combatEventPopup; // Original popup (legacy)
  11. public CombatEventPopupUXML combatEventPopupUXML; // New UXML-based popup
  12. public GameObject combatPopupPrefab; // Optional: if popup component not already in scene
  13. // Component references
  14. private TravelEventSystem travelEventSystem;
  15. private TravelEventUI eventUI;
  16. private TeamTravelSystem teamTravelSystem;
  17. // Current combat state
  18. private bool isHandlingCombat = false;
  19. private CombatTravelEvent currentCombatEvent; // Store reference to the current combat event
  20. void Start()
  21. {
  22. // Find required components - try same GameObject first, then search scene
  23. travelEventSystem = GetComponent<TravelEventSystem>();
  24. if (travelEventSystem == null)
  25. travelEventSystem = FindFirstObjectByType<TravelEventSystem>();
  26. eventUI = FindFirstObjectByType<TravelEventUI>();
  27. teamTravelSystem = FindFirstObjectByType<TeamTravelSystem>();
  28. if (travelEventSystem == null)
  29. {
  30. Debug.LogError("❌ Combat Event Integration requires TravelEventSystem in the scene!");
  31. Debug.LogError(" Please ensure you have a GameObject with TravelEventSystem component.");
  32. enabled = false;
  33. return;
  34. }
  35. else if (GetComponent<TravelEventSystem>() == null)
  36. {
  37. Debug.LogWarning("⚠️ CombatEventIntegration is not on the same GameObject as TravelEventSystem.");
  38. Debug.LogWarning(" Consider moving it to the TravelEventSystem GameObject for better organization.");
  39. }
  40. // Try to find existing popup components first
  41. if (combatEventPopup == null)
  42. combatEventPopup = FindFirstObjectByType<CombatEventPopup>();
  43. if (combatEventPopupUXML == null)
  44. combatEventPopupUXML = FindFirstObjectByType<CombatEventPopupUXML>();
  45. // If no popup component found and we have a prefab, instantiate it
  46. if (combatEventPopup == null && combatEventPopupUXML == null && combatPopupPrefab != null)
  47. {
  48. GameObject popupInstance = Instantiate(combatPopupPrefab);
  49. combatEventPopup = popupInstance.GetComponent<CombatEventPopup>();
  50. combatEventPopupUXML = popupInstance.GetComponent<CombatEventPopupUXML>();
  51. if (combatEventPopup == null && combatEventPopupUXML == null)
  52. {
  53. Debug.LogError("❌ Combat popup prefab does not contain CombatEventPopup or CombatEventPopupUXML component!");
  54. enabled = false;
  55. return;
  56. }
  57. }
  58. if (combatEventPopup == null && combatEventPopupUXML == null)
  59. {
  60. Debug.LogError("❌ Combat Event Integration requires a CombatEventPopup or CombatEventPopupUXML component!");
  61. Debug.LogError(" Either add one of these components to a GameObject in the scene,");
  62. Debug.LogError(" or assign a prefab with one of these components to combatPopupPrefab field.");
  63. enabled = false;
  64. return;
  65. }
  66. // Setup combat popup callbacks
  67. if (combatEventPopup != null)
  68. combatEventPopup.OnCombatDecision += HandleCombatDecision;
  69. if (combatEventPopupUXML != null)
  70. combatEventPopupUXML.OnCombatDecision += HandleCombatDecision;
  71. }
  72. void OnDestroy()
  73. {
  74. if (combatEventPopup != null)
  75. combatEventPopup.OnCombatDecision -= HandleCombatDecision;
  76. if (combatEventPopupUXML != null)
  77. combatEventPopupUXML.OnCombatDecision -= HandleCombatDecision;
  78. }
  79. /// <summary>
  80. /// Call this method when a combat event occurs to show the popup
  81. /// This should be called from TravelEventTypes.cs in the ExecuteEvent method
  82. /// </summary>
  83. public void ShowCombatChoicePopup(BattleEventData battleData, TravelEventContext context, string eventDescription, CombatTravelEvent combatEvent = null)
  84. {
  85. if (isHandlingCombat || battleData == null)
  86. return;
  87. isHandlingCombat = true;
  88. currentCombatEvent = combatEvent; // Store reference to the original combat event
  89. // Store battle data for later use
  90. currentBattleData = battleData;
  91. currentContext = context;
  92. // Show combat popup - try UXML version first, then fallback to original
  93. if (combatEventPopupUXML != null)
  94. {
  95. combatEventPopupUXML.OnCombatDecision = HandleCombatDecision;
  96. combatEventPopupUXML.ShowCombatEncounter(battleData, context, eventDescription);
  97. }
  98. else if (combatEventPopup != null)
  99. {
  100. combatEventPopup.OnCombatDecision = HandleCombatDecision;
  101. combatEventPopup.ShowCombatEncounter(battleData, context, eventDescription);
  102. }
  103. else
  104. {
  105. Debug.LogError("No combat popup component assigned! Please assign either CombatEventPopup or CombatEventPopupUXML.");
  106. isHandlingCombat = false;
  107. }
  108. }
  109. // Store current battle data
  110. private BattleEventData currentBattleData;
  111. private TravelEventContext currentContext;
  112. /// <summary>
  113. /// Handle the player's combat decision from the popup
  114. /// </summary>
  115. private void HandleCombatDecision(bool chooseToAttack)
  116. {
  117. if (!isHandlingCombat || currentBattleData == null)
  118. return;
  119. isHandlingCombat = false;
  120. if (chooseToAttack)
  121. {
  122. HandleAttackChoice();
  123. }
  124. else
  125. {
  126. HandleRunAwayChoice();
  127. }
  128. // Clear stored data
  129. currentBattleData = null;
  130. currentContext = null;
  131. }
  132. /// <summary>
  133. /// Handle when player chooses to attack
  134. /// </summary>
  135. private void HandleAttackChoice()
  136. {
  137. // Create and return the battle result that will start the battle
  138. var battleResult = EventResult.SimpleBattle(
  139. $"Your party prepares for battle against {currentBattleData.enemyCount} {currentBattleData.enemyType}!",
  140. currentBattleData.enemyCount,
  141. currentBattleData.enemyType
  142. );
  143. // Copy over the enemy character data
  144. battleResult.battleData.enemyCharacterData = currentBattleData.enemyCharacterData;
  145. // Apply the battle result through the travel event system
  146. ApplyBattleResult(battleResult);
  147. }
  148. /// <summary>
  149. /// Handle when player chooses to run away
  150. /// </summary>
  151. private void HandleRunAwayChoice()
  152. {
  153. EventResult escapeResult = null;
  154. // Use the combat event's escape handling if available
  155. if (currentCombatEvent != null)
  156. {
  157. escapeResult = currentCombatEvent.HandleEscapeAttempt(currentContext);
  158. }
  159. else
  160. {
  161. Debug.LogWarning("⚠️ No combat event reference - using hardcoded fallback escape handling");
  162. // Hardcoded fallback values when no combat event is available
  163. const float fallbackSuccessChance = 0.75f;
  164. bool escapeSuccessful = Random.value <= fallbackSuccessChance;
  165. if (escapeSuccessful)
  166. {
  167. escapeResult = CreateFallbackSuccessfulEscape();
  168. }
  169. else
  170. {
  171. escapeResult = CreateFallbackFailedEscape();
  172. }
  173. }
  174. // Apply the escape result
  175. if (escapeResult != null)
  176. {
  177. ApplyBattleResult(escapeResult);
  178. }
  179. else
  180. {
  181. Debug.LogWarning("⚠️ Escape not allowed by combat event - forcing battle");
  182. HandleAttackChoice();
  183. }
  184. }
  185. /// <summary>
  186. /// Create fallback successful escape result when no combat event is available
  187. /// </summary>
  188. private EventResult CreateFallbackSuccessfulEscape()
  189. {
  190. string message = "Your party successfully escapes from the enemies!";
  191. return new EventResult(message)
  192. {
  193. shouldStopTravel = false,
  194. startBattle = false,
  195. eventOccurred = true,
  196. healthChange = 0
  197. };
  198. }
  199. /// <summary>
  200. /// Create fallback failed escape result when no combat event is available
  201. /// </summary>
  202. private EventResult CreateFallbackFailedEscape()
  203. {
  204. const int fallbackHealthPenalty = 5; // Hardcoded fallback value
  205. string message = $"The enemies catch up to your party! You take {fallbackHealthPenalty} damage while trying to escape.";
  206. return new EventResult(message)
  207. {
  208. shouldStopTravel = true,
  209. startBattle = false,
  210. eventOccurred = true,
  211. healthChange = -fallbackHealthPenalty
  212. };
  213. } /// <summary>
  214. /// Apply battle result through the travel event system
  215. /// </summary>
  216. private void ApplyBattleResult(EventResult result)
  217. {
  218. // Apply resource changes
  219. if (result.healthChange != 0)
  220. {
  221. Debug.Log($"❤️ Health changed by {result.healthChange}");
  222. // TODO: Actually apply health changes to party
  223. }
  224. if (result.goldChange != 0)
  225. {
  226. Debug.Log($"💰 Gold changed by {result.goldChange}");
  227. // TODO: Actually apply gold changes to party
  228. }
  229. // Handle travel stopping
  230. if (result.shouldStopTravel && teamTravelSystem != null)
  231. {
  232. teamTravelSystem.CancelJourney();
  233. }
  234. // Handle battle start
  235. if (result.startBattle)
  236. {
  237. // Use the new CombatSceneManager to handle battle transition
  238. MonoBehaviour combatSceneManager = FindCombatSceneManager();
  239. if (combatSceneManager != null)
  240. {
  241. // Use reflection to call StartCombatEncounter method
  242. var method = combatSceneManager.GetType().GetMethod("StartCombatEncounter");
  243. if (method != null)
  244. {
  245. method.Invoke(combatSceneManager, new object[] { result.battleData, currentContext });
  246. }
  247. }
  248. }
  249. }
  250. /// <summary>
  251. /// Check if the system is currently handling a combat choice
  252. /// </summary>
  253. public bool IsHandlingCombat => isHandlingCombat;
  254. /// <summary>
  255. /// Cancel current combat handling (for cleanup)
  256. /// </summary>
  257. public void CancelCombatHandling()
  258. {
  259. if (isHandlingCombat)
  260. {
  261. isHandlingCombat = false;
  262. currentBattleData = null;
  263. currentContext = null;
  264. if (combatEventPopup != null)
  265. combatEventPopup.ForceClose();
  266. }
  267. }
  268. /// <summary>
  269. /// Find CombatSceneManager using reflection to avoid compilation issues
  270. /// </summary>
  271. private MonoBehaviour FindCombatSceneManager()
  272. {
  273. // First try to find it by component type name
  274. var allComponents = FindObjectsByType<MonoBehaviour>(FindObjectsSortMode.None);
  275. var combatSceneManager = System.Array.Find(allComponents,
  276. comp => comp.GetType().Name == "CombatSceneManager");
  277. return combatSceneManager;
  278. }
  279. }