punish v6.8.18.0

This commit is contained in:
alydev 2025-10-09 07:47:19 +10:00
commit 060278c1b7
317 changed files with 554155 additions and 0 deletions

View file

@ -0,0 +1,111 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
using FFXIVClientStructs.FFXIV.Common.Math;
using Questionable.Data;
using Questionable.Functions;
using Questionable.Model.Questing;
namespace Questionable.Windows.QuestComponents;
internal sealed class ARealmRebornComponent
{
private static readonly QuestId ATimeForEveryPurpose = new QuestId(425);
private static readonly QuestId TheUltimateWeapon = new QuestId(524);
private static readonly QuestId GoodIntentions = new QuestId(363);
private static readonly ushort[] RequiredPrimalInstances = new ushort[3] { 20004, 20006, 20005 };
private readonly QuestFunctions _questFunctions;
private readonly QuestData _questData;
private readonly TerritoryData _territoryData;
private readonly UiUtils _uiUtils;
private readonly Configuration _configuration;
public bool ShouldDraw
{
get
{
if (!_questFunctions.IsQuestAcceptedOrComplete(ATimeForEveryPurpose))
{
return _questFunctions.IsQuestComplete(TheUltimateWeapon);
}
return false;
}
}
public ARealmRebornComponent(QuestFunctions questFunctions, QuestData questData, TerritoryData territoryData, UiUtils uiUtils, Configuration configuration)
{
_questFunctions = questFunctions;
_questData = questData;
_territoryData = territoryData;
_uiUtils = uiUtils;
_configuration = configuration;
}
public void Draw()
{
if (!_questFunctions.IsQuestAcceptedOrComplete(GoodIntentions))
{
DrawPrimals();
}
DrawAllianceRaids();
}
private void DrawPrimals()
{
bool flag = UIState.IsInstanceContentCompleted(RequiredPrimalInstances.Last());
bool flag2 = _uiUtils.ChecklistItem("Hard Mode Primals", flag, _configuration.Advanced.SkipARealmRebornHardModePrimals ? new System.Numerics.Vector4?(ImGuiColors.DalamudGrey) : ((System.Numerics.Vector4?)null));
if (flag || !flag2)
{
return;
}
using ImRaii.IEndObject endObject = ImRaii.Tooltip();
if (!(!endObject))
{
ushort[] requiredPrimalInstances = RequiredPrimalInstances;
foreach (ushort instanceId in requiredPrimalInstances)
{
(System.Numerics.Vector4 color, FontAwesomeIcon icon) instanceStyle = UiUtils.GetInstanceStyle(instanceId);
FFXIVClientStructs.FFXIV.Common.Math.Vector4 vector = instanceStyle.color;
FontAwesomeIcon item = instanceStyle.icon;
_uiUtils.ChecklistItem(_territoryData.GetInstanceName(instanceId) ?? "?", vector, item, ImGui.GetStyle().FramePadding.X);
}
}
}
private void DrawAllianceRaids()
{
QuestFunctions questFunctions = _questFunctions;
IReadOnlyList<QuestId> crystalTowerQuests = QuestData.CrystalTowerQuests;
bool flag = questFunctions.IsQuestComplete(crystalTowerQuests[crystalTowerQuests.Count - 1]);
bool flag2 = _uiUtils.ChecklistItem("Crystal Tower Raids", flag, _configuration.Advanced.SkipCrystalTowerRaids ? new System.Numerics.Vector4?(ImGuiColors.DalamudGrey) : ((System.Numerics.Vector4?)null));
if (flag || !flag2)
{
return;
}
using ImRaii.IEndObject endObject = ImRaii.Tooltip();
if (!endObject)
{
return;
}
foreach (QuestId crystalTowerQuest in QuestData.CrystalTowerQuests)
{
(System.Numerics.Vector4 Color, FontAwesomeIcon Icon, string Status) questStyle = _uiUtils.GetQuestStyle(crystalTowerQuest);
FFXIVClientStructs.FFXIV.Common.Math.Vector4 vector = questStyle.Color;
FontAwesomeIcon item = questStyle.Icon;
_uiUtils.ChecklistItem(_questData.GetQuestInfo(crystalTowerQuest).Name, vector, item, ImGui.GetStyle().FramePadding.X);
}
}
}

View file

@ -0,0 +1,610 @@
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text.RegularExpressions;
using System.Text.RegularExpressions.Generated;
using Dalamud.Bindings.ImGui;
using Dalamud.Game.Text;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Plugin.Services;
using Microsoft.Extensions.Logging;
using Questionable.Controller;
using Questionable.Controller.Steps.Shared;
using Questionable.Functions;
using Questionable.Model;
using Questionable.Model.Questing;
namespace Questionable.Windows.QuestComponents;
internal sealed class ActiveQuestComponent
{
private readonly QuestController _questController;
private readonly MovementController _movementController;
private readonly CombatController _combatController;
private readonly GatheringController _gatheringController;
private readonly QuestFunctions _questFunctions;
private readonly ICommandManager _commandManager;
private readonly Configuration _configuration;
private readonly QuestRegistry _questRegistry;
private readonly PriorityWindow _priorityWindow;
private readonly UiUtils _uiUtils;
private readonly IClientState _clientState;
private readonly IChatGui _chatGui;
private readonly ILogger<ActiveQuestComponent> _logger;
public event EventHandler? Reload;
[GeneratedRegex("\\s\\s+", RegexOptions.IgnoreCase, "en-US")]
[GeneratedCode("System.Text.RegularExpressions.Generator", "9.0.12.41916")]
private static Regex MultipleWhitespaceRegex()
{
return _003CRegexGenerator_g_003EFF909AF37F4C319C8940E7DA0E71D9E470824ECE485FE299B23B08984F5D534F6__MultipleWhitespaceRegex_0.Instance;
}
public ActiveQuestComponent(QuestController questController, MovementController movementController, CombatController combatController, GatheringController gatheringController, QuestFunctions questFunctions, ICommandManager commandManager, Configuration configuration, QuestRegistry questRegistry, PriorityWindow priorityWindow, UiUtils uiUtils, IClientState clientState, IChatGui chatGui, ILogger<ActiveQuestComponent> logger)
{
_questController = questController;
_movementController = movementController;
_combatController = combatController;
_gatheringController = gatheringController;
_questFunctions = questFunctions;
_commandManager = commandManager;
_configuration = configuration;
_questRegistry = questRegistry;
_priorityWindow = priorityWindow;
_uiUtils = uiUtils;
_clientState = clientState;
_chatGui = chatGui;
_logger = logger;
}
public void Draw(bool isMinimized)
{
(QuestController.QuestProgress, QuestController.ECurrentQuestType)? currentQuestDetails = _questController.CurrentQuestDetails;
QuestController.QuestProgress questProgress = currentQuestDetails?.Item1;
QuestController.ECurrentQuestType? currentQuestType = currentQuestDetails?.Item2;
if (questProgress != null)
{
DrawQuestNames(questProgress, currentQuestType);
QuestProgressInfo questProgressInfo = DrawQuestWork(questProgress, isMinimized);
if (_combatController.IsRunning)
{
ImGui.TextColored(ImGuiColors.DalamudOrange, "In Combat");
}
else
{
string currentTaskState = _questController.CurrentTaskState;
if (currentTaskState != null)
{
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudOrange))
{
ImGui.TextUnformatted(currentTaskState);
}
}
else
{
using (ImRaii.Disabled())
{
ImGui.TextUnformatted(_questController.DebugState ?? string.Empty);
}
}
}
try
{
QuestSequence questSequence = questProgress.Quest.FindSequence(questProgress.Sequence);
QuestStep questStep = questSequence?.FindStep(questProgress.Step);
if (!isMinimized)
{
using (ImRaii.Color color = new ImRaii.Color())
{
bool flag;
if (questStep != null)
{
EInteractionType interactionType = questStep.InteractionType;
if (interactionType == EInteractionType.WaitForManualProgress || interactionType == EInteractionType.Snipe || interactionType == EInteractionType.Instruction)
{
flag = true;
goto IL_0154;
}
}
flag = false;
goto IL_0154;
IL_0154:
if (flag)
{
color.Push(ImGuiCol.Text, ImGuiColors.DalamudOrange);
}
ImGui.TextUnformatted(questStep?.Comment ?? questSequence?.Comment ?? questProgress.Quest.Root.Comment ?? string.Empty);
}
ImGui.Text(_questController.ToStatString());
}
DrawQuestButtons(questProgress, questStep, questProgressInfo, isMinimized);
}
catch (Exception ex)
{
ImGui.TextColored(ImGuiColors.DalamudRed, ex.ToString());
_logger.LogError(ex, "Could not handle active quest buttons");
}
DrawSimulationControls();
}
else
{
ImGui.Text("No active quest");
if (!isMinimized)
{
Vector4 col = ImGuiColors.DalamudGrey;
ImU8String text = new ImU8String(14, 1);
text.AppendFormatted(_questRegistry.Count);
text.AppendLiteral(" quests loaded");
ImGui.TextColored(in col, text);
}
if (ImGuiComponents.IconButton(FontAwesomeIcon.Stop))
{
_movementController.Stop();
_questController.Stop("Manual (no active quest)");
_gatheringController.Stop("Manual (no active quest)");
}
ImGui.SameLine();
if (ImGuiComponents.IconButton(FontAwesomeIcon.SortAmountDown))
{
_priorityWindow.ToggleOrUncollapse();
}
}
}
private void DrawQuestNames(QuestController.QuestProgress currentQuest, QuestController.ECurrentQuestType? currentQuestType)
{
if (currentQuestType == QuestController.ECurrentQuestType.Simulated)
{
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed))
{
ImU8String text = new ImU8String(26, 4);
text.AppendLiteral("Simulated Quest: ");
text.AppendFormatted(Shorten(currentQuest.Quest.Info.Name));
text.AppendLiteral(" (");
text.AppendFormatted(currentQuest.Quest.Id);
text.AppendLiteral(") / ");
text.AppendFormatted(currentQuest.Sequence);
text.AppendLiteral(" / ");
text.AppendFormatted(currentQuest.Step);
ImGui.TextUnformatted(text);
return;
}
}
if (currentQuestType == QuestController.ECurrentQuestType.Gathering)
{
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.ParsedGold))
{
ImU8String text = new ImU8String(20, 4);
text.AppendLiteral("Gathering: ");
text.AppendFormatted(Shorten(currentQuest.Quest.Info.Name));
text.AppendLiteral(" (");
text.AppendFormatted(currentQuest.Quest.Id);
text.AppendLiteral(") / ");
text.AppendFormatted(currentQuest.Sequence);
text.AppendLiteral(" / ");
text.AppendFormatted(currentQuest.Step);
ImGui.TextUnformatted(text);
return;
}
}
QuestController.QuestProgress startedQuest = _questController.StartedQuest;
if (startedQuest != null)
{
if (startedQuest.Quest.Source == Quest.ESource.UserDirectory)
{
ImGui.PushFont(UiBuilder.IconFont);
ImGui.TextColored(ImGuiColors.DalamudOrange, FontAwesomeIcon.FilePen.ToIconString());
ImGui.PopFont();
ImGui.SameLine(0f);
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("This quest is loaded from your 'pluginConfigs\\Questionable\\Quests' directory.\nThis gets loaded even if Questionable ships with a newer/different version of the quest.");
}
}
ImU8String text = new ImU8String(16, 4);
text.AppendLiteral("Quest: ");
text.AppendFormatted(Shorten(startedQuest.Quest.Info.Name));
text.AppendLiteral(" (");
text.AppendFormatted(startedQuest.Quest.Id);
text.AppendLiteral(") / ");
text.AppendFormatted(startedQuest.Sequence);
text.AppendLiteral(" / ");
text.AppendFormatted(startedQuest.Step);
ImGui.TextUnformatted(text);
if (startedQuest.Quest.Root.Disabled)
{
ImGui.SameLine();
ImGui.TextColored(ImGuiColors.DalamudRed, "Disabled");
}
bool flag = _configuration.Stop.Enabled && _configuration.Stop.LevelToStopAfter;
bool flag2 = _configuration.Stop.Enabled && _configuration.Stop.QuestsToStopAfter.Any((ElementId x) => !_questFunctions.IsQuestComplete(x) && !_questFunctions.IsQuestUnobtainable(x));
if (flag || flag2)
{
ImGui.SameLine();
Vector4 col = ImGuiColors.ParsedPurple;
if (flag)
{
int num = _clientState.LocalPlayer?.Level ?? 0;
if (num > 0 && num >= _configuration.Stop.TargetLevel)
{
col = ImGuiColors.ParsedGreen;
}
else if (num > 0)
{
col = ImGuiColors.ParsedBlue;
}
}
ImGui.TextColored(in col, SeIconChar.Clock.ToIconString());
if (ImGui.IsItemHovered())
{
using ImRaii.IEndObject endObject = ImRaii.Tooltip();
if (endObject)
{
ImGui.Text("Stop Conditions:");
ImGui.Separator();
if (flag)
{
int num2 = _clientState.LocalPlayer?.Level ?? 0;
text = new ImU8String(14, 1);
text.AppendLiteral("Stop at level ");
text.AppendFormatted(_configuration.Stop.TargetLevel);
ImGui.BulletText(text);
if (num2 > 0)
{
ImGui.SameLine();
if (num2 >= _configuration.Stop.TargetLevel)
{
Vector4 col2 = ImGuiColors.ParsedGreen;
text = new ImU8String(22, 1);
text.AppendLiteral("(Current: ");
text.AppendFormatted(num2);
text.AppendLiteral(" - Reached!)");
ImGui.TextColored(in col2, text);
}
else
{
Vector4 col2 = ImGuiColors.ParsedBlue;
text = new ImU8String(11, 1);
text.AppendLiteral("(Current: ");
text.AppendFormatted(num2);
text.AppendLiteral(")");
ImGui.TextColored(in col2, text);
}
}
}
if (flag2)
{
if (flag)
{
ImGui.Spacing();
}
ImGui.BulletText("Stop after completing any of these quests:");
ImGui.Indent();
foreach (ElementId item in _configuration.Stop.QuestsToStopAfter)
{
if (_questRegistry.TryGetQuest(item, out Quest quest))
{
var (color, icon, _) = _uiUtils.GetQuestStyle(item);
_uiUtils.ChecklistItem($"{quest.Info.Name} ({item})", color, icon);
}
}
ImGui.Unindent();
}
}
}
}
if (_configuration.Advanced.AdditionalStatusInformation && _questController.IsInterruptible())
{
ImGui.SameLine();
ImGui.TextColored(ImGuiColors.DalamudYellow, SeIconChar.Hyadelyn.ToIconString());
if (ImGui.IsItemHovered())
{
using ImRaii.IEndObject endObject2 = ImRaii.Tooltip();
if (endObject2)
{
ImGui.Text("This quest sequence starts with a teleport to an Aetheryte.");
ImGui.Text("Certain priority quest (e.g. class quests) may be started/completed by the plugin prior to continuing with this quest.");
ImGui.Separator();
ImGui.Text("Available priority quests:");
List<PriorityQuestInfo> nextPriorityQuestsThatCanBeAccepted = _questFunctions.GetNextPriorityQuestsThatCanBeAccepted();
List<ElementId> list = (from x in nextPriorityQuestsThatCanBeAccepted
where x.IsAvailable
select x.QuestId).ToList();
if (list.Count > 0)
{
foreach (ElementId item2 in list)
{
if (_questRegistry.TryGetQuest(item2, out Quest quest2))
{
text = new ImU8String(3, 2);
text.AppendFormatted(quest2.Info.Name);
text.AppendLiteral(" (");
text.AppendFormatted(item2);
text.AppendLiteral(")");
ImGui.BulletText(text);
}
}
}
else
{
ImGui.BulletText("(none)");
}
if (_configuration.Advanced.AdditionalStatusInformation)
{
List<PriorityQuestInfo> list2 = nextPriorityQuestsThatCanBeAccepted.Where((PriorityQuestInfo x) => !x.IsAvailable).ToList();
if (list2.Count > 0)
{
ImGui.Text("Unavailable priority quests:");
foreach (var (elementId2, value) in list2)
{
if (_questRegistry.TryGetQuest(elementId2, out Quest quest3))
{
text = new ImU8String(6, 3);
text.AppendFormatted(quest3.Info.Name);
text.AppendLiteral(" (");
text.AppendFormatted(elementId2);
text.AppendLiteral(") - ");
text.AppendFormatted(value);
ImGui.BulletText(text);
}
}
}
}
}
}
}
}
QuestController.QuestProgress nextQuest = _questController.NextQuest;
if (nextQuest != null)
{
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow))
{
ImU8String text = new ImU8String(21, 4);
text.AppendLiteral("Next Quest: ");
text.AppendFormatted(Shorten(nextQuest.Quest.Info.Name));
text.AppendLiteral(" (");
text.AppendFormatted(nextQuest.Quest.Id);
text.AppendLiteral(") / ");
text.AppendFormatted(nextQuest.Sequence);
text.AppendLiteral(" / ");
text.AppendFormatted(nextQuest.Step);
ImGui.TextUnformatted(text);
}
}
}
private unsafe QuestProgressInfo? DrawQuestWork(QuestController.QuestProgress currentQuest, bool isMinimized)
{
QuestProgressInfo questProgressInfo = _questFunctions.GetQuestProgressInfo(currentQuest.Quest.Id);
if (questProgressInfo != null)
{
if (isMinimized)
{
return questProgressInfo;
}
Vector4* styleColorVec = ImGui.GetStyleColorVec4(ImGuiCol.TextDisabled);
Vector4 color = ((styleColorVec == null) ? ImGuiColors.ParsedOrange : (*styleColorVec));
using (ImRaii.PushColor(ImGuiCol.Text, color))
{
ImU8String text = new ImU8String(0, 1);
text.AppendFormatted(questProgressInfo);
ImGui.Text(text);
if (ImGui.IsItemClicked())
{
string text2 = MultipleWhitespaceRegex().Replace(questProgressInfo.ToString(), " ");
ImGui.SetClipboardText(text2);
_chatGui.Print("Copied '" + text2 + "' to clipboard");
}
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip(questProgressInfo.Tooltip);
ImGui.SameLine();
ImGui.PushFont(UiBuilder.IconFont);
ImGui.Text(FontAwesomeIcon.Copy.ToIconString());
ImGui.PopFont();
}
if (currentQuest.Quest.Info.AlliedSociety != EAlliedSociety.None)
{
ImGui.SameLine();
text = new ImU8String(2, 1);
text.AppendLiteral("/ ");
text.AppendFormatted(questProgressInfo.ClassJob);
ImGui.Text(text);
}
}
}
else if (currentQuest.Quest.Id is QuestId)
{
using (ImRaii.Disabled())
{
if (currentQuest.Quest.Id == _questController.NextQuest?.Quest.Id)
{
ImGui.TextUnformatted("(Next quest in story line not accepted)");
}
else
{
ImGui.TextUnformatted("(Not accepted)");
}
}
}
return questProgressInfo;
}
private void DrawQuestButtons(QuestController.QuestProgress currentQuest, QuestStep? currentStep, QuestProgressInfo? questProgressInfo, bool isMinimized)
{
using (ImRaii.Disabled(_questController.IsRunning))
{
if (ImGuiComponents.IconButton(FontAwesomeIcon.Play))
{
if (questProgressInfo == null)
{
_questController.SetNextQuest(currentQuest.Quest);
}
_questController.Start("UI start");
}
if (!isMinimized)
{
ImGui.SameLine();
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.StepForward, "Step"))
{
_questController.StartSingleStep("UI step");
}
}
}
ImGui.SameLine();
if (ImGuiComponents.IconButton(FontAwesomeIcon.Stop))
{
_movementController.Stop();
_questController.Stop("UI stop");
_gatheringController.Stop("UI stop");
}
if (isMinimized)
{
ImGui.SameLine();
if (ImGuiComponents.IconButton(FontAwesomeIcon.RedoAlt))
{
this.Reload?.Invoke(this, EventArgs.Empty);
}
return;
}
bool flag = currentStep == currentQuest.Quest.FindSequence(currentQuest.Sequence)?.Steps.LastOrDefault();
WaitAtEnd.WaitNextStepOrSequence task;
bool condition = currentStep != null && !flag && currentStep.InteractionType == EInteractionType.Instruction && _questController.HasCurrentTaskMatching<WaitAtEnd.WaitNextStepOrSequence>(out task);
using (ImRaii.Disabled(flag))
{
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.ParsedGreen, condition))
{
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.ArrowCircleRight, "Skip"))
{
_movementController.Stop();
_questController.Skip(currentQuest.Quest.Id, currentQuest.Sequence);
}
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Skip the current step of the quest path.");
}
}
}
if (_commandManager.Commands.ContainsKey("/questinfo"))
{
ImGui.SameLine();
if (ImGuiComponents.IconButton(FontAwesomeIcon.Atlas))
{
_commandManager.ProcessCommand($"/questinfo {currentQuest.Quest.Id}");
}
if (ImGui.IsItemHovered())
{
ImU8String tooltip = new ImU8String(46, 1);
tooltip.AppendLiteral("Show information about '");
tooltip.AppendFormatted(currentQuest.Quest.Info.Name);
tooltip.AppendLiteral("' in Quest Map plugin.");
ImGui.SetTooltip(tooltip);
}
}
}
private void DrawSimulationControls()
{
if (_questController.SimulatedQuest == null)
{
return;
}
QuestController.QuestProgress simulatedQuest = _questController.SimulatedQuest;
ImGui.Separator();
ImGui.TextColored(ImGuiColors.DalamudRed, "Quest sim active (experimental)");
ImU8String text = new ImU8String(10, 1);
text.AppendLiteral("Sequence: ");
text.AppendFormatted(simulatedQuest.Sequence);
ImGui.Text(text);
ImGui.BeginDisabled(simulatedQuest.Sequence == 0);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Minus))
{
_movementController.Stop();
_questController.Stop("Sim-");
byte oldSequence = simulatedQuest.Sequence;
byte sequence = simulatedQuest.Quest.Root.QuestSequence.Select((QuestSequence x) => x.Sequence).LastOrDefault<byte>((byte x) => x < oldSequence, 0);
_questController.SimulatedQuest.SetSequence(sequence);
}
ImGui.EndDisabled();
ImGui.SameLine();
ImGui.BeginDisabled(simulatedQuest.Sequence >= byte.MaxValue);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
{
_movementController.Stop();
_questController.Stop("Sim+");
byte oldSequence2 = simulatedQuest.Sequence;
byte sequence2 = simulatedQuest.Quest.Root.QuestSequence.Select((QuestSequence x) => x.Sequence).FirstOrDefault((byte x) => x > oldSequence2, byte.MaxValue);
simulatedQuest.SetSequence(sequence2);
}
ImGui.EndDisabled();
QuestSequence questSequence = simulatedQuest.Quest.FindSequence(simulatedQuest.Sequence);
if (questSequence == null)
{
return;
}
using (ImRaii.PushId("SimulatedStep"))
{
text = new ImU8String(9, 2);
text.AppendLiteral("Step: ");
text.AppendFormatted(simulatedQuest.Step);
text.AppendLiteral(" / ");
text.AppendFormatted(questSequence.Steps.Count - 1);
ImGui.Text(text);
ImGui.BeginDisabled(simulatedQuest.Step == 0);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Minus))
{
_movementController.Stop();
_questController.Stop("SimStep-");
simulatedQuest.SetStep(Math.Min(simulatedQuest.Step - 1, questSequence.Steps.Count - 1));
}
ImGui.EndDisabled();
ImGui.SameLine();
ImGui.BeginDisabled(simulatedQuest.Step >= questSequence.Steps.Count);
if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
{
_movementController.Stop();
_questController.Stop("SimStep+");
simulatedQuest.SetStep((simulatedQuest.Step == questSequence.Steps.Count - 1) ? 255 : (simulatedQuest.Step + 1));
}
ImGui.EndDisabled();
if (ImGui.Button("Skip current task"))
{
_questController.SkipSimulatedTask();
}
ImGui.SameLine();
if (ImGui.Button("Clear sim"))
{
_questController.SimulateQuest(null, 0, 0);
_movementController.Stop();
_questController.Stop("ClearSim");
}
}
}
private static string Shorten(string text)
{
if (text.Length > 35)
{
return string.Concat(text.AsSpan(0, 30).Trim(), ((SeIconChar)57434).ToIconString());
}
return text;
}
}

View file

@ -0,0 +1,357 @@
using System;
using System.Globalization;
using System.Numerics;
using System.Runtime.CompilerServices;
using Dalamud.Bindings.ImGui;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Text;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game.Control;
using FFXIVClientStructs.FFXIV.Client.Game.Object;
using Microsoft.Extensions.Logging;
using Questionable.Controller;
using Questionable.Data;
using Questionable.Functions;
using Questionable.Model;
using Questionable.Model.Common;
namespace Questionable.Windows.QuestComponents;
internal sealed class CreationUtilsComponent
{
private readonly MovementController _movementController;
private readonly GameFunctions _gameFunctions;
private readonly QuestFunctions _questFunctions;
private readonly TerritoryData _territoryData;
private readonly QuestData _questData;
private readonly QuestSelectionWindow _questSelectionWindow;
private readonly IClientState _clientState;
private readonly ITargetManager _targetManager;
private readonly ICondition _condition;
private readonly IGameGui _gameGui;
private readonly Configuration _configuration;
private readonly ILogger<CreationUtilsComponent> _logger;
public CreationUtilsComponent(MovementController movementController, GameFunctions gameFunctions, QuestFunctions questFunctions, TerritoryData territoryData, QuestData questData, QuestSelectionWindow questSelectionWindow, IClientState clientState, ITargetManager targetManager, ICondition condition, IGameGui gameGui, Configuration configuration, ILogger<CreationUtilsComponent> logger)
{
_movementController = movementController;
_gameFunctions = gameFunctions;
_questFunctions = questFunctions;
_territoryData = territoryData;
_questData = questData;
_questSelectionWindow = questSelectionWindow;
_clientState = clientState;
_targetManager = targetManager;
_condition = condition;
_gameGui = gameGui;
_configuration = configuration;
_logger = logger;
}
public void Draw()
{
ImGui.Text(_territoryData.GetNameAndId(_clientState.TerritoryType));
if (_gameFunctions.IsFlyingUnlockedInCurrentZone())
{
ImGui.SameLine();
ImGui.Text(SeIconChar.BotanistSprout.ToIconString());
}
if (_configuration.Advanced.AdditionalStatusInformation)
{
QuestReference currentQuest = _questFunctions.GetCurrentQuest();
ImU8String text = new ImU8String(18, 2);
text.AppendLiteral("Current Quest: ");
text.AppendFormatted(currentQuest.CurrentQuest);
text.AppendLiteral(" → ");
text.AppendFormatted(currentQuest.Sequence);
ImGui.Text(text);
}
if (_targetManager.Target != null)
{
DrawTargetDetails(_targetManager.Target);
DrawInteractionButtons(_targetManager.Target);
ImGui.SameLine();
DrawCopyButton(_targetManager.Target);
}
else
{
DrawCopyButton();
}
ulong hoveredItem = _gameGui.HoveredItem;
if (hoveredItem != 0L)
{
ImGui.Separator();
ImU8String text = new ImU8String(14, 1);
text.AppendLiteral("Hovered Item: ");
text.AppendFormatted(hoveredItem);
ImGui.Text(text);
}
}
private unsafe void DrawTargetDetails(IGameObject target)
{
string value = string.Empty;
DefaultInterpolatedStringHandler handler;
if (target is ICharacter { NameId: not 0u } character)
{
handler = new DefaultInterpolatedStringHandler(4, 1);
handler.AppendLiteral("; n=");
handler.AppendFormatted(character.NameId);
value = handler.ToStringAndClear();
}
ImGui.Separator();
IFormatProvider invariantCulture = CultureInfo.InvariantCulture;
IFormatProvider provider = invariantCulture;
handler = new DefaultInterpolatedStringHandler(14, 4, invariantCulture);
handler.AppendLiteral("Target: ");
handler.AppendFormatted(target.Name);
handler.AppendLiteral(" (");
handler.AppendFormatted(target.ObjectKind);
handler.AppendLiteral("; ");
handler.AppendFormatted(target.DataId);
handler.AppendFormatted(value);
handler.AppendLiteral(")");
ImGui.Text(string.Create(provider, ref handler));
if (_clientState.LocalPlayer != null)
{
invariantCulture = CultureInfo.InvariantCulture;
IFormatProvider provider2 = invariantCulture;
handler = new DefaultInterpolatedStringHandler(10, 1, invariantCulture);
handler.AppendLiteral("Distance: ");
handler.AppendFormatted((target.Position - _clientState.LocalPlayer.Position).Length(), "F2");
ImGui.Text(string.Create(provider2, ref handler));
ImGui.SameLine();
float value2 = target.Position.Y - _clientState.LocalPlayer.Position.Y;
invariantCulture = CultureInfo.InvariantCulture;
IFormatProvider provider3 = invariantCulture;
handler = new DefaultInterpolatedStringHandler(3, 1, invariantCulture);
handler.AppendLiteral("Y: ");
handler.AppendFormatted(value2, "F2");
string text = string.Create(provider3, ref handler);
if (Math.Abs(value2) >= 1.95f)
{
ImGui.TextColored(ImGuiColors.DalamudOrange, text);
}
else
{
ImGui.Text(text);
}
ImGui.SameLine();
}
GameObject* address = (GameObject*)target.Address;
ImU8String text2 = new ImU8String(4, 1);
text2.AppendLiteral("QM: ");
text2.AppendFormatted(address->NamePlateIconId);
ImGui.Text(text2);
}
private unsafe void DrawInteractionButtons(IGameObject target)
{
ImGui.BeginDisabled(!_movementController.IsNavmeshReady || _gameFunctions.IsOccupied());
if (!_movementController.IsPathfinding)
{
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Bullseye, "To Target"))
{
_movementController.NavigateTo(EMovementType.DebugWindow, target.DataId, target.Position, _condition[ConditionFlag.Mounted] && _gameFunctions.IsFlyingUnlockedInCurrentZone(), sprint: true);
}
}
else if (ImGui.Button("Cancel pathfinding"))
{
_movementController.ResetPathfinding();
}
ImGui.EndDisabled();
ImGui.SameLine();
ImGui.BeginDisabled(!_questData.IsIssuerOfAnyQuest(target.DataId));
bool num = ImGuiComponents.IconButton(FontAwesomeIcon.MapMarkerAlt);
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Show all Quests starting with your current target.");
}
if (num)
{
_questSelectionWindow.OpenForTarget(_targetManager.Target);
}
ImGui.EndDisabled();
ImGui.BeginDisabled(_gameFunctions.IsOccupied());
ImGui.SameLine();
bool num2 = ImGuiComponents.IconButton(FontAwesomeIcon.MousePointer);
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Interact with your current target.");
}
if (num2)
{
ulong num3 = TargetSystem.Instance()->InteractWithObject((GameObject*)target.Address, checkLineOfSight: false);
_logger.LogInformation("XXXXX Interaction Result: {Result}", num3);
}
ImGui.EndDisabled();
}
private unsafe void DrawCopyButton(IGameObject target)
{
GameObject* address = (GameObject*)target.Address;
bool num = ImGuiComponents.IconButton(FontAwesomeIcon.Copy);
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Left click: Copy target position as JSON.\nRight click: Copy target position as C# code.");
}
if (num)
{
ImU8String clipboardText;
if (target.ObjectKind == Dalamud.Game.ClientState.Objects.Enums.ObjectKind.GatheringPoint)
{
clipboardText = new ImU8String(59, 4);
clipboardText.AppendLiteral("\"DataId\": ");
clipboardText.AppendFormatted(target.DataId);
clipboardText.AppendLiteral(",\n\"Position\": {\n \"X\": ");
clipboardText.AppendFormatted(target.Position.X.ToString(CultureInfo.InvariantCulture));
clipboardText.AppendLiteral(",\n \"Y\": ");
clipboardText.AppendFormatted(target.Position.Y.ToString(CultureInfo.InvariantCulture));
clipboardText.AppendLiteral(",\n \"Z\": ");
clipboardText.AppendFormatted(target.Position.Z.ToString(CultureInfo.InvariantCulture));
clipboardText.AppendLiteral("\n}");
ImGui.SetClipboardText(clipboardText);
return;
}
string text;
switch (address->NamePlateIconId)
{
case 71201u:
case 71211u:
case 71221u:
case 71231u:
case 71341u:
case 71351u:
text = "AcceptQuest";
break;
case 71202u:
case 71212u:
case 71222u:
case 71232u:
case 71342u:
case 71352u:
text = "AcceptQuest";
break;
case 71205u:
case 71215u:
case 71225u:
case 71235u:
case 71345u:
case 71355u:
text = "CompleteQuest";
break;
default:
text = "Interact";
break;
}
string value = text;
clipboardText = new ImU8String(99, 6);
clipboardText.AppendLiteral("\"DataId\": ");
clipboardText.AppendFormatted(target.DataId);
clipboardText.AppendLiteral(",\n\"Position\": {\n \"X\": ");
clipboardText.AppendFormatted(target.Position.X.ToString(CultureInfo.InvariantCulture));
clipboardText.AppendLiteral(",\n \"Y\": ");
clipboardText.AppendFormatted(target.Position.Y.ToString(CultureInfo.InvariantCulture));
clipboardText.AppendLiteral(",\n \"Z\": ");
clipboardText.AppendFormatted(target.Position.Z.ToString(CultureInfo.InvariantCulture));
clipboardText.AppendLiteral("\n},\n\"TerritoryId\": ");
clipboardText.AppendFormatted(_clientState.TerritoryType);
clipboardText.AppendLiteral(",\n\"InteractionType\": \"");
clipboardText.AppendFormatted(value);
clipboardText.AppendLiteral("\"");
ImGui.SetClipboardText(clipboardText);
}
else if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
DefaultInterpolatedStringHandler handler;
if (target.ObjectKind == Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Aetheryte)
{
EAetheryteLocation dataId = (EAetheryteLocation)target.DataId;
IFormatProvider invariantCulture = CultureInfo.InvariantCulture;
IFormatProvider provider = invariantCulture;
handler = new DefaultInterpolatedStringHandler(36, 4, invariantCulture);
handler.AppendLiteral("{EAetheryteLocation.");
handler.AppendFormatted(dataId);
handler.AppendLiteral(", new(");
handler.AppendFormatted(target.Position.X);
handler.AppendLiteral("f, ");
handler.AppendFormatted(target.Position.Y);
handler.AppendLiteral("f, ");
handler.AppendFormatted(target.Position.Z);
handler.AppendLiteral("f)},");
ImGui.SetClipboardText(string.Create(provider, ref handler));
}
else
{
IFormatProvider invariantCulture = CultureInfo.InvariantCulture;
IFormatProvider provider2 = invariantCulture;
handler = new DefaultInterpolatedStringHandler(12, 3, invariantCulture);
handler.AppendLiteral("new(");
handler.AppendFormatted(target.Position.X);
handler.AppendLiteral("f, ");
handler.AppendFormatted(target.Position.Y);
handler.AppendLiteral("f, ");
handler.AppendFormatted(target.Position.Z);
handler.AppendLiteral("f)");
ImGui.SetClipboardText(string.Create(provider2, ref handler));
}
}
}
private void DrawCopyButton()
{
if (_clientState.LocalPlayer != null)
{
bool num = ImGuiComponents.IconButton(FontAwesomeIcon.Copy);
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Left click: Copy your position as JSON.\nRight click: Copy your position as C# code.");
}
if (num)
{
ImU8String clipboardText = new ImU8String(87, 4);
clipboardText.AppendLiteral("\"Position\": {\n \"X\": ");
clipboardText.AppendFormatted(_clientState.LocalPlayer.Position.X.ToString(CultureInfo.InvariantCulture));
clipboardText.AppendLiteral(",\n \"Y\": ");
clipboardText.AppendFormatted(_clientState.LocalPlayer.Position.Y.ToString(CultureInfo.InvariantCulture));
clipboardText.AppendLiteral(",\n \"Z\": ");
clipboardText.AppendFormatted(_clientState.LocalPlayer.Position.Z.ToString(CultureInfo.InvariantCulture));
clipboardText.AppendLiteral("\n},\n\"TerritoryId\": ");
clipboardText.AppendFormatted(_clientState.TerritoryType);
clipboardText.AppendLiteral(",\n\"InteractionType\": \"\"");
ImGui.SetClipboardText(clipboardText);
}
else if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
Vector3 position = _clientState.LocalPlayer.Position;
IFormatProvider invariantCulture = CultureInfo.InvariantCulture;
DefaultInterpolatedStringHandler handler = new DefaultInterpolatedStringHandler(12, 3, invariantCulture);
handler.AppendLiteral("new(");
handler.AppendFormatted(position.X);
handler.AppendLiteral("f, ");
handler.AppendFormatted(position.Y);
handler.AppendLiteral("f, ");
handler.AppendFormatted(position.Z);
handler.AppendLiteral("f)");
ImGui.SetClipboardText(string.Create(invariantCulture, ref handler));
}
}
}
}

View file

@ -0,0 +1,182 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Components;
using Dalamud.Interface.Utility.Raii;
using Humanizer;
using Humanizer.Localisation;
using Questionable.Controller;
using Questionable.Data;
using Questionable.Functions;
using Questionable.Model;
using Questionable.Model.Questing;
namespace Questionable.Windows.QuestComponents;
internal sealed class EventInfoComponent
{
private sealed record EventQuest(string Name, List<ElementId> QuestIds, DateTime EndsAtUtc);
private readonly List<EventQuest> _eventQuests;
private readonly QuestData _questData;
private readonly QuestRegistry _questRegistry;
private readonly QuestFunctions _questFunctions;
private readonly UiUtils _uiUtils;
private readonly QuestController _questController;
private readonly QuestTooltipComponent _questTooltipComponent;
private readonly Configuration _configuration;
public bool ShouldDraw
{
get
{
if (_configuration.General.ShowIncompleteSeasonalEvents)
{
return _eventQuests.Any(IsIncomplete);
}
return false;
}
}
public EventInfoComponent(QuestData questData, QuestRegistry questRegistry, QuestFunctions questFunctions, UiUtils uiUtils, QuestController questController, QuestTooltipComponent questTooltipComponent, Configuration configuration)
{
int num = 2;
List<EventQuest> list = new List<EventQuest>(num);
CollectionsMarshal.SetCount(list, num);
Span<EventQuest> span = CollectionsMarshal.AsSpan(list);
int num2 = 0;
ref EventQuest reference = ref span[num2];
int num3 = 1;
List<ElementId> list2 = new List<ElementId>(num3);
CollectionsMarshal.SetCount(list2, num3);
CollectionsMarshal.AsSpan(list2)[0] = new UnlockLinkId(568);
reference = new EventQuest("Limited Time Items", list2, DateTime.MaxValue);
ref EventQuest reference2 = ref span[num2 + 1];
int num4 = 2;
List<ElementId> list3 = new List<ElementId>(num4);
CollectionsMarshal.SetCount(list3, num4);
Span<ElementId> span2 = CollectionsMarshal.AsSpan(list3);
num3 = 0;
span2[num3] = new QuestId(5297);
span2[num3 + 1] = new QuestId(5298);
reference2 = new EventQuest("The Rising 2025", list3, AtDailyReset(new DateOnly(2025, 9, 11)));
_eventQuests = list;
base._002Ector();
_questData = questData;
_questRegistry = questRegistry;
_questFunctions = questFunctions;
_uiUtils = uiUtils;
_questController = questController;
_questTooltipComponent = questTooltipComponent;
_configuration = configuration;
}
private static DateTime AtDailyReset(DateOnly date)
{
return new DateTime(date, new TimeOnly(14, 59), DateTimeKind.Utc);
}
public void Draw()
{
foreach (EventQuest eventQuest in _eventQuests)
{
if (IsIncomplete(eventQuest))
{
DrawEventQuest(eventQuest);
}
}
}
private void DrawEventQuest(EventQuest eventQuest)
{
if (eventQuest.EndsAtUtc != DateTime.MaxValue)
{
string value = (eventQuest.EndsAtUtc - DateTime.UtcNow).Humanize(1, CultureInfo.InvariantCulture, TimeUnit.Day, TimeUnit.Minute);
ImU8String text = new ImU8String(3, 2);
text.AppendFormatted(eventQuest.Name);
text.AppendLiteral(" (");
text.AppendFormatted(value);
text.AppendLiteral(")");
ImGui.Text(text);
}
else
{
ImGui.Text(eventQuest.Name);
}
List<ElementId> list = eventQuest.QuestIds.Where((ElementId x) => _questRegistry.IsKnownQuest(x) && _questFunctions.IsReadyToAcceptQuest(x) && x != _questController.StartedQuest?.Quest.Id && x != _questController.NextQuest?.Quest.Id).ToList();
foreach (ElementId questId in eventQuest.QuestIds)
{
if (_questFunctions.IsQuestComplete(questId))
{
continue;
}
ImU8String text = new ImU8String(21, 1);
text.AppendLiteral("##EventQuestSelection");
text.AppendFormatted(questId);
using (ImRaii.PushId(text))
{
string name = _questData.GetQuestInfo(questId).Name;
if (list.Contains(questId) && _questRegistry.TryGetQuest(questId, out Quest quest))
{
if (ImGuiComponents.IconButton(FontAwesomeIcon.Play))
{
_questController.SetNextQuest(quest);
_questController.Start("SeasonalEventSelection");
}
bool num = ImGui.IsItemHovered();
ImGui.SameLine();
ImGui.AlignTextToFramePadding();
ImGui.Text(name);
if (num | ImGui.IsItemHovered())
{
_questTooltipComponent.Draw(quest.Info);
}
}
else
{
ImGui.SetCursorPosX(ImGui.GetCursorPosX());
(Vector4, FontAwesomeIcon, string) questStyle = _uiUtils.GetQuestStyle(questId);
if (_uiUtils.ChecklistItem(name, questStyle.Item1, questStyle.Item2, ImGui.GetStyle().FramePadding.X))
{
_questTooltipComponent.Draw(_questData.GetQuestInfo(questId));
}
}
}
}
}
private bool IsIncomplete(EventQuest eventQuest)
{
if (eventQuest.EndsAtUtc <= DateTime.UtcNow)
{
return false;
}
return eventQuest.QuestIds.Any(ShouldShowQuest);
}
public IEnumerable<ElementId> GetCurrentlyActiveEventQuests()
{
return _eventQuests.Where((EventQuest x) => x.EndsAtUtc >= DateTime.UtcNow).SelectMany((EventQuest x) => x.QuestIds).Where(ShouldShowQuest);
}
private bool ShouldShowQuest(ElementId elementId)
{
if (!_questFunctions.IsQuestComplete(elementId))
{
return !_questFunctions.IsQuestUnobtainable(elementId);
}
return false;
}
}

View file

@ -0,0 +1,258 @@
using Dalamud.Bindings.ImGui;
using Dalamud.Game.Text;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using Questionable.Controller;
using Questionable.Data;
using Questionable.Functions;
using Questionable.Model;
using Questionable.Model.Questing;
namespace Questionable.Windows.QuestComponents;
internal sealed class QuestTooltipComponent
{
private readonly QuestRegistry _questRegistry;
private readonly QuestData _questData;
private readonly TerritoryData _territoryData;
private readonly QuestFunctions _questFunctions;
private readonly UiUtils _uiUtils;
private readonly Configuration _configuration;
public QuestTooltipComponent(QuestRegistry questRegistry, QuestData questData, TerritoryData territoryData, QuestFunctions questFunctions, UiUtils uiUtils, Configuration configuration)
{
_questRegistry = questRegistry;
_questData = questData;
_territoryData = territoryData;
_questFunctions = questFunctions;
_uiUtils = uiUtils;
_configuration = configuration;
}
public void Draw(IQuestInfo questInfo)
{
using ImRaii.IEndObject endObject = ImRaii.Tooltip();
if (endObject)
{
DrawInner(questInfo, showItemRewards: true);
}
}
public void DrawInner(IQuestInfo questInfo, bool showItemRewards)
{
ImU8String text = new ImU8String(0, 2);
text.AppendFormatted(SeIconChar.LevelEn.ToIconString());
text.AppendFormatted(questInfo.Level);
ImGui.Text(text);
ImGui.SameLine();
var (col, _, text2) = _uiUtils.GetQuestStyle(questInfo.QuestId);
ImGui.TextColored(in col, text2);
if (questInfo is QuestInfo { IsSeasonalEvent: not false })
{
ImGui.SameLine();
ImGui.TextUnformatted("Event");
}
if (questInfo.IsRepeatable)
{
ImGui.SameLine();
ImGui.TextUnformatted("Repeatable");
}
if (questInfo is QuestInfo { CompletesInstantly: not false })
{
ImGui.SameLine();
ImGui.TextUnformatted("Instant");
}
if (_questRegistry.TryGetQuest(questInfo.QuestId, out Quest quest))
{
if (quest.Root.Disabled)
{
ImGui.SameLine();
ImGui.TextColored(ImGuiColors.DalamudRed, "Disabled");
}
if (quest.Root.Author.Count == 1)
{
text = new ImU8String(8, 1);
text.AppendLiteral("Author: ");
text.AppendFormatted(quest.Root.Author[0]);
ImGui.Text(text);
}
else
{
text = new ImU8String(9, 1);
text.AppendLiteral("Authors: ");
text.AppendFormatted(string.Join(", ", quest.Root.Author));
ImGui.Text(text);
}
}
else
{
ImGui.SameLine();
ImGui.TextColored(ImGuiColors.DalamudRed, "NoQuestPath");
}
DrawQuestUnlocks(questInfo, 0, showItemRewards);
}
private void DrawQuestUnlocks(IQuestInfo questInfo, int counter, bool showItemRewards)
{
if (counter >= 10 || (counter != 0 && questInfo.IsMainScenarioQuest))
{
return;
}
if (counter > 0)
{
ImGui.Indent();
}
if (questInfo.PreviousQuests.Count > 0)
{
if (counter == 0)
{
ImGui.Separator();
}
if (questInfo.PreviousQuests.Count > 1)
{
if (questInfo.PreviousQuestJoin == EQuestJoin.All)
{
ImGui.Text("Requires all:");
}
else if (questInfo.PreviousQuestJoin == EQuestJoin.AtLeastOne)
{
ImGui.Text("Requires one:");
}
}
foreach (PreviousQuestInfo previousQuest in questInfo.PreviousQuests)
{
if (_questData.TryGetQuestInfo(previousQuest.QuestId, out IQuestInfo questInfo2))
{
var (color, fontAwesomeIcon, _) = _uiUtils.GetQuestStyle(previousQuest.QuestId);
if (!_questRegistry.IsKnownQuest(questInfo2.QuestId))
{
color = ImGuiColors.DalamudGrey;
}
_uiUtils.ChecklistItem(FormatQuestUnlockName(questInfo2, (byte)((!_questFunctions.IsQuestComplete(previousQuest.QuestId)) ? previousQuest.Sequence : 0)), color, fontAwesomeIcon);
if (questInfo2 is QuestInfo questInfo3 && (counter <= 2 || fontAwesomeIcon != FontAwesomeIcon.Check))
{
DrawQuestUnlocks(questInfo3, counter + 1, showItemRewards: false);
}
}
else
{
using (ImRaii.Disabled())
{
_uiUtils.ChecklistItem($"Unknown Quest ({previousQuest.QuestId})", ImGuiColors.DalamudGrey, FontAwesomeIcon.Question);
}
}
}
}
if (questInfo is QuestInfo questInfo4)
{
if (questInfo4.MoogleDeliveryLevel > 0)
{
ImU8String text = new ImU8String(23, 1);
text.AppendLiteral("Requires Carrier Level ");
text.AppendFormatted(questInfo4.MoogleDeliveryLevel);
ImGui.Text(text);
}
if (counter == 0 && questInfo4.QuestLocks.Count > 0)
{
ImGui.Separator();
if (questInfo4.QuestLocks.Count > 1)
{
if (questInfo4.QuestLockJoin == EQuestJoin.All)
{
ImGui.Text("Blocked by (if all completed):");
}
else if (questInfo4.QuestLockJoin == EQuestJoin.AtLeastOne)
{
ImGui.Text("Blocked by (if at least completed):");
}
}
else
{
ImGui.Text("Blocked by (if completed):");
}
foreach (QuestId questLock in questInfo4.QuestLocks)
{
IQuestInfo questInfo5 = _questData.GetQuestInfo(questLock);
var (color2, icon, _) = _uiUtils.GetQuestStyle(questLock);
if (!_questRegistry.IsKnownQuest(questInfo5.QuestId))
{
color2 = ImGuiColors.DalamudGrey;
}
_uiUtils.ChecklistItem(FormatQuestUnlockName(questInfo5, 0), color2, icon);
}
}
if (counter == 0 && questInfo4.PreviousInstanceContent.Count > 0)
{
ImGui.Separator();
if (questInfo4.PreviousInstanceContent.Count > 1)
{
if (questInfo.PreviousQuestJoin == EQuestJoin.All)
{
ImGui.Text("Requires all:");
}
else if (questInfo.PreviousQuestJoin == EQuestJoin.AtLeastOne)
{
ImGui.Text("Requires one:");
}
}
else
{
ImGui.Text("Requires:");
}
foreach (ushort item in questInfo4.PreviousInstanceContent)
{
string text2 = _territoryData.GetInstanceName(item) ?? "?";
var (color3, icon2) = UiUtils.GetInstanceStyle(item);
_uiUtils.ChecklistItem(text2, color3, icon2);
}
}
if (counter == 0 && questInfo4.GrandCompany != GrandCompany.None)
{
ImGui.Separator();
string text3 = questInfo4.GrandCompany switch
{
GrandCompany.Maelstrom => "Maelstrom",
GrandCompany.TwinAdder => "Twin Adder",
GrandCompany.ImmortalFlames => "Immortal Flames",
_ => "None",
};
GrandCompany grandCompany = _questFunctions.GetGrandCompany();
_uiUtils.ChecklistItem("Grand Company: " + text3, questInfo4.GrandCompany == grandCompany);
}
if (showItemRewards && questInfo4.ItemRewards.Count > 0)
{
ImGui.Separator();
ImGui.Text("Item Rewards:");
foreach (ItemReward itemReward in questInfo4.ItemRewards)
{
ImGui.BulletText(itemReward.Name);
}
}
}
if (counter > 0)
{
ImGui.Unindent();
}
}
private string FormatQuestUnlockName(IQuestInfo questInfo, byte sequence = 0)
{
string text = questInfo.Name;
if (_configuration.Advanced.AdditionalStatusInformation && sequence != 0)
{
text = text + " " + SeIconChar.ItemLevel.ToIconString();
}
if (questInfo.IsMainScenarioQuest)
{
return text + $" ({questInfo.QuestId}, MSQ)";
}
return text + $" ({questInfo.QuestId})";
}
}

View file

@ -0,0 +1,174 @@
using System;
using System.Globalization;
using System.Numerics;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using Questionable.Controller;
namespace Questionable.Windows.QuestComponents;
internal sealed class QuickAccessButtonsComponent
{
private readonly QuestRegistry _questRegistry;
private readonly QuestValidationWindow _questValidationWindow;
private readonly JournalProgressWindow _journalProgressWindow;
private readonly PriorityWindow _priorityWindow;
private readonly ICommandManager _commandManager;
private readonly IDalamudPluginInterface _pluginInterface;
public event EventHandler? Reload;
public QuickAccessButtonsComponent(QuestRegistry questRegistry, QuestValidationWindow questValidationWindow, JournalProgressWindow journalProgressWindow, PriorityWindow priorityWindow, ICommandManager commandManager, IDalamudPluginInterface pluginInterface)
{
_questRegistry = questRegistry;
_questValidationWindow = questValidationWindow;
_journalProgressWindow = journalProgressWindow;
_priorityWindow = priorityWindow;
_commandManager = commandManager;
_pluginInterface = pluginInterface;
}
public void Draw()
{
DrawQuestPriorityButton();
ImGui.SameLine();
DrawRebuildNavmeshButton();
DrawReloadDataButton();
ImGui.SameLine();
DrawJournalProgressButton();
if (_questRegistry.ValidationIssueCount > 0)
{
ImGui.SameLine();
DrawValidationIssuesButton();
}
}
private void DrawQuestPriorityButton()
{
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Exclamation, "Priority Quests"))
{
_priorityWindow.ToggleOrUncollapse();
}
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Configure priority quests which will be done as soon as possible.");
}
}
private void DrawRebuildNavmeshButton()
{
bool flag = _commandManager.Commands.ContainsKey("/vnav");
using (ImRaii.Disabled(!flag || !ImGui.IsKeyDown(ImGuiKey.ModCtrl)))
{
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.GlobeEurope, "Rebuild Navmesh"))
{
_commandManager.ProcessCommand("/vnav rebuild");
}
}
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
{
if (!flag)
{
ImGui.SetTooltip("vnavmesh is not available.\nPlease install it first.");
}
else
{
ImGui.SetTooltip("Hold CTRL to enable this button.\nRebuilding the navmesh will take some time.");
}
}
}
private void DrawReloadDataButton()
{
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.RedoAlt, "Reload Data"))
{
this.Reload?.Invoke(this, EventArgs.Empty);
}
}
private void DrawJournalProgressButton()
{
if (ImGuiComponents.IconButton(FontAwesomeIcon.BookBookmark))
{
_journalProgressWindow.IsOpenAndUncollapsed = true;
}
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Journal Progress");
}
}
private void DrawValidationIssuesButton()
{
int validationErrorCount = _questRegistry.ValidationErrorCount;
int num = _questRegistry.ValidationIssueCount - _questRegistry.ValidationErrorCount;
if (validationErrorCount == 0 && num == 0)
{
return;
}
int num2 = ((validationErrorCount == 0 || num == 0) ? 1 : 2);
using (ImRaii.PushId("validationissues"))
{
FontAwesomeIcon icon = FontAwesomeIcon.ExclamationTriangle;
FontAwesomeIcon icon2 = FontAwesomeIcon.InfoCircle;
Vector2 vector;
Vector2 vector2;
using (_pluginInterface.UiBuilder.IconFontFixedWidthHandle.Push())
{
vector = ((validationErrorCount > 0) ? ImGui.CalcTextSize(icon.ToIconString()) : Vector2.Zero);
vector2 = ((num > 0) ? ImGui.CalcTextSize(icon2.ToIconString()) : Vector2.Zero);
}
string text = ((validationErrorCount > 0) ? validationErrorCount.ToString(CultureInfo.InvariantCulture) : string.Empty);
string text2 = ((num > 0) ? num.ToString(CultureInfo.InvariantCulture) : string.Empty);
Vector2 vector3 = ((validationErrorCount > 0) ? ImGui.CalcTextSize(text) : Vector2.Zero);
Vector2 vector4 = ((num > 0) ? ImGui.CalcTextSize(text2) : Vector2.Zero);
ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList();
Vector2 cursorScreenPos = ImGui.GetCursorScreenPos();
float num3 = 3f * ImGuiHelpers.GlobalScale;
float x = vector.X + vector2.X + vector3.X + vector4.X + ImGui.GetStyle().FramePadding.X * 2f + num3 * 2f * (float)num2;
float frameHeight = ImGui.GetFrameHeight();
bool flag = ImGui.Button(string.Empty, new Vector2(x, frameHeight));
Vector2 vector5 = new Vector2(cursorScreenPos.X + ImGui.GetStyle().FramePadding.X, cursorScreenPos.Y + ImGui.GetStyle().FramePadding.Y);
if (validationErrorCount > 0)
{
using (_pluginInterface.UiBuilder.IconFontFixedWidthHandle.Push())
{
windowDrawList.AddText(vector5, ImGui.GetColorU32(ImGuiColors.DalamudRed), icon.ToIconString());
}
Vector2 vector6 = vector5;
vector6.X = vector5.X + vector.X + num3;
vector5 = vector6;
windowDrawList.AddText(vector5, ImGui.GetColorU32(ImGuiCol.Text), text);
vector6 = vector5;
vector6.X = vector5.X + vector3.X + 2f * num3;
vector5 = vector6;
}
if (num > 0)
{
using (_pluginInterface.UiBuilder.IconFontFixedWidthHandle.Push())
{
windowDrawList.AddText(vector5, ImGui.GetColorU32(ImGuiColors.ParsedBlue), icon2.ToIconString());
}
Vector2 vector6 = vector5;
vector6.X = vector5.X + vector2.X + num3;
vector5 = vector6;
windowDrawList.AddText(vector5, ImGui.GetColorU32(ImGuiCol.Text), text2);
}
if (flag)
{
_questValidationWindow.IsOpenAndUncollapsed = true;
}
}
}
}

View file

@ -0,0 +1,49 @@
using System.Collections.Generic;
using Dalamud.Bindings.ImGui;
using Questionable.Controller;
namespace Questionable.Windows.QuestComponents;
internal sealed class RemainingTasksComponent
{
private readonly QuestController _questController;
private readonly GatheringController _gatheringController;
public RemainingTasksComponent(QuestController questController, GatheringController gatheringController)
{
_questController = questController;
_gatheringController = gatheringController;
}
public void Draw()
{
IList<string> remainingTaskNames = _gatheringController.GetRemainingTaskNames();
if (remainingTaskNames.Count > 0)
{
ImGui.Separator();
ImGui.BeginDisabled();
foreach (string item in remainingTaskNames)
{
ImU8String text = new ImU8String(3, 1);
text.AppendLiteral("G: ");
text.AppendFormatted(item);
ImGui.TextUnformatted(text);
}
ImGui.EndDisabled();
return;
}
IList<string> remainingTaskNames2 = _questController.GetRemainingTaskNames();
if (remainingTaskNames2.Count <= 0)
{
return;
}
ImGui.Separator();
ImGui.BeginDisabled();
foreach (string item2 in remainingTaskNames2)
{
ImGui.TextUnformatted(item2);
}
ImGui.EndDisabled();
}
}