TravelUIController.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. using UnityEngine;
  2. using UnityEngine.UIElements;
  3. using System.Linq;
  4. /// <summary>
  5. /// Controls the travel UI and integrates with TeamTravelSystem for route planning and execution.
  6. /// Uses the existing travel UI elements from MapWithTravelUI.uxml
  7. /// </summary>
  8. [RequireComponent(typeof(UIDocument))]
  9. public class TravelUIController : MonoBehaviour
  10. {
  11. [Header("UI References")]
  12. public UIDocument uiDocument;
  13. [Header("Settings")]
  14. public bool showDebugLogs = false;
  15. // UI Elements
  16. private VisualElement travelContainer;
  17. private VisualElement travelPanel;
  18. private Button closeButton;
  19. private Label distanceLabel;
  20. private Label timeLabel;
  21. private Label specialCostsLabel;
  22. private Button startTravelButton;
  23. // Route selection (if available)
  24. private VisualElement routeOptionsContainer;
  25. private RadioButtonGroup routeSelection;
  26. // System references
  27. private TeamTravelSystem travelSystem;
  28. private SimpleTeamPlacement teamPlacement;
  29. // Current state
  30. private TravelRoute selectedRoute;
  31. private bool isUIVisible = false;
  32. void Awake()
  33. {
  34. if (uiDocument == null)
  35. uiDocument = GetComponent<UIDocument>();
  36. }
  37. void Start()
  38. {
  39. // Find system references
  40. travelSystem = TeamTravelSystem.Instance;
  41. teamPlacement = SimpleTeamPlacement.Instance;
  42. if (travelSystem == null)
  43. {
  44. Debug.LogError("❌ TeamTravelSystem not found! TravelUIController requires it.");
  45. return;
  46. }
  47. // Setup UI
  48. SetupUIElements();
  49. SetupEventHandlers();
  50. // Hide UI initially
  51. HideTravelUI();
  52. }
  53. void Update()
  54. {
  55. // Monitor for travel planning
  56. if (travelSystem != null && travelSystem.GetPlannedDestination().HasValue && !isUIVisible)
  57. {
  58. ShowTravelUI();
  59. }
  60. else if (travelSystem != null && !travelSystem.GetPlannedDestination().HasValue && isUIVisible)
  61. {
  62. HideTravelUI();
  63. }
  64. }
  65. /// <summary>
  66. /// Sets up references to UI elements
  67. /// </summary>
  68. private void SetupUIElements()
  69. {
  70. if (uiDocument?.rootVisualElement == null)
  71. {
  72. Debug.LogError("❌ UIDocument root not available");
  73. return;
  74. }
  75. var root = uiDocument.rootVisualElement;
  76. // Find main UI elements
  77. travelContainer = root.Q("TravelContainer");
  78. travelPanel = root.Q("TravelPanel");
  79. closeButton = root.Q<Button>("CloseButton");
  80. distanceLabel = root.Q<Label>("DistanceLabel");
  81. timeLabel = root.Q<Label>("TimeLabel");
  82. specialCostsLabel = root.Q<Label>("SpecialCostsLabel");
  83. startTravelButton = root.Q<Button>("StartTravelButton");
  84. // Optional route selection elements
  85. routeOptionsContainer = root.Q("RouteOptions");
  86. routeSelection = root.Q<RadioButtonGroup>("RouteSelection");
  87. }
  88. /// <summary>
  89. /// Sets up event handlers for UI interactions
  90. /// </summary>
  91. private void SetupEventHandlers()
  92. {
  93. // Close button
  94. if (closeButton != null)
  95. {
  96. closeButton.clicked += OnCloseButtonClicked;
  97. }
  98. // Start travel button
  99. if (startTravelButton != null)
  100. {
  101. startTravelButton.clicked += OnStartTravelClicked;
  102. }
  103. // Route selection (if available)
  104. if (routeSelection != null)
  105. {
  106. routeSelection.RegisterValueChangedCallback(OnRouteSelectionChanged);
  107. }
  108. if (showDebugLogs)
  109. {
  110. }
  111. }
  112. /// <summary>
  113. /// Shows the travel UI and updates it with current route information
  114. /// </summary>
  115. public void ShowTravelUI()
  116. {
  117. if (travelContainer == null) return;
  118. travelContainer.style.display = DisplayStyle.Flex;
  119. // Ensure the travel container blocks mouse clicks
  120. travelContainer.pickingMode = PickingMode.Position;
  121. // Add background overlay to block clicks if travel panel exists
  122. if (travelPanel != null)
  123. {
  124. travelPanel.pickingMode = PickingMode.Position;
  125. }
  126. isUIVisible = true;
  127. // Update UI with current travel information
  128. UpdateTravelInformation();
  129. if (showDebugLogs)
  130. {
  131. Debug.Log("✈️ Travel UI shown - map clicks should be blocked");
  132. }
  133. }
  134. /// <summary>
  135. /// Hides the travel UI
  136. /// </summary>
  137. public void HideTravelUI()
  138. {
  139. if (travelContainer == null) return;
  140. travelContainer.style.display = DisplayStyle.None;
  141. // Reset picking mode to allow map clicks
  142. travelContainer.pickingMode = PickingMode.Ignore;
  143. if (travelPanel != null)
  144. {
  145. travelPanel.pickingMode = PickingMode.Ignore;
  146. }
  147. isUIVisible = false;
  148. if (showDebugLogs)
  149. {
  150. Debug.Log("✈️ Travel UI hidden - map clicks should be enabled");
  151. }
  152. }
  153. /// <summary>
  154. /// Updates the travel information display with current route data
  155. /// </summary>
  156. private void UpdateTravelInformation()
  157. {
  158. if (travelSystem == null) return;
  159. var routes = travelSystem.GetAvailableRoutes();
  160. if (routes.Count == 0)
  161. {
  162. ShowNoRoutesMessage();
  163. return;
  164. }
  165. // Select the best route by default (lowest cost)
  166. selectedRoute = routes.OrderBy(r => r.totalCost).First();
  167. // Update basic information
  168. UpdateBasicRouteInfo(selectedRoute);
  169. // Update route options if available
  170. UpdateRouteOptions(routes);
  171. // Update start button
  172. UpdateStartButton(selectedRoute);
  173. }
  174. /// <summary>
  175. /// Updates the basic route information display
  176. /// </summary>
  177. private void UpdateBasicRouteInfo(TravelRoute route)
  178. {
  179. if (distanceLabel != null)
  180. {
  181. distanceLabel.text = $"Distance: {route.totalDistance:F1} leagues";
  182. }
  183. if (timeLabel != null)
  184. {
  185. distanceLabel.text = $"Travel Time: {route.estimatedTime:F1} hours";
  186. }
  187. if (specialCostsLabel != null)
  188. {
  189. if (route.specialCosts.Count > 0)
  190. {
  191. var costStrings = route.specialCosts.Select(kvp => $"{kvp.Value} {kvp.Key}");
  192. specialCostsLabel.text = $"Special Costs: {string.Join(", ", costStrings)}";
  193. specialCostsLabel.style.color = new StyleColor(Color.yellow);
  194. }
  195. else
  196. {
  197. specialCostsLabel.text = "Special Costs: None";
  198. specialCostsLabel.style.color = new StyleColor(Color.white);
  199. }
  200. }
  201. }
  202. /// <summary>
  203. /// Updates route selection options if multiple routes are available
  204. /// </summary>
  205. private void UpdateRouteOptions(System.Collections.Generic.List<TravelRoute> routes)
  206. {
  207. if (routeOptionsContainer == null || routes.Count <= 1)
  208. {
  209. // Hide route options if not available or only one route
  210. if (routeOptionsContainer != null)
  211. routeOptionsContainer.style.display = DisplayStyle.None;
  212. return;
  213. }
  214. routeOptionsContainer.style.display = DisplayStyle.Flex;
  215. // TODO: Implement route selection UI if needed
  216. // For now, we'll just use the best route automatically
  217. }
  218. /// <summary>
  219. /// Updates the start travel button with appropriate text and state
  220. /// </summary>
  221. private void UpdateStartButton(TravelRoute route)
  222. {
  223. if (startTravelButton == null) return;
  224. // Check if player can afford the route
  225. bool canAfford = CanAffordRoute(route);
  226. startTravelButton.SetEnabled(canAfford);
  227. if (canAfford)
  228. {
  229. if (route.specialCosts.Count > 0)
  230. {
  231. var totalCost = route.specialCosts.Values.Sum();
  232. startTravelButton.text = $"Start Journey ({totalCost} gold)";
  233. }
  234. else
  235. {
  236. startTravelButton.text = "Start Journey (Free)";
  237. }
  238. }
  239. else
  240. {
  241. startTravelButton.text = "Insufficient Resources";
  242. }
  243. }
  244. /// <summary>
  245. /// Checks if the player can afford the selected route
  246. /// </summary>
  247. private bool CanAffordRoute(TravelRoute route)
  248. {
  249. // TODO: Implement player resource checking
  250. // For now, assume player can always afford free routes
  251. return route.specialCosts.Count == 0 || route.specialCosts.Values.Sum() <= 100; // Placeholder
  252. }
  253. /// <summary>
  254. /// Shows a message when no routes are available
  255. /// </summary>
  256. private void ShowNoRoutesMessage()
  257. {
  258. if (distanceLabel != null)
  259. distanceLabel.text = "Distance: No route available";
  260. if (timeLabel != null)
  261. timeLabel.text = "Travel Time: --";
  262. if (specialCostsLabel != null)
  263. specialCostsLabel.text = "Cannot reach destination";
  264. if (startTravelButton != null)
  265. {
  266. startTravelButton.text = "No Route Available";
  267. startTravelButton.SetEnabled(false);
  268. }
  269. }
  270. /// <summary>
  271. /// Event handler for close button
  272. /// </summary>
  273. private void OnCloseButtonClicked()
  274. {
  275. if (travelSystem != null)
  276. {
  277. travelSystem.CancelTravelPlanning();
  278. }
  279. HideTravelUI();
  280. if (showDebugLogs)
  281. {
  282. }
  283. }
  284. /// <summary>
  285. /// Event handler for start travel button
  286. /// </summary>
  287. private void OnStartTravelClicked()
  288. {
  289. if (selectedRoute == null || travelSystem == null)
  290. {
  291. Debug.LogWarning("Cannot start travel: no route selected or travel system unavailable");
  292. return;
  293. }
  294. if (!CanAffordRoute(selectedRoute))
  295. {
  296. Debug.LogWarning("Cannot start travel: insufficient resources");
  297. return;
  298. }
  299. // Start the travel
  300. travelSystem.StartTravel(selectedRoute);
  301. // Hide UI
  302. HideTravelUI();
  303. if (showDebugLogs)
  304. {
  305. }
  306. }
  307. /// <summary>
  308. /// Event handler for route selection changes
  309. /// </summary>
  310. private void OnRouteSelectionChanged(ChangeEvent<int> evt)
  311. {
  312. if (travelSystem == null) return;
  313. var routes = travelSystem.GetAvailableRoutes();
  314. if (evt.newValue >= 0 && evt.newValue < routes.Count)
  315. {
  316. selectedRoute = routes[evt.newValue];
  317. UpdateBasicRouteInfo(selectedRoute);
  318. UpdateStartButton(selectedRoute);
  319. if (showDebugLogs)
  320. {
  321. }
  322. }
  323. }
  324. /// <summary>
  325. /// Public methods for external control
  326. /// </summary>
  327. public bool IsUIVisible() => isUIVisible;
  328. public TravelRoute GetSelectedRoute() => selectedRoute;
  329. /// <summary>
  330. /// Context menu methods for debugging
  331. /// </summary>
  332. [ContextMenu("Show Travel UI (Test)")]
  333. public void TestShowTravelUI()
  334. {
  335. ShowTravelUI();
  336. }
  337. [ContextMenu("Hide Travel UI (Test)")]
  338. public void TestHideTravelUI()
  339. {
  340. HideTravelUI();
  341. }
  342. }