muffin v6.12

This commit is contained in:
alydev 2025-10-09 07:53:51 +10:00
parent cfb4dea47e
commit c8197297b2
58 changed files with 40038 additions and 58059 deletions

View file

@ -1,12 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
@ -14,7 +10,6 @@ using Dalamud.Plugin.Services;
using LLib.ImGui;
using Questionable.Controller;
using Questionable.Functions;
using Questionable.Model;
using Questionable.Model.Questing;
using Questionable.Windows.QuestComponents;
using Questionable.Windows.Utils;
@ -23,198 +18,49 @@ namespace Questionable.Windows;
internal sealed class PriorityWindow : LWindow
{
private const string ClipboardPrefix = "qst:priority:";
public const string ClipboardPrefix = "qst:priority:";
private const string LegacyClipboardPrefix = "qst:v1:";
public const string LegacyClipboardPrefix = "qst:v1:";
private const char ClipboardSeparator = ';';
public const char ClipboardSeparator = ';';
private readonly QuestController _questController;
private readonly ManualPriorityComponent _manualPriorityComponent;
private readonly QuestFunctions _questFunctions;
private readonly PresetBuilderComponent _presetBuilderComponent;
private readonly QuestSelector _questSelector;
private readonly QuestTooltipComponent _questTooltipComponent;
private readonly UiUtils _uiUtils;
private readonly IChatGui _chatGui;
private readonly IDalamudPluginInterface _pluginInterface;
private ElementId? _draggedItem;
public PriorityWindow(QuestController questController, QuestFunctions questFunctions, QuestSelector questSelector, QuestTooltipComponent questTooltipComponent, UiUtils uiUtils, IChatGui chatGui, IDalamudPluginInterface pluginInterface)
public PriorityWindow(QuestController questController, QuestFunctions questFunctions, QuestSelector questSelector, QuestTooltipComponent questTooltipComponent, PresetBuilderComponent presetBuilderComponent, UiUtils uiUtils, IChatGui chatGui, IDalamudPluginInterface pluginInterface)
: base("Quest Priority###QuestionableQuestPriority")
{
PriorityWindow priorityWindow = this;
_questController = questController;
_questFunctions = questFunctions;
_questSelector = questSelector;
_questTooltipComponent = questTooltipComponent;
_uiUtils = uiUtils;
_chatGui = chatGui;
_pluginInterface = pluginInterface;
_questSelector.SuggestionPredicate = (Quest quest) => !quest.Info.IsMainScenarioQuest && !questFunctions.IsQuestUnobtainable(quest.Id) && questController.ManualPriorityQuests.All((Quest x) => x.Id != quest.Id);
_questSelector.DefaultPredicate = (Quest quest) => questFunctions.IsQuestAccepted(quest.Id);
_questSelector.QuestSelected = delegate(Quest quest)
{
priorityWindow._questController.ManualPriorityQuests.Add(quest);
};
base.Size = new Vector2(400f, 400f);
_manualPriorityComponent = new ManualPriorityComponent(questController, questFunctions, questSelector, questTooltipComponent, uiUtils, chatGui, pluginInterface);
_presetBuilderComponent = presetBuilderComponent;
base.Size = new Vector2(500f, 500f);
base.SizeCondition = ImGuiCond.Once;
base.SizeConstraints = new WindowSizeConstraints
{
MinimumSize = new Vector2(400f, 400f),
MaximumSize = new Vector2(400f, 999f)
MinimumSize = new Vector2(615f, 500f),
MaximumSize = new Vector2(800f, 1000f)
};
}
public override void DrawContent()
{
ImGui.Text("Quests to do first:");
_questSelector.DrawSelection();
DrawQuestList();
List<ElementId> list = ParseClipboardItems();
ImGui.BeginDisabled(list.Count == 0);
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Download, "Import from Clipboard"))
using ImRaii.IEndObject endObject = ImRaii.TabBar("PriorityTabs");
if (!endObject)
{
ImportFromClipboard(list);
return;
}
ImGui.EndDisabled();
ImGui.SameLine();
ImGui.BeginDisabled(_questController.ManualPriorityQuests.Count == 0);
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Upload, "Export to Clipboard"))
using (ImRaii.IEndObject endObject2 = ImRaii.TabItem("Manual Priority"))
{
ExportToClipboard();
}
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Check, "Remove finished Quests"))
{
_questController.ManualPriorityQuests.RemoveAll((Quest q) => _questFunctions.IsQuestComplete(q.Id));
}
ImGui.SameLine();
using (ImRaii.Disabled(!ImGui.IsKeyDown(ImGuiKey.ModCtrl)))
{
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Trash, "Clear All"))
if (endObject2)
{
_questController.ClearQuestPriority();
_manualPriorityComponent.Draw();
}
}
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
using ImRaii.IEndObject endObject3 = ImRaii.TabItem("Quest Presets");
if (endObject3)
{
ImGui.SetTooltip("Hold CTRL to enable this button.");
_presetBuilderComponent.Draw();
}
ImGui.EndDisabled();
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 DrawQuestList()
{
List<Quest> manualPriorityQuests = _questController.ManualPriorityQuests;
Quest quest = null;
Quest quest2 = null;
int index = 0;
float x = ImGui.GetContentRegionAvail().X;
List<(Vector2, Vector2)> list = new List<(Vector2, Vector2)>();
for (int i = 0; i < manualPriorityQuests.Count; i++)
{
Vector2 item = ImGui.GetCursorScreenPos() + new Vector2(0f, (0f - ImGui.GetStyle().ItemSpacing.Y) / 2f);
Quest quest3 = manualPriorityQuests[i];
ImU8String id = new ImU8String(5, 1);
id.AppendLiteral("Quest");
id.AppendFormatted(quest3.Id);
using (ImRaii.PushId(id))
{
(Vector4, FontAwesomeIcon, string) questStyle = _uiUtils.GetQuestStyle(quest3.Id);
bool flag;
using (_pluginInterface.UiBuilder.IconFontFixedWidthHandle.Push())
{
ImGui.AlignTextToFramePadding();
ImGui.TextColored(in questStyle.Item1, questStyle.Item2.ToIconString());
flag = ImGui.IsItemHovered();
}
ImGui.SameLine();
ImGui.AlignTextToFramePadding();
ImGui.Text(quest3.Info.Name);
flag |= ImGui.IsItemHovered();
if (flag)
{
_questTooltipComponent.Draw(quest3.Info);
}
if (manualPriorityQuests.Count > 1)
{
using (ImRaii.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 * 4f - ImGui.GetStyle().ItemSpacing.X);
}
if (_draggedItem == quest3.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 = quest3.Id;
}
ImGui.SameLine();
}
else
{
using (ImRaii.PushFont(UiBuilder.IconFont))
{
ImGui.SameLine(ImGui.GetContentRegionAvail().X + ImGui.GetStyle().WindowPadding.X - ImGui.CalcTextSize(FontAwesomeIcon.Times.ToIconString()).X - ImGui.GetStyle().FramePadding.X * 2f);
}
}
if (ImGuiComponents.IconButton($"##Remove{i}", FontAwesomeIcon.Times))
{
quest = quest3;
}
}
Vector2 item2 = new Vector2(item.X + x, ImGui.GetCursorScreenPos().Y - ImGui.GetStyle().ItemSpacing.Y + 2f);
list.Add((item, item2));
}
if (!ImGui.IsMouseDragging(ImGuiMouseButton.Left))
{
_draggedItem = null;
}
else if (_draggedItem != null)
{
Quest item3 = manualPriorityQuests.Single((Quest quest4) => quest4.Id == _draggedItem);
int num = manualPriorityQuests.IndexOf(item3);
var (pMin, pMax) = list[num];
ImGui.GetWindowDrawList().AddRect(pMin, pMax, ImGui.GetColorU32(ImGuiColors.DalamudGrey), 3f, ImDrawFlags.RoundCornersAll);
int num2 = list.FindIndex(((Vector2 TopLeft, Vector2 BottomRight) tuple2) => ImGui.IsMouseHoveringRect(tuple2.TopLeft, tuple2.BottomRight, clip: true));
if (num2 >= 0 && num != num2)
{
quest2 = manualPriorityQuests.Single((Quest quest4) => quest4.Id == _draggedItem);
index = num2;
}
}
if (quest != null)
{
manualPriorityQuests.Remove(quest);
}
if (quest2 != null)
{
manualPriorityQuests.Remove(quest2);
manualPriorityQuests.Insert(index, quest2);
}
}
private static List<ElementId> ParseClipboardItems()
{
return DecodeQuestPriority(ImGui.GetClipboardText().Trim());
}
public static List<ElementId> DecodeQuestPriority(string clipboardText)
@ -251,20 +97,4 @@ internal sealed class PriorityWindow : LWindow
}
return list;
}
public string EncodeQuestPriority()
{
return "qst:priority:" + Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Join(';', _questController.ManualPriorityQuests.Select((Quest x) => x.Id.ToString()))));
}
private void ExportToClipboard()
{
ImGui.SetClipboardText(EncodeQuestPriority());
_chatGui.Print("Copied quests to clipboard.", "Questionable", 576);
}
private void ImportFromClipboard(List<ElementId> questElements)
{
_questController.ImportQuestPriority(questElements);
}
}

View file

@ -225,31 +225,36 @@ internal sealed class QuestSelectionWindow : LWindow
continue;
}
EInteractionType? eInteractionType = quest.FindSequence(0)?.LastStep()?.InteractionType;
if (eInteractionType.HasValue && eInteractionType == EInteractionType.AcceptQuest && _questFunctions.IsReadyToAcceptQuest(item.QuestId))
if (!eInteractionType.HasValue || eInteractionType != EInteractionType.AcceptQuest || !_questFunctions.IsReadyToAcceptQuest(item.QuestId))
{
ImGui.BeginDisabled(_questController.NextQuest != null || _questController.SimulatedQuest != null);
bool num2 = ImGuiComponents.IconButton(FontAwesomeIcon.Play);
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Start as next quest");
}
if (num2)
{
_questController.SetNextQuest(quest);
_questController.Start("QuestSelectionWindow");
}
ImGui.SameLine();
bool num3 = ImGuiComponents.IconButton(FontAwesomeIcon.AngleDoubleRight);
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Set as next quest");
}
if (num3)
{
_questController.SetNextQuest(quest);
}
ImGui.EndDisabled();
continue;
}
ImGui.BeginDisabled(_questController.NextQuest != null || _questController.SimulatedQuest != null);
bool num2 = ImGuiComponents.IconButton(FontAwesomeIcon.Play);
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Start as next quest");
}
if (num2)
{
_questController.SetNextQuest(quest);
if (!_questController.ManualPriorityQuests.Contains(quest))
{
_questController.ManualPriorityQuests.Insert(0, quest);
}
_questController.Start("QuestSelectionWindow");
}
ImGui.SameLine();
bool num3 = ImGuiComponents.IconButton(FontAwesomeIcon.AngleDoubleRight);
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Set as next quest");
}
if (num3)
{
_questController.SetNextQuest(quest);
}
ImGui.EndDisabled();
}
}
}

View file

@ -1,95 +1,48 @@
using System.Globalization;
using System.Numerics;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
using FFXIVClientStructs.FFXIV.Common.Math;
using LLib.ImGui;
using Questionable.Data;
using Questionable.Validation;
using Questionable.Windows.QuestComponents;
namespace Questionable.Windows;
internal sealed class QuestValidationWindow : LWindow
internal sealed class QuestValidationWindow : LWindow, IPersistableWindowConfig
{
private readonly QuestValidator _questValidator;
private readonly QuestData _questData;
private readonly IDalamudPluginInterface _pluginInterface;
public QuestValidationWindow(QuestValidator questValidator, QuestData questData, IDalamudPluginInterface pluginInterface)
private readonly Configuration _configuration;
private readonly QuestValidationComponent _questValidationComponent;
public WindowConfig WindowConfig => _configuration.QuestValidationWindowConfig;
public QuestValidationWindow(QuestValidationComponent questValidationComponent, IDalamudPluginInterface pluginInterface, Configuration configuration)
: base("Quest Validation###QuestionableValidator")
{
_questValidator = questValidator;
_questData = questData;
_questValidationComponent = questValidationComponent;
_pluginInterface = pluginInterface;
base.Size = new Vector2(600f, 200f);
base.SizeCondition = ImGuiCond.Once;
_configuration = configuration;
base.Size = new Vector2(800f, 400f);
base.SizeCondition = ImGuiCond.FirstUseEver;
base.SizeConstraints = new WindowSizeConstraints
{
MinimumSize = new Vector2(600f, 200f)
MinimumSize = new Vector2(600f, 300f)
};
}
public void SaveWindowConfig()
{
_pluginInterface.SavePluginConfig(_configuration);
}
public override bool DrawConditions()
{
return _questValidationComponent.ShouldDraw;
}
public override void DrawContent()
{
using ImRaii.IEndObject endObject = ImRaii.Table("QuestSelection", 5, ImGuiTableFlags.Borders | ImGuiTableFlags.ScrollY);
if (!endObject)
{
ImGui.Text("Not table");
return;
}
ImGui.TableSetupColumn("Quest", ImGuiTableColumnFlags.WidthFixed, 50f);
ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, 200f);
ImGui.TableSetupColumn("Seq", ImGuiTableColumnFlags.WidthFixed, 30f);
ImGui.TableSetupColumn("Step", ImGuiTableColumnFlags.WidthFixed, 30f);
ImGui.TableSetupColumn("Issue", ImGuiTableColumnFlags.None, 200f);
ImGui.TableHeadersRow();
foreach (ValidationIssue issue in _questValidator.Issues)
{
ImGui.TableNextRow();
if (ImGui.TableNextColumn())
{
ImGui.TextUnformatted(issue.ElementId?.ToString() ?? string.Empty);
}
if (ImGui.TableNextColumn())
{
ImGui.TextUnformatted((issue.ElementId != null) ? _questData.GetQuestInfo(issue.ElementId).Name : issue.AlliedSociety.ToString());
}
if (ImGui.TableNextColumn())
{
ImGui.TextUnformatted(issue.Sequence?.ToString(CultureInfo.InvariantCulture) ?? string.Empty);
}
if (ImGui.TableNextColumn())
{
ImGui.TextUnformatted(issue.Step?.ToString(CultureInfo.InvariantCulture) ?? string.Empty);
}
if (!ImGui.TableNextColumn())
{
continue;
}
using (_pluginInterface.UiBuilder.IconFontFixedWidthHandle.Push())
{
if (issue.Severity == EIssueSeverity.Error)
{
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed))
{
ImGui.TextUnformatted(FontAwesomeIcon.ExclamationTriangle.ToIconString());
}
}
else
{
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.ParsedBlue))
{
ImGui.TextUnformatted(FontAwesomeIcon.InfoCircle.ToIconString());
}
}
}
ImGui.SameLine();
ImGui.TextUnformatted(issue.Description);
}
_questValidationComponent.Draw();
}
}

View file

@ -51,7 +51,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
public bool IsMinimized { get; set; }
public QuestWindow(IDalamudPluginInterface pluginInterface, QuestController questController, IClientState clientState, Configuration configuration, TerritoryData territoryData, ActiveQuestComponent activeQuestComponent, ARealmRebornComponent aRealmRebornComponent, EventInfoComponent eventInfoComponent, CreationUtilsComponent creationUtilsComponent, QuickAccessButtonsComponent quickAccessButtonsComponent, RemainingTasksComponent remainingTasksComponent, IFramework framework, InteractionUiController interactionUiController, ConfigWindow configWindow)
: base("Questionable v" + PluginVersion.ToString(4) + "###Questionable", ImGuiWindowFlags.AlwaysAutoResize)
: base("Questionable v" + PluginVersion.ToString(2) + "###Questionable", ImGuiWindowFlags.AlwaysAutoResize)
{
QuestWindow questWindow = this;
_pluginInterface = pluginInterface;

View file

@ -4,6 +4,7 @@ using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Plugin;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
using Questionable.Controller;
using Questionable.Functions;
using Questionable.Model.Questing;
@ -13,11 +14,14 @@ internal sealed class UiUtils
{
private readonly QuestFunctions _questFunctions;
private readonly QuestRegistry _questRegistry;
private readonly IDalamudPluginInterface _pluginInterface;
public UiUtils(QuestFunctions questFunctions, IDalamudPluginInterface pluginInterface)
public UiUtils(QuestFunctions questFunctions, QuestRegistry questRegistry, IDalamudPluginInterface pluginInterface)
{
_questFunctions = questFunctions;
_questRegistry = questRegistry;
_pluginInterface = pluginInterface;
}
@ -47,7 +51,7 @@ internal sealed class UiUtils
{
return (Color: ImGuiColors.DalamudGrey, Icon: FontAwesomeIcon.Minus, Status: "Unobtainable");
}
if (_questFunctions.IsQuestLocked(elementId))
if (_questFunctions.IsQuestLocked(elementId) || !_questFunctions.IsReadyToAcceptQuest(elementId) || !_questRegistry.IsKnownQuest(elementId))
{
return (Color: ImGuiColors.DalamudRed, Icon: FontAwesomeIcon.Times, Status: "Locked");
}