TravelUIController.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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. isUIVisible = true;
  120. // Update UI with current travel information
  121. UpdateTravelInformation();
  122. if (showDebugLogs)
  123. {
  124. }
  125. }
  126. /// <summary>
  127. /// Hides the travel UI
  128. /// </summary>
  129. public void HideTravelUI()
  130. {
  131. if (travelContainer == null) return;
  132. travelContainer.style.display = DisplayStyle.None;
  133. isUIVisible = false;
  134. if (showDebugLogs)
  135. {
  136. }
  137. }
  138. /// <summary>
  139. /// Updates the travel information display with current route data
  140. /// </summary>
  141. private void UpdateTravelInformation()
  142. {
  143. if (travelSystem == null) return;
  144. var routes = travelSystem.GetAvailableRoutes();
  145. if (routes.Count == 0)
  146. {
  147. ShowNoRoutesMessage();
  148. return;
  149. }
  150. // Select the best route by default (lowest cost)
  151. selectedRoute = routes.OrderBy(r => r.totalCost).First();
  152. // Update basic information
  153. UpdateBasicRouteInfo(selectedRoute);
  154. // Update route options if available
  155. UpdateRouteOptions(routes);
  156. // Update start button
  157. UpdateStartButton(selectedRoute);
  158. }
  159. /// <summary>
  160. /// Updates the basic route information display
  161. /// </summary>
  162. private void UpdateBasicRouteInfo(TravelRoute route)
  163. {
  164. if (distanceLabel != null)
  165. {
  166. distanceLabel.text = $"Distance: {route.totalDistance:F1} leagues";
  167. }
  168. if (timeLabel != null)
  169. {
  170. distanceLabel.text = $"Travel Time: {route.estimatedTime:F1} hours";
  171. }
  172. if (specialCostsLabel != null)
  173. {
  174. if (route.specialCosts.Count > 0)
  175. {
  176. var costStrings = route.specialCosts.Select(kvp => $"{kvp.Value} {kvp.Key}");
  177. specialCostsLabel.text = $"Special Costs: {string.Join(", ", costStrings)}";
  178. specialCostsLabel.style.color = new StyleColor(Color.yellow);
  179. }
  180. else
  181. {
  182. specialCostsLabel.text = "Special Costs: None";
  183. specialCostsLabel.style.color = new StyleColor(Color.white);
  184. }
  185. }
  186. }
  187. /// <summary>
  188. /// Updates route selection options if multiple routes are available
  189. /// </summary>
  190. private void UpdateRouteOptions(System.Collections.Generic.List<TravelRoute> routes)
  191. {
  192. if (routeOptionsContainer == null || routes.Count <= 1)
  193. {
  194. // Hide route options if not available or only one route
  195. if (routeOptionsContainer != null)
  196. routeOptionsContainer.style.display = DisplayStyle.None;
  197. return;
  198. }
  199. routeOptionsContainer.style.display = DisplayStyle.Flex;
  200. // TODO: Implement route selection UI if needed
  201. // For now, we'll just use the best route automatically
  202. }
  203. /// <summary>
  204. /// Updates the start travel button with appropriate text and state
  205. /// </summary>
  206. private void UpdateStartButton(TravelRoute route)
  207. {
  208. if (startTravelButton == null) return;
  209. // Check if player can afford the route
  210. bool canAfford = CanAffordRoute(route);
  211. startTravelButton.SetEnabled(canAfford);
  212. if (canAfford)
  213. {
  214. if (route.specialCosts.Count > 0)
  215. {
  216. var totalCost = route.specialCosts.Values.Sum();
  217. startTravelButton.text = $"Start Journey ({totalCost} gold)";
  218. }
  219. else
  220. {
  221. startTravelButton.text = "Start Journey (Free)";
  222. }
  223. }
  224. else
  225. {
  226. startTravelButton.text = "Insufficient Resources";
  227. }
  228. }
  229. /// <summary>
  230. /// Checks if the player can afford the selected route
  231. /// </summary>
  232. private bool CanAffordRoute(TravelRoute route)
  233. {
  234. // TODO: Implement player resource checking
  235. // For now, assume player can always afford free routes
  236. return route.specialCosts.Count == 0 || route.specialCosts.Values.Sum() <= 100; // Placeholder
  237. }
  238. /// <summary>
  239. /// Shows a message when no routes are available
  240. /// </summary>
  241. private void ShowNoRoutesMessage()
  242. {
  243. if (distanceLabel != null)
  244. distanceLabel.text = "Distance: No route available";
  245. if (timeLabel != null)
  246. timeLabel.text = "Travel Time: --";
  247. if (specialCostsLabel != null)
  248. specialCostsLabel.text = "Cannot reach destination";
  249. if (startTravelButton != null)
  250. {
  251. startTravelButton.text = "No Route Available";
  252. startTravelButton.SetEnabled(false);
  253. }
  254. }
  255. /// <summary>
  256. /// Event handler for close button
  257. /// </summary>
  258. private void OnCloseButtonClicked()
  259. {
  260. if (travelSystem != null)
  261. {
  262. travelSystem.CancelTravelPlanning();
  263. }
  264. HideTravelUI();
  265. if (showDebugLogs)
  266. {
  267. }
  268. }
  269. /// <summary>
  270. /// Event handler for start travel button
  271. /// </summary>
  272. private void OnStartTravelClicked()
  273. {
  274. if (selectedRoute == null || travelSystem == null)
  275. {
  276. Debug.LogWarning("Cannot start travel: no route selected or travel system unavailable");
  277. return;
  278. }
  279. if (!CanAffordRoute(selectedRoute))
  280. {
  281. Debug.LogWarning("Cannot start travel: insufficient resources");
  282. return;
  283. }
  284. // Start the travel
  285. travelSystem.StartTravel(selectedRoute);
  286. // Hide UI
  287. HideTravelUI();
  288. if (showDebugLogs)
  289. {
  290. }
  291. }
  292. /// <summary>
  293. /// Event handler for route selection changes
  294. /// </summary>
  295. private void OnRouteSelectionChanged(ChangeEvent<int> evt)
  296. {
  297. if (travelSystem == null) return;
  298. var routes = travelSystem.GetAvailableRoutes();
  299. if (evt.newValue >= 0 && evt.newValue < routes.Count)
  300. {
  301. selectedRoute = routes[evt.newValue];
  302. UpdateBasicRouteInfo(selectedRoute);
  303. UpdateStartButton(selectedRoute);
  304. if (showDebugLogs)
  305. {
  306. }
  307. }
  308. }
  309. /// <summary>
  310. /// Public methods for external control
  311. /// </summary>
  312. public bool IsUIVisible() => isUIVisible;
  313. public TravelRoute GetSelectedRoute() => selectedRoute;
  314. /// <summary>
  315. /// Context menu methods for debugging
  316. /// </summary>
  317. [ContextMenu("Show Travel UI (Test)")]
  318. public void TestShowTravelUI()
  319. {
  320. ShowTravelUI();
  321. }
  322. [ContextMenu("Hide Travel UI (Test)")]
  323. public void TestHideTravelUI()
  324. {
  325. HideTravelUI();
  326. }
  327. }