forked from liza/Questionable
Add quest priority window
This commit is contained in:
parent
581976b06b
commit
b4a649189a
@ -138,6 +138,8 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public QuestProgress? PendingQuest => _pendingQuest;
|
public QuestProgress? PendingQuest => _pendingQuest;
|
||||||
|
|
||||||
|
public List<Quest> ManualPriorityQuests { get; } = [];
|
||||||
|
|
||||||
public string? DebugState { get; private set; }
|
public string? DebugState { get; private set; }
|
||||||
|
|
||||||
public void Reload()
|
public void Reload()
|
||||||
@ -291,7 +293,13 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
(ElementId? currentQuestId, currentSequence) = _questFunctions.GetCurrentQuest();
|
(ElementId? currentQuestId, currentSequence) =
|
||||||
|
ManualPriorityQuests
|
||||||
|
.Where(x => _questFunctions.IsReadyToAcceptQuest(x.Id) || _questFunctions.IsQuestAccepted(x.Id))
|
||||||
|
.Select(x =>
|
||||||
|
((ElementId?, byte)?)(x.Id, _questFunctions.GetQuestProgressInfo(x.Id)?.Sequence ?? 0))
|
||||||
|
.FirstOrDefault() ??
|
||||||
|
_questFunctions.GetCurrentQuest();
|
||||||
if (currentQuestId == null || currentQuestId.Value == 0)
|
if (currentQuestId == null || currentQuestId.Value == 0)
|
||||||
{
|
{
|
||||||
if (_startedQuest != null)
|
if (_startedQuest != null)
|
||||||
|
@ -36,6 +36,7 @@ internal sealed class DalamudInitializer : IDisposable
|
|||||||
QuestSelectionWindow questSelectionWindow,
|
QuestSelectionWindow questSelectionWindow,
|
||||||
QuestValidationWindow questValidationWindow,
|
QuestValidationWindow questValidationWindow,
|
||||||
JournalProgressWindow journalProgressWindow,
|
JournalProgressWindow journalProgressWindow,
|
||||||
|
PriorityWindow priorityWindow,
|
||||||
IToastGui toastGui,
|
IToastGui toastGui,
|
||||||
ILogger<DalamudInitializer> logger)
|
ILogger<DalamudInitializer> logger)
|
||||||
{
|
{
|
||||||
@ -55,6 +56,7 @@ internal sealed class DalamudInitializer : IDisposable
|
|||||||
_windowSystem.AddWindow(questSelectionWindow);
|
_windowSystem.AddWindow(questSelectionWindow);
|
||||||
_windowSystem.AddWindow(questValidationWindow);
|
_windowSystem.AddWindow(questValidationWindow);
|
||||||
_windowSystem.AddWindow(journalProgressWindow);
|
_windowSystem.AddWindow(journalProgressWindow);
|
||||||
|
_windowSystem.AddWindow(priorityWindow);
|
||||||
|
|
||||||
_pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
|
_pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
|
||||||
_pluginInterface.UiBuilder.OpenMainUi += _questWindow.Toggle;
|
_pluginInterface.UiBuilder.OpenMainUi += _questWindow.Toggle;
|
||||||
|
@ -449,6 +449,18 @@ internal sealed unsafe class QuestFunctions
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool IsQuestLocked(QuestId questId, ElementId? extraCompletedQuest = null)
|
public bool IsQuestLocked(QuestId questId, ElementId? extraCompletedQuest = null)
|
||||||
|
{
|
||||||
|
if (IsQuestUnobtainable(questId, extraCompletedQuest))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
var questInfo = (QuestInfo)_questData.GetQuestInfo(questId);
|
||||||
|
if (questInfo.GrandCompany != GrandCompany.None && questInfo.GrandCompany != GetGrandCompany())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return !HasCompletedPreviousQuests(questInfo, extraCompletedQuest) || !HasCompletedPreviousInstances(questInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsQuestUnobtainable(QuestId questId, ElementId? extraCompletedQuest = null)
|
||||||
{
|
{
|
||||||
var questInfo = (QuestInfo)_questData.GetQuestInfo(questId);
|
var questInfo = (QuestInfo)_questData.GetQuestInfo(questId);
|
||||||
if (questInfo.QuestLocks.Count > 0)
|
if (questInfo.QuestLocks.Count > 0)
|
||||||
@ -460,13 +472,10 @@ internal sealed unsafe class QuestFunctions
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (questInfo.GrandCompany != GrandCompany.None && questInfo.GrandCompany != GetGrandCompany())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (_questData.GetLockedClassQuests().Contains(questId))
|
if (_questData.GetLockedClassQuests().Contains(questId))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return !HasCompletedPreviousQuests(questInfo, extraCompletedQuest) || !HasCompletedPreviousInstances(questInfo);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsQuestLocked(LeveId leveId)
|
public bool IsQuestLocked(LeveId leveId)
|
||||||
|
@ -208,6 +208,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
|
|||||||
serviceCollection.AddSingleton<QuestSelectionWindow>();
|
serviceCollection.AddSingleton<QuestSelectionWindow>();
|
||||||
serviceCollection.AddSingleton<QuestValidationWindow>();
|
serviceCollection.AddSingleton<QuestValidationWindow>();
|
||||||
serviceCollection.AddSingleton<JournalProgressWindow>();
|
serviceCollection.AddSingleton<JournalProgressWindow>();
|
||||||
|
serviceCollection.AddSingleton<PriorityWindow>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddQuestValidators(ServiceCollection serviceCollection)
|
private static void AddQuestValidators(ServiceCollection serviceCollection)
|
||||||
|
223
Questionable/Windows/PriorityWindow.cs
Normal file
223
Questionable/Windows/PriorityWindow.cs
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Colors;
|
||||||
|
using Dalamud.Interface.Components;
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
using ImGuiNET;
|
||||||
|
using LLib.ImGui;
|
||||||
|
using Questionable.Controller;
|
||||||
|
using Questionable.Functions;
|
||||||
|
using Questionable.Model;
|
||||||
|
using Questionable.Model.Questing;
|
||||||
|
using Questionable.Windows.QuestComponents;
|
||||||
|
|
||||||
|
namespace Questionable.Windows;
|
||||||
|
|
||||||
|
internal sealed class PriorityWindow : LWindow
|
||||||
|
{
|
||||||
|
private readonly QuestController _questController;
|
||||||
|
private readonly QuestRegistry _questRegistry;
|
||||||
|
private readonly QuestFunctions _questFunctions;
|
||||||
|
private readonly QuestTooltipComponent _questTooltipComponent;
|
||||||
|
private readonly UiUtils _uiUtils;
|
||||||
|
private readonly IDalamudPluginInterface _pluginInterface;
|
||||||
|
|
||||||
|
private string _searchString = string.Empty;
|
||||||
|
private ElementId? _draggedItem;
|
||||||
|
|
||||||
|
public PriorityWindow(QuestController questController, QuestRegistry questRegistry, QuestFunctions questFunctions,
|
||||||
|
QuestTooltipComponent questTooltipComponent, UiUtils uiUtils, IDalamudPluginInterface pluginInterface)
|
||||||
|
: base("Quest Priority###QuestionableQuestPriority")
|
||||||
|
{
|
||||||
|
_questController = questController;
|
||||||
|
_questRegistry = questRegistry;
|
||||||
|
_questFunctions = questFunctions;
|
||||||
|
_questTooltipComponent = questTooltipComponent;
|
||||||
|
_uiUtils = uiUtils;
|
||||||
|
_pluginInterface = pluginInterface;
|
||||||
|
|
||||||
|
Size = new Vector2(400, 400);
|
||||||
|
SizeCondition = ImGuiCond.Once;
|
||||||
|
SizeConstraints = new WindowSizeConstraints
|
||||||
|
{
|
||||||
|
MinimumSize = new Vector2(400, 400),
|
||||||
|
MaximumSize = new Vector2(400, 999)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Draw()
|
||||||
|
{
|
||||||
|
ImGui.Text("Quests to do first:");
|
||||||
|
DrawQuestFilter();
|
||||||
|
DrawQuestList();
|
||||||
|
ImGui.Spacing();
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
ImGui.Spacing();
|
||||||
|
ImGui.TextWrapped(
|
||||||
|
"If you have an active MSQ quest, Questionable will generally try to do:");
|
||||||
|
ImGui.BulletText("'Priority' quests: class quests, ARR primals, ARR raids");
|
||||||
|
ImGui.BulletText(
|
||||||
|
"Supported quests in your 'To-Do list'\n(quests from your Journal that are always on-screen)");
|
||||||
|
ImGui.BulletText("MSQ quest (if available, unless it is marked as 'ignored'\nin your Journal)");
|
||||||
|
ImGui.TextWrapped(
|
||||||
|
"If you don't have any active MSQ quest, it will always try to pick up the next quest in the MSQ first.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawQuestFilter()
|
||||||
|
{
|
||||||
|
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
|
||||||
|
if (ImGui.BeginCombo($"##QuestSelection", "Add Quest...", ImGuiComboFlags.HeightLarge))
|
||||||
|
{
|
||||||
|
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
|
||||||
|
bool addFirst = ImGui.InputTextWithHint("", "Filter...", ref _searchString, 256,
|
||||||
|
ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.EnterReturnsTrue);
|
||||||
|
|
||||||
|
IEnumerable<Quest> foundQuests;
|
||||||
|
if (!string.IsNullOrEmpty(_searchString))
|
||||||
|
{
|
||||||
|
foundQuests = _questRegistry.AllQuests
|
||||||
|
.Where(x => x.Info.Name.Contains(_searchString, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
.Where(x => x.Id is not QuestId questId || !_questFunctions.IsQuestUnobtainable(questId));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foundQuests = _questRegistry.AllQuests.Where(x => _questFunctions.IsQuestAccepted(x.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var quest in foundQuests)
|
||||||
|
{
|
||||||
|
if (quest.Info.IsMainScenarioQuest || _questController.ManualPriorityQuests.Contains(quest))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool addThis = ImGui.Selectable(quest.Info.Name);
|
||||||
|
if (addThis || addFirst)
|
||||||
|
{
|
||||||
|
_questController.ManualPriorityQuests.Add(quest);
|
||||||
|
|
||||||
|
if (addFirst)
|
||||||
|
{
|
||||||
|
ImGui.CloseCurrentPopup();
|
||||||
|
addFirst = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Spacing();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawQuestList()
|
||||||
|
{
|
||||||
|
List<Quest> priorityQuests = _questController.ManualPriorityQuests;
|
||||||
|
Quest? itemToRemove = null;
|
||||||
|
Quest? itemToAdd = null;
|
||||||
|
int indexToAdd = 0;
|
||||||
|
|
||||||
|
float width = ImGui.GetContentRegionAvail().X;
|
||||||
|
List<(Vector2 TopLeft, Vector2 BottomRight)> itemPositions = [];
|
||||||
|
|
||||||
|
for (int i = 0; i < priorityQuests.Count; ++i)
|
||||||
|
{
|
||||||
|
Vector2 topLeft = ImGui.GetCursorScreenPos() +
|
||||||
|
new Vector2(0, -ImGui.GetStyle().ItemSpacing.Y / 2);
|
||||||
|
var quest = priorityQuests[i];
|
||||||
|
ImGui.PushID($"Quest{quest.Id}");
|
||||||
|
|
||||||
|
var style = _uiUtils.GetQuestStyle(quest.Id);
|
||||||
|
bool hovered;
|
||||||
|
using (var _ = _pluginInterface.UiBuilder.IconFontFixedWidthHandle.Push())
|
||||||
|
{
|
||||||
|
ImGui.AlignTextToFramePadding();
|
||||||
|
ImGui.TextColored(style.Color, style.Icon.ToIconString());
|
||||||
|
hovered = ImGui.IsItemHovered();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.AlignTextToFramePadding();
|
||||||
|
ImGui.Text(quest.Info.Name);
|
||||||
|
hovered |= ImGui.IsItemHovered();
|
||||||
|
|
||||||
|
if (hovered)
|
||||||
|
_questTooltipComponent.Draw(quest.Info);
|
||||||
|
|
||||||
|
if (priorityQuests.Count > 1)
|
||||||
|
{
|
||||||
|
ImGui.PushFont(UiBuilder.IconFont);
|
||||||
|
ImGui.SameLine(ImGui.GetContentRegionAvail().X +
|
||||||
|
ImGui.GetStyle().WindowPadding.X -
|
||||||
|
ImGui.CalcTextSize(FontAwesomeIcon.ArrowsUpDown.ToIconString()).X -
|
||||||
|
ImGui.CalcTextSize(FontAwesomeIcon.Times.ToIconString()).X -
|
||||||
|
ImGui.GetStyle().FramePadding.X * 4 -
|
||||||
|
ImGui.GetStyle().ItemSpacing.X);
|
||||||
|
ImGui.PopFont();
|
||||||
|
|
||||||
|
if (_draggedItem == quest.Id)
|
||||||
|
{
|
||||||
|
ImGuiComponents.IconButton("##Move", FontAwesomeIcon.ArrowsUpDown,
|
||||||
|
ImGui.ColorConvertU32ToFloat4(ImGui.GetColorU32(ImGuiCol.ButtonActive)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ImGuiComponents.IconButton("##Move", FontAwesomeIcon.ArrowsUpDown);
|
||||||
|
|
||||||
|
if (_draggedItem == null && ImGui.IsItemActive() && ImGui.IsMouseDragging(ImGuiMouseButton.Left))
|
||||||
|
_draggedItem = quest.Id;
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.PushFont(UiBuilder.IconFont);
|
||||||
|
ImGui.SameLine(ImGui.GetContentRegionAvail().X +
|
||||||
|
ImGui.GetStyle().WindowPadding.X -
|
||||||
|
ImGui.CalcTextSize(FontAwesomeIcon.Times.ToIconString()).X -
|
||||||
|
ImGui.GetStyle().FramePadding.X * 2);
|
||||||
|
ImGui.PopFont();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGuiComponents.IconButton($"##Remove{i}", FontAwesomeIcon.Times))
|
||||||
|
itemToRemove = quest;
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
|
||||||
|
Vector2 bottomRight = new Vector2(topLeft.X + width,
|
||||||
|
ImGui.GetCursorScreenPos().Y - ImGui.GetStyle().ItemSpacing.Y + 2);
|
||||||
|
itemPositions.Add((topLeft, bottomRight));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ImGui.IsMouseDragging(ImGuiMouseButton.Left))
|
||||||
|
_draggedItem = null;
|
||||||
|
else if (_draggedItem != null)
|
||||||
|
{
|
||||||
|
var draggedItem = priorityQuests.Single(x => x.Id == _draggedItem);
|
||||||
|
int oldIndex = priorityQuests.IndexOf(draggedItem);
|
||||||
|
|
||||||
|
var (topLeft, bottomRight) = itemPositions[oldIndex];
|
||||||
|
ImGui.GetWindowDrawList().AddRect(topLeft, bottomRight, ImGui.GetColorU32(ImGuiColors.DalamudGrey), 3f,
|
||||||
|
ImDrawFlags.RoundCornersAll);
|
||||||
|
|
||||||
|
int newIndex = itemPositions.FindIndex(x => ImGui.IsMouseHoveringRect(x.TopLeft, x.BottomRight, true));
|
||||||
|
if (newIndex >= 0 && oldIndex != newIndex)
|
||||||
|
{
|
||||||
|
itemToAdd = priorityQuests.Single(x => x.Id == _draggedItem);
|
||||||
|
indexToAdd = newIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemToRemove != null)
|
||||||
|
{
|
||||||
|
priorityQuests.Remove(itemToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemToAdd != null)
|
||||||
|
{
|
||||||
|
priorityQuests.Remove(itemToAdd);
|
||||||
|
priorityQuests.Insert(indexToAdd, itemToAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -31,6 +31,7 @@ internal sealed partial class ActiveQuestComponent
|
|||||||
private readonly ICommandManager _commandManager;
|
private readonly ICommandManager _commandManager;
|
||||||
private readonly Configuration _configuration;
|
private readonly Configuration _configuration;
|
||||||
private readonly QuestRegistry _questRegistry;
|
private readonly QuestRegistry _questRegistry;
|
||||||
|
private readonly PriorityWindow _priorityWindow;
|
||||||
private readonly IChatGui _chatGui;
|
private readonly IChatGui _chatGui;
|
||||||
|
|
||||||
public ActiveQuestComponent(
|
public ActiveQuestComponent(
|
||||||
@ -42,6 +43,7 @@ internal sealed partial class ActiveQuestComponent
|
|||||||
ICommandManager commandManager,
|
ICommandManager commandManager,
|
||||||
Configuration configuration,
|
Configuration configuration,
|
||||||
QuestRegistry questRegistry,
|
QuestRegistry questRegistry,
|
||||||
|
PriorityWindow priorityWindow,
|
||||||
IChatGui chatGui)
|
IChatGui chatGui)
|
||||||
{
|
{
|
||||||
_questController = questController;
|
_questController = questController;
|
||||||
@ -52,6 +54,7 @@ internal sealed partial class ActiveQuestComponent
|
|||||||
_commandManager = commandManager;
|
_commandManager = commandManager;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_questRegistry = questRegistry;
|
_questRegistry = questRegistry;
|
||||||
|
_priorityWindow = priorityWindow;
|
||||||
_chatGui = chatGui;
|
_chatGui = chatGui;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,6 +114,10 @@ internal sealed partial class ActiveQuestComponent
|
|||||||
_questController.Stop("Manual (no active quest)");
|
_questController.Stop("Manual (no active quest)");
|
||||||
_gatheringController.Stop("Manual (no active quest)");
|
_gatheringController.Stop("Manual (no active quest)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGuiComponents.IconButton(FontAwesomeIcon.SortAmountDown))
|
||||||
|
_priorityWindow.Toggle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,6 +300,10 @@ internal sealed partial class ActiveQuestComponent
|
|||||||
ImGui.PopStyleColor();
|
ImGui.PopStyleColor();
|
||||||
ImGui.EndDisabled();
|
ImGui.EndDisabled();
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGuiComponents.IconButton(FontAwesomeIcon.SortAmountDown))
|
||||||
|
_priorityWindow.Toggle();
|
||||||
|
|
||||||
if (_commandManager.Commands.TryGetValue("/questinfo", out var commandInfo))
|
if (_commandManager.Commands.TryGetValue("/questinfo", out var commandInfo))
|
||||||
{
|
{
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
|
Loading…
Reference in New Issue
Block a user