| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041 |
- using UnityEngine;
- using UnityEngine.UIElements;
- using System.Collections.Generic;
- using System.Linq;
- /// <summary>
- /// UI Controller for the Travel System with route selection and comparison
- /// </summary>
- public class TravelUI : MonoBehaviour
- {
- [Header("UI Document")]
- public UIDocument uiDocument;
- [Header("UI Files")]
- public VisualTreeAsset travelUIAsset;
- public StyleSheet travelUIStyleSheet;
- // UI Elements
- private VisualElement travelContainer;
- private VisualElement travelPanel;
- private VisualElement clickBlocker;
- private Label distanceLabel;
- private Label timeLabel;
- private Label specialCostsLabel;
- private Button startTravelButton;
- private Button cancelTravelButton;
- private VisualElement routeList;
- // Travel data
- private Vector2Int currentDestination;
- private List<TravelRoute> availableRoutes = new List<TravelRoute>();
- private TravelRoute selectedRoute;
- // State
- private bool isUIVisible = false;
- void Awake()
- {
- // Find UI Document if not assigned
- if (uiDocument == null)
- {
- uiDocument = GetComponent<UIDocument>();
- }
- // Load UXML asset from Resources if not assigned
- if (travelUIAsset == null)
- {
- travelUIAsset = Resources.Load<VisualTreeAsset>("UI/Map/TravelUI");
- if (travelUIAsset == null)
- {
- // Try alternative path
- travelUIAsset = Resources.Load<VisualTreeAsset>("TravelUI");
- }
- }
- // Load USS style sheet if not assigned
- if (travelUIStyleSheet == null)
- {
- travelUIStyleSheet = Resources.Load<StyleSheet>("UI/Map/TravelUI");
- if (travelUIStyleSheet == null)
- {
- // Try alternative path
- travelUIStyleSheet = Resources.Load<StyleSheet>("TravelUI");
- }
- }
- }
- void Start()
- {
- SetupUI();
- }
- void SetupUI()
- {
- if (uiDocument == null)
- {
- Debug.LogError("TravelUI: UIDocument not found!");
- return;
- }
- var root = uiDocument.rootVisualElement;
- // Load and instantiate the UXML if we have the asset
- if (travelUIAsset != null)
- {
- // Clear existing content
- root.Clear();
- // Instantiate from UXML
- travelUIAsset.CloneTree(root);
- // Add style sheet
- if (travelUIStyleSheet != null)
- {
- root.styleSheets.Add(travelUIStyleSheet);
- }
- else
- {
- Debug.LogWarning("TravelUI: No style sheet found");
- }
- }
- else
- {
- Debug.LogWarning("TravelUI: No UXML asset found");
- }
- // Find UI elements
- travelContainer = root.Q<VisualElement>("TravelContainer");
- travelPanel = root.Q<VisualElement>("TravelPanel");
- clickBlocker = root.Q<VisualElement>("ClickBlocker");
- distanceLabel = root.Q<Label>("DistanceLabel");
- timeLabel = root.Q<Label>("TimeLabel");
- specialCostsLabel = root.Q<Label>("SpecialCostsLabel");
- startTravelButton = root.Q<Button>("StartTravelButton");
- cancelTravelButton = root.Q<Button>("CancelTravelButton");
- // Find draggable header and close button
- var travelHeader = root.Q<VisualElement>("TravelHeader");
- var closeButton = root.Q<Button>("CloseButton");
- // Find or create route list container
- routeList = root.Q<VisualElement>("RouteList");
- if (routeList == null)
- {
- Debug.Log("🔨 TravelUI: RouteList not found, creating it...");
- // Create route list if it doesn't exist
- var routeOptions = root.Q<VisualElement>("RouteOptions");
- if (routeOptions != null)
- {
- routeList = new VisualElement();
- routeList.name = "RouteList";
- routeList.AddToClassList("route-list");
- routeOptions.Add(routeList);
- Debug.Log("✅ TravelUI: RouteList created and added to RouteOptions");
- }
- else
- {
- Debug.LogWarning("⚠️ TravelUI: RouteOptions container not found, cannot create RouteList");
- }
- }
- else
- {
- Debug.Log("RouteList found");
- }
- // Setup dragging functionality
- if (travelHeader != null && travelPanel != null)
- {
- SetupDragFunctionality(travelHeader, travelPanel);
- }
- // Setup close button
- if (closeButton != null)
- {
- closeButton.clicked += OnCancelTravelClicked;
- }
- // Setup button callbacks
- if (startTravelButton != null)
- {
- startTravelButton.clicked += OnStartTravelClicked;
- }
- if (cancelTravelButton != null)
- {
- cancelTravelButton.clicked += OnCancelTravelClicked;
- }
- // Setup click blocking on the invisible overlay
- if (clickBlocker != null)
- {
- clickBlocker.RegisterCallback<ClickEvent>(evt =>
- {
- Debug.Log("�️ TravelUI: Click blocked by overlay - stopping propagation");
- evt.StopPropagation(); // Prevent clicks from passing through to the map
- });
- }
- else
- {
- Debug.LogWarning("⚠️ TravelUI: ClickBlocker element not found!");
- }
- // Hide UI initially
- HideTravelPanel();
- Debug.Log("TravelUI initialized successfully");
- }
- /// <summary>
- /// DEBUG: Force show the TravelUI for testing
- /// </summary>
- [ContextMenu("DEBUG: Force Show TravelUI")]
- public void DebugForceShowTravelUI()
- {
- Debug.Log("🧪 TravelUI: DEBUG Force showing TravelUI...");
- // CHECK FOR DUPLICATE TEAM MARKERS
- var allTeamMarkers = GameObject.FindObjectsByType<GameObject>(FindObjectsSortMode.None).Where(g => g.name == "TeamMarker").ToArray();
- Debug.Log($"🔍 Found {allTeamMarkers.Length} TeamMarker objects:");
- for (int i = 0; i < allTeamMarkers.Length; i++)
- {
- var marker = allTeamMarkers[i];
- bool hasSphere = marker.GetComponentInChildren<Transform>().name.Contains("Sphere");
- Debug.Log($" {i + 1}. {marker.name} at {marker.transform.position} - Has Sphere: {hasSphere}");
- }
- // Prevent multiple instances
- if (isUIVisible)
- {
- Debug.Log("⚠️ TravelUI: Already visible, ignoring duplicate show request");
- return;
- }
- // Create some dummy routes for testing with proper initialization
- var dummyRoutes = new List<TravelRoute>
- {
- new TravelRoute
- {
- routeType = RouteType.RoadPreferred,
- estimatedTime = 10.5f,
- totalDistance = 25.0f,
- totalCost = 50,
- specialCosts = new Dictionary<string, int> { { "Ferry", 10 } },
- path = new List<Vector2Int> { new Vector2Int(50, 50), new Vector2Int(75, 75), new Vector2Int(100, 100) }
- },
- new TravelRoute
- {
- routeType = RouteType.Standard,
- estimatedTime = 12.0f,
- totalDistance = 22.0f,
- totalCost = 45,
- specialCosts = new Dictionary<string, int>(),
- path = new List<Vector2Int> { new Vector2Int(50, 50), new Vector2Int(100, 100) }
- },
- new TravelRoute
- {
- routeType = RouteType.Special,
- estimatedTime = 8.0f,
- totalDistance = 30.0f,
- totalCost = 35,
- specialCosts = new Dictionary<string, int> { { "Tunnel Torch", 2 }, { "Mountain Guide", 15 } },
- path = new List<Vector2Int> { new Vector2Int(50, 50), new Vector2Int(60, 80), new Vector2Int(100, 100) }
- }
- };
- ShowTravelUI(new Vector2Int(100, 100), dummyRoutes);
- }
- /// <summary>
- /// Sets up click blocking for the travel UI to prevent click-through
- /// </summary>
- private void SetupClickBlocking()
- {
- // The click blocker overlay handles blocking all clicks that aren't on UI elements
- // This is already set up in SetupUI() via the clickBlocker element
-
- Debug.Log("🔧 TravelUI: Click blocking active - overlay will prevent map clicks");
- }
- /// <summary>
- /// Shows the travel UI with route options - UPDATED
- /// </summary>
- public void ShowTravelUI(Vector2Int destination, List<TravelRoute> routes)
- {
- Debug.Log($"🚀 TravelUI: ShowTravelUI called with destination {destination} and {routes.Count} routes");
- // If UI is already visible, update with new routes instead of ignoring
- if (isUIVisible)
- {
- Debug.Log("🔄 TravelUI: Already visible, updating with new routes");
- UpdateRoutesAndRefreshUI(destination, routes);
- return;
- }
- if (travelContainer == null)
- {
- Debug.LogWarning("⚠️ TravelUI: Container not found, attempting to setup UI");
- SetupUI();
- if (travelContainer == null)
- {
- Debug.LogError("❌ TravelUI: Failed to setup UI - travelContainer still null");
- return;
- }
- Debug.Log("✅ TravelUI: Successfully setup UI after retry");
- }
- currentDestination = destination;
- availableRoutes = new List<TravelRoute>(routes);
- // Select the fastest route by default
- if (availableRoutes.Count > 0)
- {
- selectedRoute = availableRoutes.OrderBy(r => r.estimatedTime).First();
- }
- else
- {
- Debug.LogWarning("TravelUI: No routes available!");
- }
- // Update UI content
- UpdateTravelInfo();
- PopulateRouteList();
- // Show the UI
- travelContainer.style.display = DisplayStyle.Flex;
- isUIVisible = true;
- // Ensure travel UI doesn't overlap with team overview panel
- EnsureNoTeamOverviewOverlap();
- // Set up click blocking when showing the UI
- SetupClickBlocking();
- // Force a layout update to ensure everything is positioned correctly
- travelContainer.MarkDirtyRepaint();
- Debug.Log($"📋 TravelUI: Showing UI with {routes.Count} routes to {destination}");
- Debug.Log($"🔒 TravelUI: UI panel now blocks clicks within its bounds - isUIVisible: {isUIVisible}");
- Debug.Log($"🔍 TravelUI: Container display style: {travelContainer.style.display}");
- }
- /// <summary>
- /// Hides the travel panel - UPDATED
- /// </summary>
- public void HideTravelPanel()
- {
- if (travelContainer != null)
- {
- travelContainer.style.display = DisplayStyle.None;
- }
- isUIVisible = false;
- // Clear route visualization when hiding
- var travelSystem = FindFirstObjectByType<TeamTravelSystem>();
- if (travelSystem != null)
- {
- try
- {
- // Try to clear route visualization
- var clearMethod = travelSystem.GetType().GetMethod("ClearRouteVisualization");
- if (clearMethod != null)
- {
- clearMethod.Invoke(travelSystem, null);
- Debug.Log("✅ TravelUI: Cleared route visualization");
- }
- }
- catch (System.Exception e)
- {
- Debug.LogWarning($"⚠️ TravelUI: Failed to clear route visualization: {e.Message}");
- }
- }
- Debug.Log("👻 TravelUI: Panel hidden");
- Debug.Log($"🔓 TravelUI: Map clicks now enabled outside panel - isUIVisible: {isUIVisible}");
- }
- /// <summary>
- /// Updates the UI with new routes and forces a complete refresh
- /// </summary>
- public void UpdateRoutesAndRefreshUI(Vector2Int destination, List<TravelRoute> routes)
- {
- Debug.Log($"🔄 TravelUI: UpdateRoutesAndRefreshUI called with {routes.Count} routes");
- // Update the route data
- currentDestination = destination;
- availableRoutes = new List<TravelRoute>(routes);
- // Select the fastest route by default
- if (availableRoutes.Count > 0)
- {
- selectedRoute = availableRoutes.OrderBy(r => r.estimatedTime).First();
- Debug.Log($"🎯 TravelUI: Updated to new default route: {selectedRoute.routeType}");
- }
- else
- {
- Debug.LogWarning("⚠️ TravelUI: No routes available in update!");
- selectedRoute = null;
- }
- // Force a complete UI refresh
- Debug.Log("🔄 TravelUI: Updating travel info after route refresh...");
- UpdateTravelInfo();
- Debug.Log("📋 TravelUI: Repopulating route list...");
- PopulateRouteList();
- // Force the entire container to repaint
- if (travelContainer != null)
- {
- travelContainer.MarkDirtyRepaint();
- Debug.Log("🎨 TravelUI: Forced container repaint after route update");
- }
- Debug.Log($"✅ TravelUI: UI refreshed with {routes.Count} updated routes");
- }
- /// <summary>
- /// DEBUG: Force hide the TravelUI for testing
- /// </summary>
- [ContextMenu("DEBUG: Force Hide TravelUI")]
- public void DebugForceHideTravelUI()
- {
- Debug.Log("🧪 TravelUI: DEBUG Force hiding TravelUI...");
- // Hide UI
- HideTravelPanel();
- }
- /// <summary>
- /// DEBUG: Test manual label updates
- /// </summary>
- [ContextMenu("DEBUG: Test Label Updates")]
- public void DebugTestLabelUpdates()
- {
- Debug.Log("🧪 TravelUI: DEBUG Testing label updates...");
- if (distanceLabel != null)
- {
- distanceLabel.text = $"Distance: {UnityEngine.Random.Range(10f, 100f):F1} leagues [DEBUG]";
- distanceLabel.MarkDirtyRepaint(); // Force UI refresh
- Debug.Log($"✅ TravelUI: Distance updated to: {distanceLabel.text}");
- }
- else
- {
- Debug.LogError("❌ TravelUI: distanceLabel is null!");
- }
- if (timeLabel != null)
- {
- timeLabel.text = $"Travel Time: {UnityEngine.Random.Range(5f, 50f):F1} hours [DEBUG]";
- timeLabel.MarkDirtyRepaint(); // Force UI refresh
- Debug.Log($"✅ TravelUI: Time updated to: {timeLabel.text}");
- }
- else
- {
- Debug.LogError("❌ TravelUI: timeLabel is null!");
- }
- if (specialCostsLabel != null)
- {
- specialCostsLabel.text = $"Special Costs: {UnityEngine.Random.Range(0, 100)} gold [DEBUG]";
- specialCostsLabel.MarkDirtyRepaint(); // Force UI refresh
- Debug.Log($"✅ TravelUI: Special costs updated to: {specialCostsLabel.text}");
- }
- else
- {
- Debug.LogError("❌ TravelUI: specialCostsLabel is null!");
- }
- // Force the entire container to refresh
- if (travelContainer != null)
- {
- travelContainer.MarkDirtyRepaint();
- }
- }
- /// <summary>
- /// DEBUG: Test route selection programmatically
- /// </summary>
- [ContextMenu("DEBUG: Test Route Selection")]
- public void DebugTestRouteSelection()
- {
- Debug.Log("🧪 TravelUI: DEBUG Testing route selection...");
- if (availableRoutes == null || availableRoutes.Count == 0)
- {
- Debug.LogError("❌ TravelUI: No available routes for testing!");
- return;
- }
- // Try to select each route programmatically
- for (int i = 0; i < availableRoutes.Count; i++)
- {
- var route = availableRoutes[i];
- Debug.Log($"🔄 TravelUI: Testing route {i + 1}: {route.routeType}");
- // Find the corresponding UI element
- var routeOptions = routeList.Children().ToList();
- if (i < routeOptions.Count)
- {
- var routeElement = routeOptions[i];
- Debug.Log($"🎯 TravelUI: Simulating click on route element {i}");
- SelectRoute(route, routeElement);
- // Wait a bit and show results
- Debug.Log($"📊 TravelUI: After selecting {route.routeType}:");
- Debug.Log($" Distance: {distanceLabel?.text ?? "NULL"}");
- Debug.Log($" Time: {timeLabel?.text ?? "NULL"}");
- Debug.Log($" Special: {specialCostsLabel?.text ?? "NULL"}");
- }
- else
- {
- Debug.LogError($"❌ TravelUI: Route element {i} not found in UI!");
- }
- }
- }
- /// <summary>
- /// Updates travel information display
- /// </summary>
- private void UpdateTravelInfo()
- {
- Debug.Log($"🔄 TravelUI.UpdateTravelInfo called - selectedRoute: {selectedRoute?.routeType}");
- if (selectedRoute == null)
- {
- Debug.LogWarning("⚠️ TravelUI.UpdateTravelInfo: selectedRoute is null");
- return;
- }
- Debug.Log($"📊 TravelUI.UpdateTravelInfo: Updating with route {selectedRoute.routeType} - Time: {selectedRoute.estimatedTime:F1}h, Distance: {selectedRoute.totalDistance:F1}, SpecialCosts: {selectedRoute.specialCosts?.Count ?? 0}");
- if (distanceLabel != null)
- {
- distanceLabel.text = $"Distance: {selectedRoute.totalDistance:F1} leagues";
- distanceLabel.MarkDirtyRepaint(); // Force UI refresh
- Debug.Log($"✅ TravelUI: Updated distance to: {distanceLabel.text}");
- }
- else
- {
- Debug.LogWarning("⚠️ TravelUI.UpdateTravelInfo: distanceLabel is null");
- }
- if (timeLabel != null)
- {
- timeLabel.text = $"Travel Time: {selectedRoute.estimatedTime:F1} hours";
- timeLabel.MarkDirtyRepaint(); // Force UI refresh
- Debug.Log($"✅ TravelUI: Updated time to: {timeLabel.text}");
- }
- else
- {
- Debug.LogWarning("⚠️ TravelUI.UpdateTravelInfo: timeLabel is null");
- }
- if (specialCostsLabel != null)
- {
- if (selectedRoute.specialCosts != null && selectedRoute.specialCosts.Count > 0)
- {
- var costs = selectedRoute.specialCosts.Select(kvp => $"{kvp.Key}: {kvp.Value}");
- specialCostsLabel.text = $"Special Costs: {string.Join(", ", costs)}";
- specialCostsLabel.style.display = DisplayStyle.Flex;
- specialCostsLabel.MarkDirtyRepaint(); // Force UI refresh
- Debug.Log($"✅ TravelUI: Updated special costs to: {specialCostsLabel.text}");
- }
- else
- {
- specialCostsLabel.text = "Special Costs: None";
- specialCostsLabel.style.display = DisplayStyle.Flex;
- specialCostsLabel.MarkDirtyRepaint(); // Force UI refresh
- Debug.Log($"✅ TravelUI: Updated special costs to: None");
- }
- }
- else
- {
- Debug.LogWarning("⚠️ TravelUI.UpdateTravelInfo: specialCostsLabel is null");
- }
- // Force the entire container to refresh
- if (travelContainer != null)
- {
- travelContainer.MarkDirtyRepaint();
- }
- Debug.Log("✅ TravelUI.UpdateTravelInfo: Complete");
- }
- /// <summary>
- /// Populates the route selection list
- /// </summary>
- private void PopulateRouteList()
- {
- if (routeList == null) return;
- // Clear existing route options
- routeList.Clear();
- // Sort routes by estimated time (fastest first)
- var sortedRoutes = availableRoutes.OrderBy(r => r.estimatedTime).ToList();
- for (int i = 0; i < sortedRoutes.Count; i++)
- {
- var route = sortedRoutes[i];
- var routeElement = CreateRouteOptionElement(route, i == 0); // First route is selected by default
- routeList.Add(routeElement);
- }
- Debug.Log($"📊 TravelUI: Populated route list with {sortedRoutes.Count} options");
- }
- /// <summary>
- /// Creates a clickable route option element
- /// </summary>
- private VisualElement CreateRouteOptionElement(TravelRoute route, bool isSelected)
- {
- var routeOption = new VisualElement();
- routeOption.AddToClassList("route-option");
- if (isSelected)
- {
- routeOption.AddToClassList("route-selected");
- selectedRoute = route;
- }
- // Color indicator
- var colorIndicator = new VisualElement();
- colorIndicator.AddToClassList("route-color-indicator");
- // Set color based on route type
- Color routeColor = GetRouteDisplayColor(route);
- colorIndicator.style.backgroundColor = routeColor;
- routeOption.Add(colorIndicator);
- // Route details container
- var routeDetails = new VisualElement();
- routeDetails.AddToClassList("route-details");
- // Route type and main info
- var routeHeader = new Label($"{GetRouteDisplayName(route)}");
- routeHeader.AddToClassList("route-header");
- routeDetails.Add(routeHeader);
- // Time info
- var routeTime = new Label($"Time: {route.estimatedTime:F1}h");
- routeTime.AddToClassList("route-time");
- routeDetails.Add(routeTime);
- // Resource costs (gold, torches, etc.)
- var resourceCosts = GetResourceCosts(route);
- if (resourceCosts.Count > 0)
- {
- var costText = string.Join(", ", resourceCosts.Select(kvp => $"{kvp.Value} {kvp.Key}"));
- var routeCost = new Label($"Resources: {costText}");
- routeCost.AddToClassList("route-cost");
- routeDetails.Add(routeCost);
- }
- else
- {
- var routeCost = new Label("Resources: None");
- routeCost.AddToClassList("route-cost");
- routeDetails.Add(routeCost);
- }
- // Special costs if any
- if (route.specialCosts.Count > 0)
- {
- var specialText = string.Join(", ", route.specialCosts.Select(kvp => $"{kvp.Key}: {kvp.Value}"));
- var specialLabel = new Label($"Special: {specialText}");
- specialLabel.AddToClassList("route-special");
- routeDetails.Add(specialLabel);
- }
- // Add debug information showing path composition
- var debugInfo = GetRouteDebugInfo(route);
- if (!string.IsNullOrEmpty(debugInfo))
- {
- var debugLabel = new Label(debugInfo);
- debugLabel.AddToClassList("route-debug");
- routeDetails.Add(debugLabel);
- }
- routeOption.Add(routeDetails);
- // Click handler with enhanced debugging
- routeOption.RegisterCallback<ClickEvent>(evt =>
- {
- Debug.Log($"🖱️ TravelUI: Route clicked! Event target: {evt.target}, Route: {route.routeType}");
- SelectRoute(route, routeOption);
- evt.StopPropagation(); // Prevent event bubbling
- });
- // Also add mouse events for debugging
- routeOption.RegisterCallback<MouseEnterEvent>(evt =>
- {
- Debug.Log($"🐭 TravelUI: Mouse entered route: {route.routeType}");
- });
- return routeOption;
- }
- /// <summary>
- /// Handles route selection
- /// </summary>
- private void SelectRoute(TravelRoute route, VisualElement clickedElement)
- {
- Debug.Log($"🎯 TravelUI: SelectRoute called for {route.routeType} - Time: {route.estimatedTime:F1}h, Distance: {route.totalDistance:F1}");
- Debug.Log($"🔍 TravelUI: SelectRoute - Previous selectedRoute: {selectedRoute?.routeType}");
- selectedRoute = route;
- // Update visual selection
- var allRouteOptions = routeList.Children();
- Debug.Log($"📋 TravelUI: SelectRoute - Found {allRouteOptions.Count()} route options in list");
- foreach (var option in allRouteOptions)
- {
- option.RemoveFromClassList("route-selected");
- }
- clickedElement.AddToClassList("route-selected");
- Debug.Log($"✅ TravelUI: SelectRoute - Visual selection updated for {route.routeType}");
- Debug.Log($"🔄 TravelUI: About to call UpdateTravelInfo for {route.routeType}");
- // Update travel info
- UpdateTravelInfo();
- // Notify the travel system to highlight this route - FIX THIS CALL
- var travelSystem = FindFirstObjectByType<TeamTravelSystem>();
- if (travelSystem != null)
- {
- // Use the correct method name from your travel system
- try
- {
- travelSystem.VisualizeSpecificRoute(route);
- Debug.Log($"✅ TravelUI: Successfully called VisualizeSpecificRoute for {route.routeType}");
- }
- catch (System.Exception e)
- {
- Debug.LogWarning($"⚠️ TravelUI: Failed to visualize route: {e.Message}");
- // Try alternative method names
- var method = travelSystem.GetType().GetMethod("HighlightRoute");
- if (method != null)
- {
- method.Invoke(travelSystem, new object[] { route });
- Debug.Log($"✅ TravelUI: Used HighlightRoute instead");
- }
- }
- }
- else
- {
- Debug.LogWarning("⚠️ TravelUI: TeamTravelSystem not found for route visualization");
- }
- Debug.Log($"🎯 TravelUI: Selected {route.routeType} route - SelectRoute complete");
- }
- /// <summary>
- /// Gets display color for route based on type (GPS-style)
- /// </summary>
- private Color GetRouteDisplayColor(TravelRoute route)
- {
- // Match colors from TeamTravelSystem GPS-style
- switch (route.routeType)
- {
- case RouteType.Standard:
- return Color.blue; // Shortest route
- case RouteType.RoadPreferred:
- return Color.green; // Fastest route
- case RouteType.Special:
- return Color.yellow; // Cheapest route
- default:
- return Color.blue;
- }
- }
- /// <summary>
- /// Gets GPS-style display name for route type
- /// </summary>
- private string GetRouteDisplayName(TravelRoute route)
- {
- switch (route.routeType)
- {
- case RouteType.Standard:
- return "Shortest Route";
- case RouteType.RoadPreferred:
- return "Fastest Route";
- case RouteType.Special:
- return "Cheapest Route";
- default:
- return "Unknown Route";
- }
- }
- /// <summary>
- /// Handles start travel button click
- /// </summary>
- private void OnStartTravelClicked()
- {
- if (selectedRoute == null)
- {
- Debug.LogWarning("⚠️ TravelUI: No route selected for travel");
- return;
- }
- Debug.Log($"🚶 TravelUI: Starting travel with {selectedRoute.routeType} route");
- // Start travel through the travel system
- var travelSystem = TeamTravelSystem.Instance;
- if (travelSystem != null)
- {
- travelSystem.StartTravel(selectedRoute);
- }
- // Hide UI
- HideTravelPanel();
- }
- /// <summary>
- /// Handles cancel button click
- /// </summary>
- private void OnCancelTravelClicked()
- {
- Debug.Log("❌ TravelUI: Travel cancelled by user");
- // Cancel travel planning
- var travelSystem = TeamTravelSystem.Instance;
- if (travelSystem != null)
- {
- travelSystem.CancelTravelPlanning();
- }
- // Hide UI
- HideTravelPanel();
- }
- /// <summary>
- /// Updates UI for a selected route (called by TeamTravelSystem via reflection)
- /// </summary>
- public void UpdateUIForSelectedRoute(TravelRoute route)
- {
- if (!isUIVisible)
- {
- return;
- }
- selectedRoute = route;
- UpdateTravelInfo();
- // Update visual selection in route list
- if (routeList != null)
- {
- var routeOptions = routeList.Children().ToList();
- for (int i = 0; i < routeOptions.Count && i < availableRoutes.Count; i++)
- {
- var routeOption = routeOptions[i];
- var routeData = availableRoutes.OrderBy(r => r.estimatedTime).ToList()[i];
- if (routeData == route)
- {
- routeOption.AddToClassList("route-selected");
- Debug.Log($"🎯 TravelUI.UpdateUIForSelectedRoute: Visual selection updated for route {i}");
- }
- else
- {
- routeOption.RemoveFromClassList("route-selected");
- }
- }
- }
- else
- {
- Debug.LogWarning("⚠️ TravelUI.UpdateUIForSelectedRoute: routeList is null");
- }
- Debug.Log($"🔄 TravelUI: Updated UI for {route.routeType} route");
- }
- /// <summary>
- /// Checks if UI is blocking input (called by TeamTravelSystem via reflection)
- /// </summary>
- public bool IsUIBlocking()
- {
- return isUIVisible;
- }
- /// <summary>
- /// Check if a screen position (in Unity's screen coordinates) is within the UI panel
- /// </summary>
- public bool IsPointWithinUI(Vector2 screenPosition)
- {
- if (!isUIVisible || travelPanel == null)
- {
- return false;
- }
- // Convert screen position to panel-relative position
- Vector2 panelPosition = RuntimePanelUtils.ScreenToPanel(travelPanel.panel, screenPosition);
- // Check if the position is within the panel bounds
- bool withinBounds = travelPanel.worldBound.Contains(panelPosition);
- return withinBounds;
- }
- /// <summary>
- /// Public getters for external access
- /// </summary>
- public bool IsVisible => isUIVisible;
- public TravelRoute GetSelectedRoute() => selectedRoute;
- /// <summary>
- /// Forces the UI to refresh with new route data - called externally when routes are recalculated
- /// </summary>
- public void RefreshWithNewRoutes(List<TravelRoute> routes)
- {
- Debug.Log($"🔄 TravelUI: RefreshWithNewRoutes called externally with {routes.Count} routes");
- if (!isUIVisible)
- {
- Debug.LogWarning("⚠️ TravelUI: RefreshWithNewRoutes called but UI is not visible");
- return;
- }
- UpdateRoutesAndRefreshUI(currentDestination, routes);
- }
- /// <summary>
- /// Sets up drag functionality for the travel panel
- /// </summary>
- private void SetupDragFunctionality(VisualElement dragHandle, VisualElement panelToDrag)
- {
- bool isDragging = false;
- Vector2 startPosition = Vector2.zero;
- Vector2 startMousePosition = Vector2.zero;
- dragHandle.RegisterCallback<MouseDownEvent>(evt =>
- {
- if (evt.button == 0) // Left mouse button
- {
- isDragging = true;
- startPosition = new Vector2(panelToDrag.style.left.value.value, panelToDrag.style.top.value.value);
- startMousePosition = evt.mousePosition;
- dragHandle.CaptureMouse();
- evt.StopPropagation();
- }
- });
- dragHandle.RegisterCallback<MouseMoveEvent>(evt =>
- {
- if (isDragging)
- {
- Vector2 delta = evt.mousePosition - startMousePosition;
- panelToDrag.style.left = startPosition.x + delta.x;
- panelToDrag.style.top = startPosition.y + delta.y;
- evt.StopPropagation();
- }
- });
- dragHandle.RegisterCallback<MouseUpEvent>(evt =>
- {
- if (isDragging)
- {
- isDragging = false;
- dragHandle.ReleaseMouse();
- evt.StopPropagation();
- }
- });
- }
- /// <summary>
- /// Gets debug information about route composition
- /// </summary>
- private string GetRouteDebugInfo(TravelRoute route)
- {
- if (route?.path == null || route.path.Count == 0) return "";
- // Get terrain analysis from TeamTravelSystem
- var travelSystem = TeamTravelSystem.Instance;
- if (travelSystem == null) return "";
- // Count different terrain types in the route
- var terrainCounts = new Dictionary<string, int>();
- // This is a simplified analysis - in a full implementation,
- // you'd access the actual map data through the travel system
- float avgCostPerTile = route.totalCost / route.path.Count;
- string preference = "";
- switch (route.routeType)
- {
- case RouteType.RoadPreferred:
- preference = "Prefers roads";
- break;
- case RouteType.Special:
- preference = "Uses ferries/tunnels";
- break;
- default:
- preference = "Cheapest path";
- break;
- }
- return $"{preference} • Avg: {avgCostPerTile:F1}/tile";
- }
- /// <summary>
- /// Gets resource costs for a route (gold, torches, etc.)
- /// </summary>
- private Dictionary<string, int> GetResourceCosts(TravelRoute route)
- {
- var costs = new Dictionary<string, int>();
- // Add special costs from the route (with null safety)
- if (route?.specialCosts != null)
- {
- foreach (var specialCost in route.specialCosts)
- {
- switch (specialCost.Key)
- {
- case "Ferry":
- case "Bridge Toll":
- costs["Gold"] = costs.GetValueOrDefault("Gold", 0) + specialCost.Value;
- break;
- case "Tunnel Torch":
- costs["Torches"] = costs.GetValueOrDefault("Torches", 0) + specialCost.Value;
- break;
- case "Mountain Guide":
- costs["Gold"] = costs.GetValueOrDefault("Gold", 0) + specialCost.Value;
- break;
- default:
- costs[specialCost.Key] = specialCost.Value;
- break;
- }
- }
- }
- return costs;
- }
- /// <summary>
- /// Ensures the travel UI doesn't overlap with the team overview panel on the right side
- /// </summary>
- private void EnsureNoTeamOverviewOverlap()
- {
- if (travelContainer == null) return;
- // Check if team overview exists
- var teamOverview = FindFirstObjectByType<TeamOverviewController>();
- if (teamOverview != null)
- {
- // The CSS already centers the travel UI, but we can add extra margin if needed
- // This is a safeguard to ensure proper spacing
- var panel = travelContainer.Q("TravelPanel");
- if (panel != null)
- {
- // Add some extra margin to avoid any potential overlap
- panel.style.marginRight = 320; // Team overview width + padding
- }
- }
- }
- }
|