| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690 |
- using UnityEngine;
- using UnityEngine.UIElements;
- using System.Collections.Generic;
- using System.Linq;
- /// <summary>
- /// UI controller for the Adventurer's Guild interface
- /// </summary>
- public class AdventurersGuildUI : MonoBehaviour
- {
- [Header("UI References")]
- [SerializeField] private UIDocument uiDocument;
- [Header("Guild Reference")]
- [SerializeField] private AdventurersGuild guild;
- private VisualElement root;
- private VisualElement questBoardPanel;
- private VisualElement activeQuestsPanel;
- private VisualElement questHistoryPanel;
- private VisualElement questDetailsPanel;
- private ScrollView questBoardList;
- private ScrollView activeQuestsList;
- private ScrollView questHistoryList;
- private Button questBoardTab;
- private Button activeQuestsTab;
- private Button questHistoryTab;
- private Label renownLabel;
- private Label questCountLabel;
- private Label historyStatsLabel;
- private Quest selectedQuest;
- private ActiveQuest selectedActiveQuest;
- private void Start()
- {
- InitializeUI();
- SetupEventListeners();
- ShowQuestBoard();
- }
- private void OnEnable()
- {
- if (QuestManager.Instance != null)
- {
- QuestManager.Instance.OnQuestAccepted += OnQuestAccepted;
- QuestManager.Instance.OnQuestCompleted += OnQuestCompleted;
- QuestManager.Instance.OnQuestFailed += OnQuestFailed;
- QuestManager.Instance.OnRenownChanged += OnRenownChanged;
- }
- }
- private void OnDisable()
- {
- if (QuestManager.Instance != null)
- {
- QuestManager.Instance.OnQuestAccepted -= OnQuestAccepted;
- QuestManager.Instance.OnQuestCompleted -= OnQuestCompleted;
- QuestManager.Instance.OnQuestFailed -= OnQuestFailed;
- QuestManager.Instance.OnRenownChanged -= OnRenownChanged;
- }
- }
- private void InitializeUI()
- {
- if (uiDocument == null)
- uiDocument = GetComponent<UIDocument>();
- root = uiDocument.rootVisualElement;
- // Get panel references
- questBoardPanel = root.Q("QuestBoardPanel");
- activeQuestsPanel = root.Q("ActiveQuestsPanel");
- questHistoryPanel = root.Q("QuestHistoryPanel");
- questDetailsPanel = root.Q("QuestDetailsPanel");
- // Get list references
- questBoardList = root.Q<ScrollView>("QuestBoardList");
- activeQuestsList = root.Q<ScrollView>("ActiveQuestsList");
- questHistoryList = root.Q<ScrollView>("QuestHistoryList");
- // Get tab references
- questBoardTab = root.Q<Button>("QuestBoardTab");
- activeQuestsTab = root.Q<Button>("ActiveQuestsTab");
- questHistoryTab = root.Q<Button>("QuestHistoryTab");
- // Get label references
- renownLabel = root.Q<Label>("RenownLabel");
- questCountLabel = root.Q<Label>("QuestCountLabel");
- historyStatsLabel = root.Q<Label>("HistoryStatsLabel");
- // Find guild if not assigned
- if (guild == null)
- guild = FindFirstObjectByType<AdventurersGuild>();
- UpdateRenownDisplay();
- }
- private void SetupEventListeners()
- {
- // Tab navigation
- questBoardTab?.RegisterCallback<ClickEvent>(evt => ShowTab("QuestBoard"));
- activeQuestsTab?.RegisterCallback<ClickEvent>(evt => ShowTab("ActiveQuests"));
- questHistoryTab?.RegisterCallback<ClickEvent>(evt => ShowTab("QuestHistory"));
- // Close button
- var closeButton = root.Q<Button>("CloseButton");
- closeButton?.RegisterCallback<ClickEvent>(evt => CloseGuild());
- // Action buttons
- var refreshButton = root.Q<Button>("RefreshBoardButton");
- refreshButton?.RegisterCallback<ClickEvent>(evt =>
- {
- // Refresh the guild board first, then the UI
- if (guild != null)
- {
- guild.RefreshQuestBoard();
- }
- RefreshQuestBoard();
- });
- var acceptButton = root.Q<Button>("AcceptQuestButton");
- acceptButton?.RegisterCallback<ClickEvent>(evt => AcceptSelectedQuest());
- var abandonButton = root.Q<Button>("AbandonQuestButton");
- abandonButton?.RegisterCallback<ClickEvent>(evt => AbandonSelectedQuest());
- }
- private void ShowTab(string tabName)
- {
- // Hide all panels
- questBoardPanel.AddToClassList("hidden");
- activeQuestsPanel.AddToClassList("hidden");
- questHistoryPanel.AddToClassList("hidden");
- // Remove active class from all tabs
- questBoardTab.RemoveFromClassList("active-tab");
- activeQuestsTab.RemoveFromClassList("active-tab");
- questHistoryTab.RemoveFromClassList("active-tab");
- // Show selected panel and mark tab as active
- switch (tabName)
- {
- case "QuestBoard":
- questBoardPanel.RemoveFromClassList("hidden");
- questBoardTab.AddToClassList("active-tab");
- RefreshQuestBoard();
- break;
- case "ActiveQuests":
- activeQuestsPanel.RemoveFromClassList("hidden");
- activeQuestsTab.AddToClassList("active-tab");
- RefreshActiveQuests();
- break;
- case "QuestHistory":
- questHistoryPanel.RemoveFromClassList("hidden");
- questHistoryTab.AddToClassList("active-tab");
- RefreshQuestHistory();
- break;
- }
- CloseQuestDetails();
- }
- private void RefreshQuestBoard()
- {
- if (guild == null || questBoardList == null) return;
- questBoardList.Clear();
- var questBoard = guild.GetQuestBoard();
- if (questBoard.Count == 0)
- {
- // Try to refresh the board first
- guild.RefreshQuestBoard();
- questBoard = guild.GetQuestBoard();
-
- if (questBoard.Count == 0)
- {
- var placeholder = new Label("No quests available. Check back later!");
- placeholder.AddToClassList("placeholder-text");
- questBoardList.Add(placeholder);
-
- // Add a button to create a test quest for debugging
- var debugButton = new Button(() => CreateDebugQuest()) { text = "🔧 Create Test Quest (Debug)" };
- debugButton.AddToClassList("debug-button");
- questBoardList.Add(debugButton);
- return;
- }
- }
- // Add helpful instructions at the top
- if (questBoard.Count > 0)
- {
- var instructions = new Label("💡 Click on any quest below to view details and accept it!");
- instructions.AddToClassList("instructions-text");
- questBoardList.Add(instructions);
- }
- foreach (var quest in questBoard)
- {
- var questEntry = CreateQuestEntry(quest);
- questBoardList.Add(questEntry);
- }
- } private void CreateDebugQuest()
- {
- if (guild == null) return;
- var debugQuest = ScriptableObject.CreateInstance<Quest>();
- debugQuest.questTitle = "Test Quest - Goblin Patrol";
- debugQuest.questDescription = "A group of goblins has been spotted near the village. Clear them out to protect the trade routes.";
- debugQuest.questType = QuestType.Combat;
- debugQuest.difficulty = QuestDifficulty.Easy;
- debugQuest.timeLimitDays = 7;
- debugQuest.targetAreaName = "Forest Edge";
- debugQuest.targetMapPosition = new Vector2Int(45, 55);
- debugQuest.goldReward = 75;
- debugQuest.renownReward = 10;
- debugQuest.minimumRenown = 0; // No requirements for testing
- debugQuest.goals.Add(new QuestGoal
- {
- description = "Defeat 5 Goblins",
- goalType = QuestGoalType.KillEnemies,
- targetName = "Goblin",
- targetCount = 5
- });
- // Add to guild's available quests and refresh
- var availableQuests = new System.Collections.Generic.List<Quest>();
- var currentBoard = guild.GetQuestBoard();
- availableQuests.AddRange(currentBoard);
- availableQuests.Add(debugQuest);
- // Use reflection or a public method to add the quest
- // For now, just force it into the board via the guild's debug method
- Debug.Log("✅ Created debug quest. Use the guild's 'Create Simple Test Quest' context menu to add it properly.");
- // Refresh the UI
- RefreshQuestBoard();
- }
- private void RefreshActiveQuests()
- {
- if (QuestManager.Instance == null || activeQuestsList == null) return;
- activeQuestsList.Clear();
- var activeQuests = QuestManager.Instance.GetActiveQuests();
- questCountLabel.text = $"{activeQuests.Count}/{QuestManager.Instance.maxActiveQuests} Quests";
- if (activeQuests.Count == 0)
- {
- var placeholder = new Label("No active quests.");
- placeholder.AddToClassList("placeholder-text");
- activeQuestsList.Add(placeholder);
- return;
- }
- foreach (var activeQuest in activeQuests)
- {
- var questEntry = CreateActiveQuestEntry(activeQuest);
- activeQuestsList.Add(questEntry);
- }
- }
- private void RefreshQuestHistory()
- {
- // TODO: Implement quest history display
- questHistoryList.Clear();
- var placeholder = new Label("Quest history not yet implemented.");
- placeholder.AddToClassList("placeholder-text");
- questHistoryList.Add(placeholder);
- historyStatsLabel.text = "Completed: 0 | Failed: 0";
- }
- private VisualElement CreateQuestEntry(Quest quest)
- {
- var entry = new VisualElement();
- entry.AddToClassList("quest-list-item");
- entry.AddToClassList("clickable-quest"); // New class for better styling
-
- // Add a hover effect to make it clear it's clickable
- entry.RegisterCallback<MouseEnterEvent>(evt => entry.AddToClassList("quest-hover"));
- entry.RegisterCallback<MouseLeaveEvent>(evt => entry.RemoveFromClassList("quest-hover"));
- // Header with title and difficulty badge
- var header = new VisualElement();
- header.AddToClassList("quest-item-header");
- var titleContainer = new VisualElement();
- titleContainer.AddToClassList("quest-title-container");
-
- var title = new Label(quest.questTitle);
- title.AddToClassList("quest-item-title");
-
- var clickHint = new Label("📋 Click to view details");
- clickHint.AddToClassList("quest-click-hint");
-
- titleContainer.Add(title);
- titleContainer.Add(clickHint);
- var difficulty = new Label(quest.difficulty.ToString().ToUpper());
- difficulty.AddToClassList("quest-item-difficulty");
- difficulty.AddToClassList($"difficulty-{quest.difficulty.ToString().ToLower()}");
- header.Add(titleContainer);
- header.Add(difficulty);
- // Description (truncated)
- var description = new Label(TruncateText(quest.questDescription, 100));
- description.AddToClassList("quest-item-description");
- // Key info row
- var infoRow = new VisualElement();
- infoRow.AddToClassList("quest-info-row");
-
- var location = new Label($"📍 {quest.targetAreaName}");
- location.AddToClassList("quest-info-item");
-
- var timeLimit = new Label($"⏰ {quest.timeLimitDays}d {quest.timeLimitHours}h");
- timeLimit.AddToClassList("quest-info-item");
-
- infoRow.Add(location);
- infoRow.Add(timeLimit);
- // Rewards container - made more prominent
- var rewardsContainer = new VisualElement();
- rewardsContainer.AddToClassList("quest-item-rewards");
-
- var rewardsLabel = new Label("Rewards:");
- rewardsLabel.AddToClassList("rewards-label");
- rewardsContainer.Add(rewardsLabel);
-
- var rewardsContent = new VisualElement();
- rewardsContent.AddToClassList("rewards-content");
- if (quest.goldReward > 0)
- {
- var goldReward = new Label($"💰 {quest.goldReward} Gold");
- goldReward.AddToClassList("quest-item-reward");
- goldReward.AddToClassList("reward-gold");
- rewardsContent.Add(goldReward);
- }
- if (quest.renownReward > 0)
- {
- var renownReward = new Label($"⭐ +{quest.renownReward} Renown");
- renownReward.AddToClassList("quest-item-reward");
- renownReward.AddToClassList("reward-renown");
- rewardsContent.Add(renownReward);
- }
-
- rewardsContainer.Add(rewardsContent);
- // Requirements
- if (quest.minimumRenown > 0)
- {
- var requirements = new Label($"⚡ Requires {quest.minimumRenown} Renown");
- requirements.AddToClassList("quest-requirements");
- rewardsContainer.Add(requirements);
- }
- // Assemble the entry
- entry.Add(header);
- entry.Add(description);
- entry.Add(infoRow);
- entry.Add(rewardsContainer);
- // Click handler to select quest and show details
- entry.RegisterCallback<ClickEvent>(evt =>
- {
- // Remove selection from all quest items
- foreach (var child in questBoardList.Children())
- {
- child.RemoveFromClassList("selected");
- }
- // Select this item
- entry.AddToClassList("selected");
- ShowQuestDetails(quest);
- });
- return entry;
- }
-
- private string TruncateText(string text, int maxLength)
- {
- if (string.IsNullOrEmpty(text) || text.Length <= maxLength)
- return text;
-
- return text.Substring(0, maxLength - 3) + "...";
- }
- private VisualElement CreateActiveQuestEntry(ActiveQuest activeQuest)
- {
- var entry = CreateQuestEntry(activeQuest.questData);
- // Add urgency indicator
- var urgency = activeQuest.GetUrgency();
- entry.AddToClassList($"urgency-{urgency.ToString().ToLower()}");
- // Update time display to show remaining time
- var timeLabel = entry.Q<Label>(className: "quest-entry-time");
- if (timeLabel != null)
- {
- timeLabel.text = $"⏰ {activeQuest.GetTimeRemainingString()}";
- }
- // Add progress info
- var progressLabel = new Label($"Progress: {activeQuest.GetOverallProgress() * 100:F0}%");
- progressLabel.style.color = Color.cyan;
- progressLabel.style.fontSize = 12;
- entry.Add(progressLabel);
- // Click handler for active quest
- entry.RegisterCallback<ClickEvent>(evt => ShowActiveQuestDetails(activeQuest));
- return entry;
- }
- private void ShowQuestDetails(Quest quest)
- {
- selectedQuest = quest;
- selectedActiveQuest = null;
- // Show quest info container and hide placeholder
- var questInfoContainer = root.Q("QuestInfoContainer");
- var placeholder = root.Q("QuestDetailsText");
- questInfoContainer?.RemoveFromClassList("hidden");
- placeholder?.AddToClassList("hidden");
- // Populate the details with null checks
- try
- {
- PopulateQuestDetails(quest);
- }
- catch (System.Exception ex)
- {
- Debug.LogError($"Error populating quest details: {ex.Message}");
-
- // Fallback - show basic info
- var title = root.Q<Label>("QuestTitle");
- if (title != null) title.text = quest?.questTitle ?? "Unknown Quest";
-
- var description = root.Q<Label>("QuestDescription");
- if (description != null) description.text = quest?.questDescription ?? "Quest details unavailable.";
- }
- // Show/hide appropriate buttons
- var acceptButton = root.Q<Button>("AcceptQuestButton");
- var abandonButton = root.Q<Button>("AbandonQuestButton");
- if (acceptButton != null)
- {
- acceptButton.RemoveFromClassList("hidden");
- acceptButton.AddToClassList("accept-button");
- acceptButton.AddToClassList("action-button");
- }
-
- if (abandonButton != null)
- {
- abandonButton.AddToClassList("hidden");
- }
- }
- private void CloseGuild()
- {
- // Destroy the guild UI GameObject
- if (gameObject != null)
- {
- Destroy(gameObject);
- }
- }
- private void ShowActiveQuestDetails(ActiveQuest activeQuest)
- {
- selectedQuest = null;
- selectedActiveQuest = activeQuest;
- questDetailsPanel.RemoveFromClassList("hidden");
- PopulateQuestDetails(activeQuest.questData, activeQuest);
- // Show/hide appropriate buttons
- root.Q<Button>("AcceptQuestButton").AddToClassList("hidden");
- root.Q<Button>("AbandonQuestButton").RemoveFromClassList("hidden");
- root.Q<Button>("TrackQuestButton").RemoveFromClassList("hidden");
- }
- private void PopulateQuestDetails(Quest quest, ActiveQuest activeQuest = null)
- {
- if (quest == null) return;
- // Basic info - with null checks
- var questTitle = root.Q<Label>("QuestTitle");
- if (questTitle != null) questTitle.text = quest.questTitle;
-
- var questDifficulty = root.Q<Label>("QuestDifficulty");
- if (questDifficulty != null) questDifficulty.text = $"Difficulty: {quest.difficulty}";
- var questTimeLimit = root.Q<Label>("QuestTimeLimit");
- if (questTimeLimit != null)
- {
- if (activeQuest != null)
- {
- questTimeLimit.text = $"Time Remaining: {activeQuest.GetTimeRemainingString()}";
- }
- else
- {
- questTimeLimit.text = $"Time Limit: {quest.timeLimitDays}d {quest.timeLimitHours}h";
- }
- }
- // Description
- var questDescription = root.Q<Label>("QuestDescription");
- if (questDescription != null) questDescription.text = quest.questDescription;
- // Objectives
- var objectivesList = root.Q("ObjectivesList");
- if (objectivesList != null)
- {
- objectivesList.Clear();
- var goalsToShow = activeQuest?.activeGoals ?? quest.goals;
- foreach (var goal in goalsToShow)
- {
- if (goal.isHidden && activeQuest == null) continue;
- var objectiveItem = new VisualElement();
- objectiveItem.AddToClassList("objective-item");
- var status = new VisualElement();
- status.AddToClassList("objective-status");
- if (goal.IsCompleted)
- status.AddToClassList("objective-completed");
- var text = new Label(goal.description);
- text.AddToClassList("objective-text");
- if (activeQuest != null)
- {
- text.text += $" ({goal.currentProgress}/{goal.targetCount})";
- }
- objectiveItem.Add(status);
- objectiveItem.Add(text);
- objectivesList.Add(objectiveItem);
- }
- }
- // Location
- var questLocation = root.Q<Label>("QuestLocation");
- if (questLocation != null) questLocation.text = $"Target Area: {quest.targetAreaName}";
- // Calculate travel time if we have current position
- var travelTime = quest.CalculateTravelTime(new Vector2Int(50, 50)); // Placeholder position
- var travelTimeLabel = root.Q<Label>("TravelTime");
- if (travelTimeLabel != null) travelTimeLabel.text = $"Travel Time: ~{travelTime:F1} hours";
- // Rewards
- var goldReward = root.Q<Label>("GoldReward");
- if (goldReward != null) goldReward.text = $"💰 Gold: {quest.goldReward}";
-
- var renownReward = root.Q<Label>("RenownReward");
- if (renownReward != null) renownReward.text = $"⭐ Renown: +{quest.renownReward}";
- var itemRewardsList = root.Q("ItemRewardsList");
- if (itemRewardsList != null)
- {
- itemRewardsList.Clear();
- foreach (var itemName in quest.itemRewards)
- {
- var itemLabel = new Label($"🎁 {itemName}");
- itemLabel.AddToClassList("reward-item");
- itemRewardsList.Add(itemLabel);
- }
- }
- }
- private void CloseQuestDetails()
- {
- questDetailsPanel.AddToClassList("hidden");
- selectedQuest = null;
- selectedActiveQuest = null;
- }
- private void AcceptSelectedQuest()
- {
- if (selectedQuest == null || guild == null) return;
- bool accepted = guild.AcceptQuest(selectedQuest);
- if (accepted)
- {
- CloseQuestDetails();
- RefreshQuestBoard();
- ShowTab("ActiveQuests");
- }
- }
- private void AbandonSelectedQuest()
- {
- if (selectedActiveQuest == null || QuestManager.Instance == null) return;
- bool abandoned = QuestManager.Instance.AbandonQuest(selectedActiveQuest.questId);
- if (abandoned)
- {
- CloseQuestDetails();
- RefreshActiveQuests();
- }
- }
- private void TrackSelectedQuest()
- {
- if (selectedActiveQuest == null) return;
- // TODO: Implement quest tracking on map
- Debug.Log($"Tracking quest: {selectedActiveQuest.questData.questTitle}");
- CloseQuestDetails();
- }
- private void UpdateRenownDisplay()
- {
- if (renownLabel != null && QuestManager.Instance != null)
- {
- renownLabel.text = $"Renown: {QuestManager.Instance.GetRenown()}";
- }
- }
- private void ShowQuestBoard()
- {
- ShowTab("QuestBoard");
- }
- // Event handlers
- private void OnQuestAccepted(ActiveQuest quest)
- {
- RefreshQuestBoard();
- RefreshActiveQuests();
- }
- private void OnQuestCompleted(ActiveQuest quest, List<QuestReward> rewards)
- {
- RefreshActiveQuests();
- RefreshQuestHistory();
- }
- private void OnQuestFailed(ActiveQuest quest)
- {
- RefreshActiveQuests();
- RefreshQuestHistory();
- }
- private void OnRenownChanged(int newRenown)
- {
- UpdateRenownDisplay();
- }
- // Debug methods
- [ContextMenu("Force Refresh UI")]
- private void DebugForceRefreshUI()
- {
- if (guild != null)
- {
- guild.RefreshQuestBoard();
- }
- RefreshQuestBoard();
- RefreshActiveQuests();
- RefreshQuestHistory();
- Debug.Log("🔄 Forced UI refresh complete");
- }
- [ContextMenu("Debug Guild Connection")]
- private void DebugGuildConnection()
- {
- Debug.Log($"Guild reference: {(guild != null ? "✅ Found" : "❌ NULL")}");
- Debug.Log($"QuestManager: {(QuestManager.Instance != null ? "✅ Found" : "❌ NULL")}");
- if (guild != null)
- {
- var questBoard = guild.GetQuestBoard();
- Debug.Log($"Quest Board: {questBoard.Count} quests");
- }
- }
- }
|