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 FFXIVClientStructs.FFXIV.Client.Game; 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; } using (ImRaii.Disabled(!_questFunctions.IsReadyToAcceptQuest(questInfo.QuestId) || quest == null || quest.Root.Disabled)) { if (ImGui.MenuItem("Start as next quest")) { _questController.SetNextQuest(quest); _questController.Start(label); } } if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) { if (!_questFunctions.IsReadyToAcceptQuest(questInfo.QuestId)) { ImGui.SetTooltip("Quest is not ready to accept"); } else if (quest == null) { ImGui.SetTooltip("Quest has no path available"); } else if (quest.Root.Disabled) { ImGui.SetTooltip("Quest path is disabled"); } } 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, disabled, locked with no unlock path, 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 flag = _commandManager.Commands.ContainsKey("/questinfo"); using (ImRaii.Disabled(!(questInfo.QuestId is QuestId) || !flag)) { if (ImGui.MenuItem("View in Quest Map")) { _commandManager.ProcessCommand($"/questinfo {questInfo.QuestId}"); } } } private unsafe List GetIncompletePrerequisiteQuests(IQuestInfo questInfo) { List list = new List(); HashSet visited = new HashSet(); CollectPrerequisitesRecursive(questInfo, list, visited); list.Reverse(); Quest quest2; List list2 = (from qId in list.Where(delegate(ElementId qId) { if (!_questData.TryGetQuestInfo(qId, out IQuestInfo questInfo2)) { return false; } if (questInfo2.IsRepeatable && qId is QuestId questId2) { if (QuestManager.Instance()->IsDailyQuestCompleted(questId2.Value)) { return false; } } else if (_questFunctions.IsQuestComplete(qId)) { return false; } return true; }) where !_questFunctions.IsQuestUnobtainable(qId) where _questRegistry.IsKnownQuest(qId) where (!_questRegistry.TryGetQuest(qId, out quest2) || !quest2.Root.Disabled) ? true : false where !_questController.ManualPriorityQuests.Any((Quest q) => q.Id.Equals(qId)) select qId).ToList(); list2.Reverse(); bool flag = false; flag = ((!questInfo.IsRepeatable || !(questInfo.QuestId is QuestId questId)) ? (!_questFunctions.IsQuestComplete(questInfo.QuestId)) : (!QuestManager.Instance()->IsDailyQuestCompleted(questId.Value))); Quest quest; bool flag2 = _questRegistry.TryGetQuest(questInfo.QuestId, out quest) && quest.Root.Disabled; bool flag3 = _questFunctions.IsQuestLocked(questInfo.QuestId) && questInfo.PreviousQuests.Count == 0; if (flag && !flag2 && !flag3 && !_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, disabled, locked with no unlock path, or already in priority).", "Questionable", 576); } } internal static void ShowFilterContextMenu(QuestJournalComponent journalUi) { if (ImGuiComponents.IconButton(FontAwesomeIcon.Filter)) { ImGui.OpenPopup("QuestFilters"); } if (ImGui.IsItemHovered()) { ImGui.SetTooltip("Filter Options"); } using ImRaii.IEndObject endObject = ImRaii.Popup("QuestFilters"); if (!ImRaii.IEndObject.op_True(endObject)) { return; } if ((0u | (ImGui.Checkbox("Available Only", ref journalUi.Filter.AvailableOnly) ? 1u : 0u) | (ImGui.Checkbox("Hide Without Quest Paths", ref journalUi.Filter.HideNoPaths) ? 1u : 0u) | (ImGui.Checkbox("Hide Unobtainable", ref journalUi.Filter.HideUnobtainable) ? 1u : 0u)) != 0) { journalUi.UpdateFilter(); } if (journalUi.Filter.AdvancedFiltersActive) { ImGui.Separator(); if (ImGui.Button("Clear Filters")) { journalUi.Filter.AvailableOnly = false; journalUi.Filter.HideNoPaths = false; journalUi.Filter.HideUnobtainable = false; journalUi.UpdateFilter(); } } } public void AddAllAvailableQuests() { int num = _questRegistry.AllQuests.Count(delegate(Quest quest) { if (!quest.Root.Disabled && !_questFunctions.IsQuestRemoved(quest.Id) && _questFunctions.IsReadyToAcceptQuest(quest.Id) && !_questFunctions.IsQuestComplete(quest.Id) && !_questFunctions.IsQuestAccepted(quest.Id) && !_questController.ManualPriorityQuests.Any((Quest q) => q.Id.Equals(quest.Id))) { QuestSequence? questSequence = quest.FindSequence(0); if (questSequence == null) { return false; } return questSequence.Steps.FirstOrDefault()?.IsTeleportableForPriorityQuests() == true; } return false; }); using (ImRaii.Disabled(num == 0)) { if (ImGuiComponents.IconButton(FontAwesomeIcon.ListOl)) { int num2 = _questController.AddAllAvailableQuests(); string value = ((num2 == 1) ? "quest" : "quests"); _chatGui.Print($"Added {num2} {value} to priority queue.", "Questionable", 576); } } if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) { object obj; switch (num) { case 0: ImGui.SetTooltip("No available quests to add"); return; default: obj = "quests"; break; case 1: obj = "quest"; break; } string value2 = (string)obj; ImU8String tooltip = new ImU8String(27, 2); tooltip.AppendLiteral("Add "); tooltip.AppendFormatted(num); tooltip.AppendLiteral(" available "); tooltip.AppendFormatted(value2); tooltip.AppendLiteral(" to priority"); ImGui.SetTooltip(tooltip); } } }