using System.Collections.Generic; using System.Linq; using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Components; using Dalamud.Interface.Utility.Raii; using Dalamud.Plugin.Services; using Microsoft.Extensions.Logging; using Questionable.Controller; using Questionable.Data; using Questionable.Functions; using Questionable.Model; using Questionable.Model.Questing; namespace Questionable.Windows.JournalComponents; internal sealed class QuestJournalUtils { private readonly QuestController _questController; private readonly QuestFunctions _questFunctions; private readonly QuestData _questData; private readonly QuestRegistry _questRegistry; private readonly ICommandManager _commandManager; private readonly IChatGui _chatGui; private readonly ILogger _logger; public QuestJournalUtils(QuestController questController, QuestFunctions questFunctions, QuestData questData, QuestRegistry questRegistry, ICommandManager commandManager, IChatGui chatGui, ILogger logger) { _questController = questController; _questFunctions = questFunctions; _questData = questData; _questRegistry = questRegistry; _commandManager = commandManager; _chatGui = chatGui; _logger = logger; } public void ShowContextMenu(IQuestInfo questInfo, Quest? quest, string label) { ImU8String strId; if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) { strId = new ImU8String(12, 1); strId.AppendLiteral("##QuestPopup"); strId.AppendFormatted(questInfo.QuestId); ImGui.OpenPopup(strId); } strId = new ImU8String(12, 1); strId.AppendLiteral("##QuestPopup"); strId.AppendFormatted(questInfo.QuestId); using ImRaii.IEndObject endObject = ImRaii.Popup(strId); if (!endObject) { return; } bool flag = _questFunctions.IsQuestComplete(questInfo.QuestId); bool flag2 = _questFunctions.IsQuestAccepted(questInfo.QuestId); bool flag3 = _questFunctions.IsReadyToAcceptQuest(questInfo.QuestId); using (ImRaii.Disabled(quest == null || flag || (!flag3 && !flag2))) { if (ImGui.MenuItem("Start as next quest")) { if (quest == null) { return; } if (flag2) { QuestProgressInfo questProgressInfo = _questFunctions.GetQuestProgressInfo(questInfo.QuestId); if (questProgressInfo != null) { _questController.SetStartedQuest(quest, questProgressInfo.Sequence); _questController.Start(label); } } else { _questController.SetNextQuest(quest); _questController.Start(label); } } } List incompletePrerequisiteQuests = GetIncompletePrerequisiteQuests(questInfo); using (ImRaii.Disabled(incompletePrerequisiteQuests.Count == 0)) { if (ImGui.MenuItem(incompletePrerequisiteQuests.Count switch { 0 => "Add quest and requirements to priority", 1 => "Add 1 quest to priority", _ => $"Add {incompletePrerequisiteQuests.Count} quests to priority", })) { AddRequiredQuestsToPriority(questInfo, incompletePrerequisiteQuests); } } if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) { if (incompletePrerequisiteQuests.Count == 0) { ImGui.SetTooltip("No quests to add (quest may be complete or already in priority)"); } else { ImGui.SetTooltip((incompletePrerequisiteQuests.Count == 1) ? "Add this quest to the priority list" : $"Add this quest and {incompletePrerequisiteQuests.Count - 1} required quest(s) to the priority list in completion order"); } } bool flag4 = _commandManager.Commands.ContainsKey("/questinfo"); using (ImRaii.Disabled(!(questInfo.QuestId is QuestId) || !flag4)) { if (ImGui.MenuItem("View in Quest Map")) { _commandManager.ProcessCommand($"/questinfo {questInfo.QuestId}"); } } } private List GetIncompletePrerequisiteQuests(IQuestInfo questInfo) { List list = new List(); HashSet visited = new HashSet(); CollectPrerequisitesRecursive(questInfo, list, visited); list.Reverse(); List list2 = (from qId in list where !_questFunctions.IsQuestComplete(qId) where !_questFunctions.IsQuestUnobtainable(qId) where _questRegistry.IsKnownQuest(qId) where !_questController.ManualPriorityQuests.Any((Quest q) => q.Id.Equals(qId)) select qId).ToList(); list2.Reverse(); if (!_questFunctions.IsQuestComplete(questInfo.QuestId) && !_questFunctions.IsQuestUnobtainable(questInfo.QuestId) && _questRegistry.IsKnownQuest(questInfo.QuestId) && !_questController.ManualPriorityQuests.Any((Quest q) => q.Id.Equals(questInfo.QuestId))) { list2.Add(questInfo.QuestId); } return list2; } private void CollectPrerequisitesRecursive(IQuestInfo questInfo, List prerequisites, HashSet visited) { if (visited.Contains(questInfo.QuestId)) { return; } visited.Add(questInfo.QuestId); if (questInfo.PreviousQuests.Count <= 0) { return; } if (questInfo.PreviousQuestJoin == EQuestJoin.All) { foreach (PreviousQuestInfo previousQuest in questInfo.PreviousQuests) { if (_questData.TryGetQuestInfo(previousQuest.QuestId, out IQuestInfo questInfo2)) { CollectPrerequisitesRecursive(questInfo2, prerequisites, visited); if (!prerequisites.Contains(previousQuest.QuestId)) { prerequisites.Add(previousQuest.QuestId); } } } return; } if (questInfo.PreviousQuestJoin != EQuestJoin.AtLeastOne) { return; } foreach (PreviousQuestInfo previousQuest2 in questInfo.PreviousQuests) { if (_questFunctions.IsQuestComplete(previousQuest2.QuestId)) { continue; } if (_questData.TryGetQuestInfo(previousQuest2.QuestId, out IQuestInfo questInfo3)) { CollectPrerequisitesRecursive(questInfo3, prerequisites, visited); if (!prerequisites.Contains(previousQuest2.QuestId)) { prerequisites.Add(previousQuest2.QuestId); } } break; } } private void AddRequiredQuestsToPriority(IQuestInfo questInfo, List prerequisiteQuests) { int num = 0; foreach (ElementId prerequisiteQuest in prerequisiteQuests) { if (_questController.AddQuestPriority(prerequisiteQuest)) { num++; } } if (num > 0) { string text = ((num == 1) ? "quest" : "quests"); _logger.LogInformation("Added {Count} {QuestWord} for '{QuestName}' to priority list", num, text, questInfo.Name); _chatGui.Print($"Added {num} {text} to priority list.", "Questionable", 576); } else { _logger.LogWarning("No quests were added to priority list for '{QuestName}'", questInfo.Name); _chatGui.Print("No quests to add (may be complete or already in priority).", "Questionable", 576); } } internal static void ShowFilterContextMenu(QuestJournalComponent journalUi) { if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Filter, "Filter")) { ImGui.OpenPopup("##QuestFilters"); } using ImRaii.IEndObject endObject = ImRaii.Popup("##QuestFilters"); if (!(!endObject) && (ImGui.Checkbox("Show only Available Quests", ref journalUi.Filter.AvailableOnly) || ImGui.Checkbox("Hide Quests Without Path", ref journalUi.Filter.HideNoPaths) || ImGui.Checkbox("Hide Unobtainable Quests", ref journalUi.Filter.HideUnobtainable))) { journalUi.UpdateFilter(); } } }