| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152 |
- using UnityEngine;
- using UnityEngine.UIElements;
- using System.Collections.Generic;
- using System.Collections;
- using Unity.VisualScripting;
- using System;
- public class ActiveQuestUI : MonoBehaviour, IClickBlocker
- {
- [Header("UI References")]
- public UIDocument uiDocument;
- // Main UI elements
- private VisualElement questTracker;
- private Label trackerTitle;
- private Button questLogButton;
- private Button toggleTrackerButton;
- private ScrollView activeQuestsList;
- private Label noQuestsMessage;
- private VisualElement quickActions;
- private Button showAllButton;
- private Button trackLocationButton;
- private Button abandonQuestButton;
- // Popup elements
- private VisualElement questDetailsPopup;
- private VisualElement popupContent;
- private Label popupTitle;
- private Button closePopupButton;
- private VisualElement popupDetails;
- private VisualElement questInfo;
- private VisualElement objectivesList;
- private VisualElement rewardsList;
- private VisualElement popupActions;
- private Button trackButton;
- private Button navigateButton;
- // Notification elements
- private VisualElement completionNotification;
- private VisualElement progressNotification;
- // Exposed flag other systems can check to know UI is capturing pointer
- // State
- private ActiveQuest selectedQuest;
- private bool isUIVisible = false;
- private List<VisualElement> questEntries = new List<VisualElement>();
- [System.NonSerialized]
- private bool recentlyHandledClick = false; // Flag to prevent map clicks when UI handles them
- public bool IsVisible => isUIVisible;
- public bool IsBlockingClick(Vector2 screenPosition)
- {
- // Primary method: Check if we recently handled a UI click
- if (recentlyHandledClick)
- {
- Debug.Log("🚫 ActiveQuestUI: Blocking click due to recent UI interaction");
- return true;
- }
- // If UI is not visible, don't block anything
- if (!isUIVisible)
- {
- return false;
- }
- // Dynamic coordinate-based approach: Block clicks in the quest tracker area
- // This needs to account for the expanded quest panel when it shows more options
- float questPanelWidth = 320f; // Approximate width of quest panel
- float questPanelHeight = 250f; // Larger height to cover expanded panel (was 120f)
- float questPanelX = 20f; // Left edge
- float questPanelY = Screen.height - questPanelHeight - 20f; // Top edge (converted to screen coords)
- // Alternative: Try to get actual bounds from the quest tracker if available
- if (questTracker != null)
- {
- try
- {
- // Try to use the actual UI element bounds if possible
- var bounds = questTracker.worldBound;
- if (bounds.width > 0 && bounds.height > 0)
- {
- // Convert UI bounds to screen coordinates
- questPanelX = bounds.x;
- questPanelY = Screen.height - bounds.y - bounds.height;
- questPanelWidth = bounds.width;
- questPanelHeight = bounds.height;
- Debug.Log($"🔍 Using actual UI bounds: x={questPanelX}, y={questPanelY}, w={questPanelWidth}, h={questPanelHeight}");
- }
- }
- catch (System.Exception e)
- {
- Debug.LogWarning($"Failed to get UI bounds, using fallback: {e.Message}");
- }
- }
- bool inQuestArea = screenPosition.x >= questPanelX &&
- screenPosition.x <= questPanelX + questPanelWidth &&
- screenPosition.y >= questPanelY &&
- screenPosition.y <= questPanelY + questPanelHeight;
- if (inQuestArea)
- {
- Debug.Log($"🛡️ ActiveQuestUI: Blocking click in quest area at {screenPosition} (quest area: {questPanelX}-{questPanelX + questPanelWidth}, {questPanelY}-{questPanelY + questPanelHeight})");
- return true;
- }
- // Don't block clicks outside the quest area
- return false;
- }
- void OnEnable() => ClickBlockingHelper.RegisterWithClickManager(this);
- void OnDisable() => ClickBlockingHelper.UnregisterWithClickManager(this);
- /// <summary>
- /// Sets a temporary flag to block travel system clicks when UI handles a click event.
- /// This is much more reliable than trying to calculate coordinates manually.
- /// </summary>
- private void SetClickFlag()
- {
- ClickBlockingHelper.SetClickFlag("ActiveQuestUI", this, (flag) => recentlyHandledClick = flag);
- }
- private void Start()
- {
- Debug.Log("ActiveQuestUI: Start called");
- InitializeUI();
- SubscribeToEvents();
- // Delay quest refresh to ensure QuestManager is fully initialized
- StartCoroutine(DelayedQuestRefresh());
- }
- private IEnumerator DelayedQuestRefresh()
- {
- yield return new WaitForEndOfFrame();
- Debug.Log("ActiveQuestUI: Performing delayed quest refresh");
- RefreshQuestList();
- }
- private void InitializeUI()
- {
- if (uiDocument == null)
- uiDocument = GetComponent<UIDocument>();
- var root = uiDocument.rootVisualElement;
- if (root == null)
- {
- return;
- }
- // Ensure root doesn't block other UI - set to ignore picking
- root.pickingMode = PickingMode.Ignore;
- // Ensure this UI has proper sorting order to be above map but below modals
- if (uiDocument.sortingOrder == 0)
- {
- uiDocument.sortingOrder = 10; // Above map, below modals like TravelUI
- }
- // Get main elements
- questTracker = root.Q<VisualElement>("quest-tracker");
- trackerTitle = root.Q<Label>("tracker-title");
- questLogButton = root.Q<Button>("quest-log-button");
- toggleTrackerButton = root.Q<Button>("toggle-tracker-button");
- activeQuestsList = root.Q<ScrollView>("active-quests-list");
- noQuestsMessage = root.Q<Label>("no-quests-message");
- quickActions = root.Q<VisualElement>("quick-actions");
- showAllButton = root.Q<Button>("show-all-button");
- trackLocationButton = root.Q<Button>("track-location-button");
- abandonQuestButton = root.Q<Button>("abandon-quest-button");
- // Get popup elements
- questDetailsPopup = root.Q<VisualElement>("quest-details-popup");
- popupContent = root.Q<VisualElement>("popup-content");
- popupTitle = root.Q<Label>("popup-title");
- closePopupButton = root.Q<Button>("close-popup-button");
- popupDetails = root.Q<VisualElement>("popup-details");
- questInfo = root.Q<VisualElement>("quest-info");
- objectivesList = root.Q<VisualElement>("objectives-list");
- rewardsList = root.Q<VisualElement>("rewards-list");
- popupActions = root.Q<VisualElement>("popup-actions");
- trackButton = root.Q<Button>("track-button");
- navigateButton = root.Q<Button>("navigate-button");
- // Get notification elements
- completionNotification = root.Q<VisualElement>("completion-notification");
- progressNotification = root.Q<VisualElement>("progress-notification");
- // Set up event handlers
- questLogButton.clicked += () => OpenFullQuestLog();
- toggleTrackerButton.clicked += () => ToggleQuestTracker();
- showAllButton.clicked += () => OpenFullQuestLog();
- trackLocationButton.clicked += () => TrackSelectedQuest();
- abandonQuestButton.clicked += () => AbandonSelectedQuest();
- closePopupButton.clicked += () => CloseQuestDetails();
- trackButton.clicked += () => TrackSelectedQuest();
- navigateButton.clicked += () => NavigateToQuest();
- // Initially hide popup and notifications
- if (questDetailsPopup != null)
- questDetailsPopup.style.display = DisplayStyle.None;
- if (completionNotification != null)
- completionNotification.style.display = DisplayStyle.None;
- if (progressNotification != null)
- progressNotification.style.display = DisplayStyle.None;
- // Update tracker title with count
- UpdateTrackerTitle();
- // Add TravelUI-style click blocking
- AddClickBlockingOverlay(root);
- // Add mouse event blocking to prevent clicks from going through
- if (questTracker != null)
- {
- // Ensure the quest tracker can receive mouse events and has higher priority
- questTracker.pickingMode = PickingMode.Position;
- questTracker.RegisterCallback<MouseDownEvent>(evt =>
- {
- Debug.Log("QuestTracker MouseDownEvent - stopping propagation");
- SetClickFlag(); // Set flag to block travel system
- evt.StopPropagation();
- });
- questTracker.RegisterCallback<MouseUpEvent>(evt =>
- {
- Debug.Log("QuestTracker MouseUpEvent - stopping propagation");
- evt.StopPropagation();
- });
- questTracker.RegisterCallback<ClickEvent>(evt =>
- {
- Debug.Log("QuestTracker ClickEvent - stopping propagation");
- SetClickFlag(); // Set flag to block travel system
- evt.StopPropagation();
- });
- // Also block pointer events for UI Toolkit compatibility
- questTracker.RegisterCallback<PointerDownEvent>(evt =>
- {
- Debug.Log("QuestTracker PointerDownEvent - stopping propagation");
- SetClickFlag(); // Set flag to block travel system
- evt.StopPropagation();
- });
- questTracker.RegisterCallback<PointerUpEvent>(evt =>
- {
- Debug.Log("QuestTracker PointerUpEvent - stopping propagation");
- evt.StopPropagation();
- });
- } // Also block events on popup
- if (questDetailsPopup != null)
- {
- questDetailsPopup.RegisterCallback<MouseDownEvent>(evt =>
- {
- SetClickFlag(); // Set flag to block travel system
- evt.StopPropagation();
- });
- questDetailsPopup.RegisterCallback<MouseUpEvent>(evt =>
- {
- evt.StopPropagation();
- });
- questDetailsPopup.RegisterCallback<ClickEvent>(evt =>
- {
- SetClickFlag(); // Set flag to block travel system
- evt.StopPropagation();
- });
- }
- isUIVisible = true;
- }
- #region Context Menu Debug Methods
- [ContextMenu("Refresh Quest List")]
- private void DebugRefreshQuestList()
- {
- RefreshQuestList();
- }
- [ContextMenu("Debug Quest System")]
- private void DebugQuestSystem()
- {
- Debug.Log("=== QUEST SYSTEM DEBUG ===");
- if (QuestManager.Instance == null)
- {
- Debug.LogError("QuestManager.Instance is NULL!");
- return;
- }
- Debug.Log("QuestManager.Instance exists");
- var activeQuests = QuestManager.Instance.GetActiveQuests();
- Debug.Log($"Active quests count: {activeQuests.Count}");
- foreach (var quest in activeQuests)
- {
- Debug.Log($"Active Quest: {quest.questData.questTitle} - Status: {quest.status}");
- }
- // Check UI elements
- Debug.Log($"questTracker: {(questTracker != null ? "EXISTS" : "NULL")}");
- Debug.Log($"activeQuestsList: {(activeQuestsList != null ? "EXISTS" : "NULL")}");
- Debug.Log($"trackerTitle: {(trackerTitle != null ? "EXISTS" : "NULL")}");
- if (trackerTitle != null)
- {
- Debug.Log($"Tracker title text: '{trackerTitle.text}'");
- }
- }
- [ContextMenu("Force Load Quest Data")]
- private void DebugForceLoadQuestData()
- {
- if (QuestManager.Instance != null)
- {
- Debug.Log("Forcing QuestManager to load quest data...");
- QuestManager.Instance.LoadQuestData();
- RefreshQuestList();
- }
- else
- {
- Debug.LogError("QuestManager.Instance is null!");
- }
- }
- [ContextMenu("Check PlayerPrefs Quest Data")]
- private void DebugCheckPlayerPrefsQuestData()
- {
- Debug.Log("=== CHECKING QUEST PERSISTENCE ===");
- if (PlayerPrefs.HasKey("QuestSaveData"))
- {
- string questSaveData = PlayerPrefs.GetString("QuestSaveData");
- Debug.Log($"Found QuestSaveData in PlayerPrefs: {questSaveData}");
- if (string.IsNullOrEmpty(questSaveData))
- {
- Debug.LogWarning("QuestSaveData exists but is empty!");
- }
- }
- else
- {
- Debug.LogWarning("No QuestSaveData found in PlayerPrefs!");
- }
- }
- [ContextMenu("Test Quest Entry")]
- private void DebugTestQuestEntry()
- {
- if (QuestManager.Instance != null)
- {
- var activeQuests = QuestManager.Instance.GetActiveQuests();
- Debug.Log($"Active quests found: {activeQuests.Count}");
- foreach (var quest in activeQuests)
- {
- Debug.Log($"- {quest.questData.questTitle}");
- }
- }
- else
- {
- Debug.LogWarning("No QuestManager found!");
- }
- }
- [ContextMenu("Force Show Popup")]
- private void DebugForceShowPopup()
- {
- if (questDetailsPopup != null)
- {
- questDetailsPopup.style.display = DisplayStyle.Flex;
- isUIVisible = true;
- Debug.Log("Forced popup to show");
- }
- }
- [ContextMenu("Force Hide Popup")]
- private void DebugForceHidePopup()
- {
- if (questDetailsPopup != null)
- {
- questDetailsPopup.style.display = DisplayStyle.None;
- Debug.Log("Forced popup to hide");
- isUIVisible = false;
- }
- }
- [ContextMenu("Toggle Quest Tracker Visibility")]
- private void DebugToggleQuestTracker()
- {
- if (questTracker != null)
- {
- bool isVisible = questTracker.style.display != DisplayStyle.None;
- questTracker.style.display = isVisible ? DisplayStyle.None : DisplayStyle.Flex;
- Debug.Log($"Quest tracker {(isVisible ? "hidden" : "shown")}");
- isUIVisible = isVisible;
- }
- }
- private bool isTrackerMinimized = false;
- private void ToggleQuestTracker()
- {
- isTrackerMinimized = !isTrackerMinimized;
- if (isTrackerMinimized)
- {
- // Hide the quest list and actions, only show header
- if (activeQuestsList != null)
- activeQuestsList.style.display = DisplayStyle.None;
- if (quickActions != null)
- quickActions.style.display = DisplayStyle.None;
- if (noQuestsMessage != null)
- noQuestsMessage.style.display = DisplayStyle.None;
- // Change button text to show expand option
- if (toggleTrackerButton != null)
- toggleTrackerButton.text = "+";
- // Make tracker smaller
- if (questTracker != null)
- {
- questTracker.style.height = 40;
- questTracker.style.maxHeight = 40;
- }
- }
- else
- {
- // Show everything again
- if (activeQuestsList != null)
- activeQuestsList.style.display = DisplayStyle.Flex;
- if (quickActions != null)
- quickActions.style.display = DisplayStyle.Flex;
- // Show no quests message if needed
- var activeQuests = QuestManager.Instance?.GetActiveQuests();
- if (activeQuests == null || activeQuests.Count == 0)
- {
- if (noQuestsMessage != null)
- noQuestsMessage.style.display = DisplayStyle.Flex;
- }
- // Change button text back
- if (toggleTrackerButton != null)
- toggleTrackerButton.text = "−";
- // Restore tracker size
- if (questTracker != null)
- {
- questTracker.style.height = StyleKeyword.Auto;
- questTracker.style.maxHeight = 350;
- }
- }
- }
- [ContextMenu("Reset Quest Tracker Position")]
- private void DebugResetQuestTrackerPosition()
- {
- if (questTracker != null)
- {
- questTracker.style.position = Position.Absolute;
- questTracker.style.top = 20;
- questTracker.style.left = 20;
- questTracker.style.right = StyleKeyword.Auto;
- questTracker.style.width = 250;
- Debug.Log("Reset quest tracker to left side position");
- }
- }
- #endregion
- private void SubscribeToEvents()
- {
- Debug.Log("ActiveQuestUI: SubscribeToEvents called");
- if (QuestManager.Instance != null)
- {
- Debug.Log("ActiveQuestUI: QuestManager found, subscribing to events");
- QuestManager.Instance.OnQuestAccepted += HandleQuestAccepted;
- QuestManager.Instance.OnQuestCompleted += HandleQuestCompleted;
- QuestManager.Instance.OnQuestAbandoned += HandleQuestAbandoned;
- QuestManager.Instance.OnQuestFailed += HandleQuestFailed;
- }
- else
- {
- Debug.LogWarning("ActiveQuestUI: QuestManager.Instance is null during SubscribeToEvents!");
- }
- }
- private void OnDestroy()
- {
- // Unregister from ClickManager
- ClickBlockingHelper.UnregisterWithClickManager(this);
- // Unregister from QuestManager events
- if (QuestManager.Instance != null)
- {
- QuestManager.Instance.OnQuestAccepted -= HandleQuestAccepted;
- QuestManager.Instance.OnQuestCompleted -= HandleQuestCompleted;
- QuestManager.Instance.OnQuestAbandoned -= HandleQuestAbandoned;
- QuestManager.Instance.OnQuestFailed -= HandleQuestFailed;
- }
- }
- #region Quest List Management
- private void RefreshQuestList()
- {
- Debug.Log("ActiveQuestUI: RefreshQuestList called");
- ClearQuestList();
- if (QuestManager.Instance == null)
- {
- Debug.LogWarning("ActiveQuestUI: QuestManager.Instance is null");
- ShowNoQuestsMessage();
- return;
- }
- var activeQuests = QuestManager.Instance.GetActiveQuests();
- Debug.Log($"ActiveQuestUI: Found {activeQuests.Count} active quests");
- if (activeQuests.Count == 0)
- {
- Debug.Log("ActiveQuestUI: No active quests found, showing no quests message");
- ShowNoQuestsMessage();
- return;
- }
- Debug.Log("ActiveQuestUI: Creating quest entries");
- HideNoQuestsMessage();
- foreach (var quest in activeQuests)
- {
- Debug.Log($"ActiveQuestUI: Creating entry for quest: {quest.questData.questTitle}");
- CreateQuestEntry(quest);
- }
- UpdateTrackerTitle();
- UpdateQuickActions();
- }
- private void ClearQuestList()
- {
- questEntries.Clear();
- activeQuestsList?.Clear();
- }
- private void ShowNoQuestsMessage()
- {
- if (noQuestsMessage != null)
- noQuestsMessage.style.display = DisplayStyle.Flex;
- if (quickActions != null)
- quickActions.style.display = DisplayStyle.None;
- }
- private void HideNoQuestsMessage()
- {
- if (noQuestsMessage != null)
- noQuestsMessage.style.display = DisplayStyle.None;
- if (quickActions != null)
- quickActions.style.display = DisplayStyle.Flex;
- }
- private void CreateQuestEntry(ActiveQuest quest)
- {
- var entry = new VisualElement();
- entry.AddToClassList("quest-entry-compact");
- // Header with title and urgency
- var header = new VisualElement();
- header.AddToClassList("quest-compact-header");
- var title = new Label(quest.questData.questTitle);
- title.AddToClassList("quest-compact-title");
- var urgency = new VisualElement();
- urgency.AddToClassList("quest-compact-urgency");
- urgency.AddToClassList(GetUrgencyClass(quest.GetUrgencyLevel()));
- header.Add(title);
- header.Add(urgency);
- // Info row with progress and time
- var info = new VisualElement();
- info.AddToClassList("quest-compact-info");
- var progress = new Label($"{quest.GetCompletedObjectivesCount()}/{quest.questData.goals.Count} objectives");
- progress.AddToClassList("quest-compact-progress"); var timeRemaining = new Label(GetTimeRemainingText(quest));
- timeRemaining.AddToClassList("quest-compact-time");
- info.Add(progress);
- info.Add(timeRemaining);
- entry.Add(header);
- entry.Add(info);
- // Click handler
- entry.RegisterCallback<ClickEvent>(evt => SelectQuest(quest, entry));
- activeQuestsList.Add(entry);
- questEntries.Add(entry);
- }
- private string GetUrgencyClass(QuestUrgency urgency)
- {
- switch (urgency)
- {
- case QuestUrgency.Low: return "urgency-low";
- case QuestUrgency.Medium: return "urgency-medium";
- case QuestUrgency.High: return "urgency-high";
- case QuestUrgency.Critical: return "urgency-critical";
- default: return "urgency-low";
- }
- }
- private string GetTimeRemainingText(ActiveQuest quest)
- {
- if (quest.questData.timeLimit <= 0)
- return "No time limit";
- float remaining = quest.GetTimeRemaining();
- if (remaining <= 0)
- return "EXPIRED";
- if (remaining < 1f)
- return "< 1 hour";
- if (remaining < 24f)
- return $"{Mathf.CeilToInt(remaining)}h";
- return $"{Mathf.CeilToInt(remaining / 24f)}d";
- }
- private void AddClickBlockingOverlay(VisualElement root)
- {
- // Create a click blocker similar to TravelUI
- var clickBlocker = new VisualElement();
- clickBlocker.name = "ClickBlocker";
- clickBlocker.AddToClassList("click-blocker");
- // Position as first child (behind everything else)
- root.Insert(0, clickBlocker);
- // Block all mouse events
- clickBlocker.RegisterCallback<ClickEvent>(evt =>
- {
- evt.StopPropagation();
- });
- clickBlocker.RegisterCallback<MouseDownEvent>(evt =>
- {
- evt.StopPropagation();
- });
- clickBlocker.RegisterCallback<MouseUpEvent>(evt =>
- {
- evt.StopPropagation();
- });
- }
- private void UpdateTrackerTitle()
- {
- Debug.Log("UpdateTrackerTitle called");
- if (trackerTitle == null)
- {
- Debug.LogWarning("trackerTitle is null!");
- return;
- }
- int activeCount = QuestManager.Instance?.GetActiveQuests().Count ?? 0;
- string newTitle = $"Active Quests ({activeCount})";
- Debug.Log($"Setting tracker title to: '{newTitle}'");
- trackerTitle.text = newTitle;
- // Force update the display
- if (questTracker != null)
- {
- questTracker.style.display = DisplayStyle.Flex;
- Debug.Log("Ensured questTracker is visible");
- }
- }
- #endregion
- #region Selection and Actions
- private void SelectQuest(ActiveQuest quest, VisualElement entry)
- {
- // Deselect previous
- foreach (var questEntry in questEntries)
- {
- questEntry.RemoveFromClassList("selected");
- }
- // Select new
- entry.AddToClassList("selected");
- selectedQuest = quest;
- UpdateQuickActions();
- }
- private void UpdateQuickActions()
- {
- if (quickActions == null) return;
- bool hasSelection = selectedQuest != null;
- trackLocationButton?.SetEnabled(hasSelection);
- abandonQuestButton?.SetEnabled(hasSelection);
- }
- private void TrackSelectedQuest()
- {
- if (selectedQuest == null) return;
- // Focus camera on quest location
- var questMapMarkerManager = FindFirstObjectByType<QuestMapMarkerManager>();
- if (questMapMarkerManager != null)
- {
- questMapMarkerManager.FocusOnQuest(selectedQuest);
- Debug.Log($"Tracking quest: {selectedQuest.questData.questTitle}");
- }
- // Show quest details popup
- ShowQuestDetails(selectedQuest);
- }
- private void AbandonSelectedQuest()
- {
- if (selectedQuest == null) return;
- // Show confirmation dialog (simplified for now)
- if (QuestManager.Instance != null)
- {
- QuestManager.Instance.AbandonQuest(selectedQuest.questId);
- }
- }
- private void OpenFullQuestLog()
- {
- if (selectedQuest != null)
- {
- ShowQuestDetails(selectedQuest);
- }
- else
- {
- // Open the Adventures Guild UI or a quest log scene
- Debug.Log("Opening full quest log...");
- }
- }
- private void NavigateToQuest()
- {
- if (selectedQuest == null) return;
- // Set travel destination to quest location
- // var travelSystem = FindFirstObjectByType<TravelSystem>();
- // if (travelSystem != null)
- // {
- // Vector2 questLocation = new Vector2(selectedQuest.questData.targetLocationX, selectedQuest.questData.targetLocationY);
- // travelSystem.SetDestination(questLocation);
- // Debug.Log($"Navigating to quest at {questLocation}");
- // }
- Vector2 questLocation = new Vector2(selectedQuest.questData.targetLocationX, selectedQuest.questData.targetLocationY);
- Debug.Log($"Navigating to quest at {questLocation}");
- }
- #endregion
- #region Quest Details Popup
- private void ShowQuestDetails(ActiveQuest quest)
- {
- if (questDetailsPopup == null) return;
- // Populate quest info
- PopulateQuestDetails(quest);
- // Show popup
- if (questDetailsPopup != null)
- questDetailsPopup.style.display = DisplayStyle.Flex;
- }
- private void CloseQuestDetails()
- {
- if (questDetailsPopup != null)
- questDetailsPopup.style.display = DisplayStyle.None;
- }
- private void PopulateQuestDetails(ActiveQuest quest)
- {
- if (popupTitle != null)
- popupTitle.text = quest.questData.questTitle;
- if (questInfo == null) return;
- questInfo.Clear();
- // Title and difficulty
- var title = new Label(quest.questData.questTitle);
- title.AddToClassList("quest-title");
- questInfo.Add(title);
- var difficulty = new Label(quest.questData.difficulty.ToString().ToUpper());
- difficulty.AddToClassList("quest-difficulty");
- difficulty.AddToClassList($"difficulty-{quest.questData.difficulty.ToString().ToLower()}");
- questInfo.Add(difficulty);
- // Status bar
- var status = new VisualElement();
- status.AddToClassList("quest-status");
- var timeLabel = new Label(GetDetailedTimeText(quest));
- timeLabel.AddToClassList("time-remaining");
- var locationLabel = new Label($"Location: {quest.questData.targetLocationName}");
- locationLabel.AddToClassList("quest-location");
- status.Add(timeLabel);
- status.Add(locationLabel);
- questInfo.Add(status);
- // Description
- var descSection = new VisualElement();
- descSection.AddToClassList("section");
- var descHeader = new Label("Description");
- descHeader.AddToClassList("section-header");
- descSection.Add(descHeader);
- var description = new Label(quest.questData.description);
- description.AddToClassList("quest-description");
- descSection.Add(description);
- questInfo.Add(descSection);
- // Objectives
- PopulateObjectives(quest);
- // Rewards
- PopulateRewards(quest);
- }
- private void PopulateObjectives(ActiveQuest quest)
- {
- if (objectivesList == null) return;
- objectivesList.Clear();
- var section = new VisualElement();
- section.AddToClassList("section");
- var header = new Label("Objectives");
- header.AddToClassList("section-header");
- section.Add(header);
- // Progress bar
- var progressContainer = new VisualElement();
- progressContainer.AddToClassList("progress-container");
- var progressBar = new VisualElement();
- progressBar.AddToClassList("progress-bar");
- var progressFill = new VisualElement();
- progressFill.AddToClassList("progress-fill");
- int completed = quest.GetCompletedObjectivesCount();
- int total = quest.questData.objectives.Count;
- float percentage = total > 0 ? (float)completed / total * 100f : 0f;
- progressFill.style.width = new Length(percentage, LengthUnit.Percent);
- progressBar.Add(progressFill);
- var progressText = new Label($"{completed}/{total}");
- progressText.AddToClassList("progress-text");
- progressContainer.Add(progressBar);
- progressContainer.Add(progressText);
- section.Add(progressContainer);
- // Objective list
- var objList = new VisualElement();
- objList.AddToClassList("objectives-list");
- for (int i = 0; i < quest.questData.objectives.Count; i++)
- {
- var objective = quest.questData.objectives[i];
- bool isCompleted = quest.GetObjectiveProgress(i) >= objective.targetAmount;
- var objItem = new VisualElement();
- objItem.AddToClassList("objective-item-popup");
- var status = new VisualElement();
- status.AddToClassList("objective-status-popup");
- if (isCompleted)
- status.AddToClassList("objective-completed-popup");
- var text = new Label(objective.description);
- text.AddToClassList("objective-text-popup");
- var progress = new Label($"{quest.GetObjectiveProgress(i)}/{objective.targetAmount}");
- progress.AddToClassList("objective-progress-popup");
- objItem.Add(status);
- objItem.Add(text);
- objItem.Add(progress);
- objList.Add(objItem);
- }
- section.Add(objList);
- objectivesList.Add(section);
- }
- private void PopulateRewards(ActiveQuest quest)
- {
- if (rewardsList == null) return;
- rewardsList.Clear();
- var section = new VisualElement();
- section.AddToClassList("section");
- var header = new Label("Rewards");
- header.AddToClassList("section-header");
- section.Add(header);
- var rewards = new VisualElement();
- rewards.AddToClassList("rewards-list");
- if (quest.questData.goldReward > 0)
- {
- var goldReward = new Label($"🪙 {quest.questData.goldReward} Gold");
- goldReward.AddToClassList("reward-item");
- rewards.Add(goldReward);
- }
- if (quest.questData.renownReward > 0)
- {
- var renownReward = new Label($"⭐ {quest.questData.renownReward} Renown");
- renownReward.AddToClassList("reward-item");
- rewards.Add(renownReward);
- }
- foreach (var item in quest.questData.itemRewards)
- {
- if (item != null)
- {
- var itemReward = new Label($"📦 {item}");
- itemReward.AddToClassList("reward-item");
- rewards.Add(itemReward);
- }
- }
- section.Add(rewards);
- rewardsList.Add(section);
- }
- private string GetDetailedTimeText(ActiveQuest quest)
- {
- if (quest.questData.timeLimit <= 0)
- return "No time limit";
- float remaining = quest.GetTimeRemaining();
- if (remaining <= 0)
- return "QUEST EXPIRED";
- if (remaining < 1f)
- return $"{Mathf.RoundToInt(remaining * 60f)} minutes remaining";
- if (remaining < 24f)
- return $"{Mathf.RoundToInt(remaining)} hours remaining";
- int days = Mathf.FloorToInt(remaining / 24f);
- int hours = Mathf.RoundToInt(remaining % 24f);
- return $"{days}d {hours}h remaining";
- }
- #endregion
- #region Event Handlers
- private void HandleQuestAccepted(ActiveQuest quest)
- {
- Debug.Log($"ActiveQuestUI: HandleQuestAccepted called for quest {quest.questData.questTitle}");
- RefreshQuestList();
- }
- private void HandleQuestCompleted(ActiveQuest quest, List<QuestReward> rewards)
- {
- Debug.Log($"ActiveQuestUI: HandleQuestCompleted called for quest {quest.questData.questTitle}");
- ShowCompletionNotification(quest, rewards);
- RefreshQuestList();
- }
- private void HandleQuestAbandoned(ActiveQuest quest)
- {
- Debug.Log($"ActiveQuestUI: HandleQuestAbandoned called for quest {quest.questData.questTitle}");
- if (selectedQuest?.questData == quest.questData)
- selectedQuest = null;
- RefreshQuestList();
- }
- private void HandleQuestFailed(ActiveQuest quest)
- {
- Debug.Log($"ActiveQuestUI: HandleQuestFailed called for quest {quest.questData.questTitle}");
- if (selectedQuest?.questData == quest.questData)
- selectedQuest = null;
- RefreshQuestList();
- }
- private void HandleQuestProgress(ActiveQuest quest, int objectiveIndex, int newProgress)
- {
- // Update the specific quest entry
- RefreshQuestList();
- // Show progress notification if objective completed
- if (quest.questData.objectives[objectiveIndex].targetAmount <= newProgress)
- {
- ShowProgressNotification(quest, objectiveIndex);
- }
- }
- #endregion
- #region Notifications
- private void ShowCompletionNotification(ActiveQuest quest, List<QuestReward> rewards)
- {
- if (completionNotification == null) return;
- var content = completionNotification.Q<VisualElement>("notification-content");
- if (content == null) return;
- content.Clear();
- var icon = new Label("✅");
- icon.AddToClassList("completion-icon");
- content.Add(icon);
- var title = new Label("Quest Completed!");
- title.AddToClassList("completion-title");
- content.Add(title);
- var questTitle = new Label(quest.questData.questTitle);
- questTitle.AddToClassList("completed-quest-title");
- content.Add(questTitle);
- var rewardsText = new Label("Rewards: " + GetRewardsText(rewards));
- rewardsText.AddToClassList("completion-rewards");
- content.Add(rewardsText);
- if (completionNotification != null)
- completionNotification.style.display = DisplayStyle.Flex;
- // Auto-hide after 5 seconds
- StartCoroutine(HideNotificationAfterDelay(completionNotification, 5f));
- }
- private void ShowProgressNotification(ActiveQuest quest, int objectiveIndex)
- {
- if (progressNotification == null) return;
- var content = progressNotification.Q<VisualElement>("progress-notification-content");
- if (content == null) return;
- content.Clear();
- var icon = new Label("🎯");
- icon.AddToClassList("progress-icon");
- content.Add(icon);
- var title = new Label("Objective Complete!");
- title.AddToClassList("progress-title");
- content.Add(title);
- var objective = new Label(quest.questData.objectives[objectiveIndex].description);
- objective.AddToClassList("completed-objective");
- content.Add(objective);
- if (progressNotification != null)
- progressNotification.style.display = DisplayStyle.Flex;
- // Auto-hide after 3 seconds
- StartCoroutine(HideNotificationAfterDelay(progressNotification, 3f));
- }
- private IEnumerator HideNotificationAfterDelay(VisualElement notification, float delay)
- {
- yield return new WaitForSeconds(delay);
- if (notification != null)
- notification.style.display = DisplayStyle.None;
- }
- private string GetRewardsText(List<QuestReward> rewards)
- {
- var rewardTexts = new List<string>();
- foreach (var reward in rewards)
- {
- switch (reward.type)
- {
- case QuestRewardType.Gold:
- rewardTexts.Add($"{reward.amount} Gold");
- break;
- case QuestRewardType.Renown:
- rewardTexts.Add($"{reward.amount} Renown");
- break;
- case QuestRewardType.Item:
- if (reward.item != null)
- rewardTexts.Add(reward.item.name);
- break;
- }
- }
- return string.Join(", ", rewardTexts);
- }
- internal bool IsPointWithinUI(Vector2 screenPosition)
- {
- if (questTracker == null)
- {
- return false;
- }
- // Convert screen position to panel-relative position
- Vector2 panelPosition = RuntimePanelUtils.ScreenToPanel(questTracker.panel, screenPosition);
- // Check if the position is within the panel bounds
- bool withinBounds = questTracker.worldBound.Contains(panelPosition);
- return withinBounds;
- }
- #endregion
- }
|