forked from aly/qstbak
916 lines
31 KiB
C#
916 lines
31 KiB
C#
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.Utility.Raii;
|
|
using Dalamud.Plugin.Services;
|
|
using Lumina.Excel.Sheets;
|
|
using Microsoft.Extensions.Logging;
|
|
using Questionable.Controller;
|
|
using Questionable.Controller.Conditions;
|
|
using Questionable.External;
|
|
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 FishingController _fishingController;
|
|
|
|
private readonly FateController _fateController;
|
|
|
|
private readonly SeasonalDutyController _seasonalDutyController;
|
|
|
|
private readonly AttunementController _attunementController;
|
|
|
|
private readonly CustomDeliveryController _customDeliveryController;
|
|
|
|
private readonly QuestFunctions _questFunctions;
|
|
|
|
private readonly Configuration _configuration;
|
|
|
|
private readonly QuestRegistry _questRegistry;
|
|
|
|
private readonly UiUtils _uiUtils;
|
|
|
|
private readonly IObjectTable _objectTable;
|
|
|
|
private readonly IClientState _clientState;
|
|
|
|
private readonly IChatGui _chatGui;
|
|
|
|
private readonly AutoDutyIpc _autoDutyIpc;
|
|
|
|
private readonly IDataManager _dataManager;
|
|
|
|
private readonly ILogger<ActiveQuestComponent> _logger;
|
|
|
|
private bool _questCardExpanded;
|
|
|
|
public event System.Action? OpenQueueTab;
|
|
|
|
[GeneratedRegex("\\s\\s+", RegexOptions.IgnoreCase, "en-US")]
|
|
[GeneratedCode("System.Text.RegularExpressions.Generator", "10.0.14.37416")]
|
|
private static Regex MultipleWhitespaceRegex()
|
|
{
|
|
return _003CRegexGenerator_g_003EFF909AF37F4C319C8940E7DA0E71D9E470824ECE485FE299B23B08984F5D534F6__MultipleWhitespaceRegex_0.Instance;
|
|
}
|
|
|
|
public ActiveQuestComponent(QuestController questController, MovementController movementController, CombatController combatController, GatheringController gatheringController, FishingController fishingController, FateController fateController, SeasonalDutyController seasonalDutyController, AttunementController attunementController, CustomDeliveryController customDeliveryController, QuestFunctions questFunctions, Configuration configuration, QuestRegistry questRegistry, UiUtils uiUtils, IObjectTable objectTable, IClientState clientState, IChatGui chatGui, AutoDutyIpc autoDutyIpc, IDataManager dataManager, ILogger<ActiveQuestComponent> logger)
|
|
{
|
|
_questController = questController;
|
|
_movementController = movementController;
|
|
_combatController = combatController;
|
|
_gatheringController = gatheringController;
|
|
_fishingController = fishingController;
|
|
_fateController = fateController;
|
|
_seasonalDutyController = seasonalDutyController;
|
|
_attunementController = attunementController;
|
|
_customDeliveryController = customDeliveryController;
|
|
_questFunctions = questFunctions;
|
|
_configuration = configuration;
|
|
_questRegistry = questRegistry;
|
|
_uiUtils = uiUtils;
|
|
_objectTable = objectTable;
|
|
_clientState = clientState;
|
|
_chatGui = chatGui;
|
|
_autoDutyIpc = autoDutyIpc;
|
|
_dataManager = dataManager;
|
|
_logger = logger;
|
|
}
|
|
|
|
public void Draw(bool isMinimized)
|
|
{
|
|
if (_fateController.IsRunning)
|
|
{
|
|
DrawFateActive(isMinimized);
|
|
return;
|
|
}
|
|
if (_seasonalDutyController.IsRunning)
|
|
{
|
|
DrawDutyActive(isMinimized);
|
|
return;
|
|
}
|
|
if (_customDeliveryController.IsRunning)
|
|
{
|
|
DrawCustomDeliveryActive(isMinimized);
|
|
return;
|
|
}
|
|
if (_gatheringController.IsRunning)
|
|
{
|
|
DrawGatheringActive(isMinimized);
|
|
return;
|
|
}
|
|
if (_fishingController.IsRunning)
|
|
{
|
|
DrawFishingActive(isMinimized);
|
|
return;
|
|
}
|
|
(QuestController.QuestProgress, QuestController.ECurrentQuestType)? currentQuestDetails = _questController.CurrentQuestDetails;
|
|
QuestController.QuestProgress questProgress = currentQuestDetails?.Item1;
|
|
QuestController.ECurrentQuestType? currentQuestType = currentQuestDetails?.Item2;
|
|
if (questProgress != null)
|
|
{
|
|
if (isMinimized)
|
|
{
|
|
DrawMinimizedQuest(questProgress);
|
|
}
|
|
else
|
|
{
|
|
DrawQuestCard(questProgress, currentQuestType);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DrawNoActiveQuest(isMinimized);
|
|
}
|
|
}
|
|
|
|
private void DrawFateActive(bool isMinimized)
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.ParsedGold))
|
|
{
|
|
ImGui.TextUnformatted(UiThemeUtils.TruncateToWidth("FATE: " + _fateController.CurrentFate.Name, ImGui.GetContentRegionAvail().X));
|
|
}
|
|
IList<string> remainingTaskNames = _fateController.GetRemainingTaskNames();
|
|
if (remainingTaskNames.Count > 0)
|
|
{
|
|
UiThemeUtils.WrappedTextColored(UiThemeUtils.DimTextColor, remainingTaskNames[0]);
|
|
}
|
|
if (!isMinimized)
|
|
{
|
|
string text = (_fateController.CycleLimit.HasValue ? $"Cycle {_fateController.CompletedCycles + 1} / {_fateController.CycleLimit}" : $"Cycle {_fateController.CompletedCycles + 1}");
|
|
ImGui.TextColored(in UiThemeUtils.MutedTextColor, text);
|
|
}
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.Stop, ImGui.GetFrameHeight()))
|
|
{
|
|
_fateController.Stop("UI stop");
|
|
_movementController.Stop();
|
|
}
|
|
}
|
|
|
|
private void DrawDutyActive(bool isMinimized)
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.ParsedGreen))
|
|
{
|
|
ImGui.TextUnformatted(UiThemeUtils.TruncateToWidth("Duty: " + _seasonalDutyController.CurrentDuty.Name, ImGui.GetContentRegionAvail().X));
|
|
}
|
|
IList<string> remainingTaskNames = _seasonalDutyController.GetRemainingTaskNames();
|
|
if (remainingTaskNames.Count > 0)
|
|
{
|
|
UiThemeUtils.WrappedTextColored(UiThemeUtils.DimTextColor, remainingTaskNames[0]);
|
|
}
|
|
if (!isMinimized)
|
|
{
|
|
string text = (_seasonalDutyController.CycleLimit.HasValue ? $"Cycle {_seasonalDutyController.CompletedCycles + 1} / {_seasonalDutyController.CycleLimit}" : $"Cycle {_seasonalDutyController.CompletedCycles + 1}");
|
|
ImGui.TextColored(in UiThemeUtils.MutedTextColor, text);
|
|
}
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.Stop, ImGui.GetFrameHeight()))
|
|
{
|
|
_seasonalDutyController.Stop("UI stop");
|
|
_movementController.Stop();
|
|
}
|
|
}
|
|
|
|
private void DrawCustomDeliveryActive(bool isMinimized)
|
|
{
|
|
string text = _customDeliveryController.CurrentNpcName ?? "Custom Delivery";
|
|
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.ParsedPurple))
|
|
{
|
|
ImGui.TextUnformatted(UiThemeUtils.TruncateToWidth("Delivery: " + text, ImGui.GetContentRegionAvail().X));
|
|
}
|
|
UiThemeUtils.WrappedTextColored(ImGuiColors.DalamudOrange, _customDeliveryController.StatusLabel);
|
|
IList<string> remainingTaskNames = _customDeliveryController.GetRemainingTaskNames();
|
|
if (remainingTaskNames.Count > 0)
|
|
{
|
|
UiThemeUtils.WrappedTextColored(UiThemeUtils.DimTextColor, remainingTaskNames[0]);
|
|
}
|
|
if (!isMinimized)
|
|
{
|
|
int queueRemaining = _customDeliveryController.QueueRemaining;
|
|
if (queueRemaining > 0)
|
|
{
|
|
ImU8String text2 = new ImU8String(19, 1);
|
|
text2.AppendFormatted(queueRemaining);
|
|
text2.AppendLiteral(" more NPC(s) queued");
|
|
ImGui.TextColored(in UiThemeUtils.MutedTextColor, text2);
|
|
}
|
|
}
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.Stop, ImGui.GetFrameHeight()))
|
|
{
|
|
_customDeliveryController.Stop("UI stop");
|
|
_movementController.Stop();
|
|
}
|
|
}
|
|
|
|
private void DrawGatheringActive(bool isMinimized)
|
|
{
|
|
string text = ResolveItemName(_gatheringController.CurrentItemId) ?? "Gathering";
|
|
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.ParsedGold))
|
|
{
|
|
ImGui.TextUnformatted(UiThemeUtils.TruncateToWidth("Gathering: " + text, ImGui.GetContentRegionAvail().X));
|
|
}
|
|
IList<string> remainingTaskNames = _gatheringController.GetRemainingTaskNames();
|
|
if (remainingTaskNames.Count > 0)
|
|
{
|
|
UiThemeUtils.WrappedTextColored(UiThemeUtils.DimTextColor, remainingTaskNames[0]);
|
|
}
|
|
if (!isMinimized && remainingTaskNames.Count > 1)
|
|
{
|
|
ImU8String text2 = new ImU8String(13, 1);
|
|
text2.AppendFormatted(remainingTaskNames.Count - 1);
|
|
text2.AppendLiteral(" more task(s)");
|
|
ImGui.TextColored(in UiThemeUtils.MutedTextColor, text2);
|
|
}
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.Stop, ImGui.GetFrameHeight()))
|
|
{
|
|
_gatheringController.Stop("UI stop");
|
|
_movementController.Stop();
|
|
}
|
|
}
|
|
|
|
private void DrawFishingActive(bool isMinimized)
|
|
{
|
|
string text = ResolveItemName(_fishingController.CurrentItemId) ?? "Fishing";
|
|
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.ParsedBlue))
|
|
{
|
|
ImGui.TextUnformatted(UiThemeUtils.TruncateToWidth("Fishing: " + text, ImGui.GetContentRegionAvail().X));
|
|
}
|
|
IList<string> remainingTaskNames = _fishingController.GetRemainingTaskNames();
|
|
if (remainingTaskNames.Count > 0)
|
|
{
|
|
UiThemeUtils.WrappedTextColored(UiThemeUtils.DimTextColor, remainingTaskNames[0]);
|
|
}
|
|
if (!isMinimized)
|
|
{
|
|
string text2 = _fishingController.State.ToString();
|
|
ImGui.TextColored(in UiThemeUtils.MutedTextColor, text2);
|
|
}
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.Stop, ImGui.GetFrameHeight()))
|
|
{
|
|
_fishingController.Stop("UI stop");
|
|
_movementController.Stop();
|
|
}
|
|
}
|
|
|
|
private string? ResolveItemName(uint? itemId)
|
|
{
|
|
if (!itemId.HasValue)
|
|
{
|
|
return null;
|
|
}
|
|
if (_dataManager.GetExcelSheet<Item>().TryGetRow(itemId.Value, out var row))
|
|
{
|
|
return row.Name.ToString();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void StopAllControllers(string reason)
|
|
{
|
|
_movementController.Stop();
|
|
_questController.Stop(reason);
|
|
_gatheringController.Stop(reason);
|
|
_fishingController.Stop(reason);
|
|
_fateController.Stop(reason);
|
|
_seasonalDutyController.Stop(reason);
|
|
_customDeliveryController.Stop(reason);
|
|
_attunementController.Stop(reason);
|
|
}
|
|
|
|
private void DrawStopConditionTooltip()
|
|
{
|
|
if ((_configuration.Stop.Conditions.Count == 0 && _questController.SessionConditions.Count == 0) || !ImGui.IsItemHovered())
|
|
{
|
|
return;
|
|
}
|
|
ImGui.BeginTooltip();
|
|
ImGui.TextUnformatted("Stop conditions:");
|
|
foreach (StopCondition condition in _configuration.Stop.Conditions)
|
|
{
|
|
ImU8String text = new ImU8String(3, 2);
|
|
text.AppendLiteral("[");
|
|
text.AppendFormatted(condition.Mode);
|
|
text.AppendLiteral("] ");
|
|
text.AppendFormatted(condition.GetDescription());
|
|
ImGui.BulletText(text);
|
|
}
|
|
foreach (StopCondition sessionCondition in _questController.SessionConditions)
|
|
{
|
|
ImU8String text2 = new ImU8String(3, 2);
|
|
text2.AppendLiteral("[");
|
|
text2.AppendFormatted(sessionCondition.Mode);
|
|
text2.AppendLiteral("] ");
|
|
text2.AppendFormatted(sessionCondition.GetDescription());
|
|
ImGui.BulletText(text2);
|
|
}
|
|
ImGui.EndTooltip();
|
|
}
|
|
|
|
private void DrawMinimizedQuest(QuestController.QuestProgress currentQuest)
|
|
{
|
|
QuestController.QuestProgress startedQuest = _questController.StartedQuest;
|
|
string text = ((startedQuest != null) ? Shorten(startedQuest.Quest.Info.Name) : Shorten(currentQuest.Quest.Info.Name));
|
|
float cursorPosX = ImGui.GetCursorPosX();
|
|
float x = ImGui.GetContentRegionAvail().X;
|
|
float frameHeight = ImGui.GetFrameHeight();
|
|
float x2 = ImGui.GetStyle().ItemSpacing.X;
|
|
float num = frameHeight * 4f + x2 * 3f;
|
|
ImGui.TextColored(in UiThemeUtils.AccentColor, UiThemeUtils.TruncateToWidth(text, x - num - x2));
|
|
ImGui.SameLine(cursorPosX + x - num);
|
|
using (ImRaii.Disabled(_questController.IsRunning || _gatheringController.IsRunning || _fishingController.IsRunning || _fateController.IsRunning || _seasonalDutyController.IsRunning || _customDeliveryController.IsRunning || _attunementController.IsRunning))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Button, UiThemeUtils.PlayButtonColor))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.ButtonHovered, UiThemeUtils.PlayButtonHover))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.ButtonActive, UiThemeUtils.PlayButtonActive))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Text, UiThemeUtils.PlayButtonText))
|
|
{
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.Play, frameHeight))
|
|
{
|
|
if (_questFunctions.GetQuestProgressInfo(currentQuest.Quest.Id) == null)
|
|
{
|
|
_questController.SetNextQuest(currentQuest.Quest);
|
|
}
|
|
_questController.Start("UI start");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ImGui.SameLine();
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.StepForward, frameHeight))
|
|
{
|
|
_questController.StartSingleStep("UI step");
|
|
}
|
|
ImGui.SameLine();
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.Stop, frameHeight))
|
|
{
|
|
StopAllControllers("UI stop");
|
|
}
|
|
ImGui.SameLine();
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.Forward, frameHeight))
|
|
{
|
|
_movementController.Stop();
|
|
_questController.Skip(currentQuest.Quest.Id, currentQuest.Sequence);
|
|
}
|
|
int num2 = currentQuest.Quest.FindSequence(currentQuest.Sequence)?.Steps.Count ?? 0;
|
|
float fraction = ((num2 > 0) ? ((float)currentQuest.Step / (float)num2) : 0f);
|
|
using (UiThemeUtils.PushProgressBarColors())
|
|
{
|
|
ImGui.ProgressBar(fraction, new Vector2(-1f, 3f), string.Empty);
|
|
}
|
|
int value = Math.Min(currentQuest.Step + 1, Math.Max(num2, 1));
|
|
string text2 = null;
|
|
if (_combatController.IsRunning)
|
|
{
|
|
text2 = "In Combat";
|
|
}
|
|
else
|
|
{
|
|
string currentTaskState = _questController.CurrentTaskState;
|
|
if (currentTaskState != null)
|
|
{
|
|
text2 = currentTaskState;
|
|
}
|
|
else if (!string.IsNullOrEmpty(_questController.DebugState))
|
|
{
|
|
text2 = _questController.DebugState;
|
|
}
|
|
}
|
|
string text3 = ((text2 != null) ? $"Step {value}/{num2} - {text2}" : $"Step {value}/{num2}");
|
|
using (ImRaii.PushColor(ImGuiCol.Text, UiThemeUtils.DimTextColor))
|
|
{
|
|
UiThemeUtils.WrappedText(text3);
|
|
}
|
|
}
|
|
|
|
private void DrawNoActiveQuest(bool isMinimized)
|
|
{
|
|
(Vector2 ContentStartPos, float AvailableWidth, ImDrawListPtr DrawList) tuple = UiThemeUtils.BeginCard();
|
|
Vector2 item = tuple.ContentStartPos;
|
|
float item2 = tuple.AvailableWidth;
|
|
ImDrawListPtr item3 = tuple.DrawList;
|
|
float cursorPosX = ImGui.GetCursorPosX();
|
|
float num = ImGui.GetContentRegionAvail().X - 12f;
|
|
try
|
|
{
|
|
(bool isLevelLocked, int levelsNeeded, int requiredLevel, string? questName) msqLevelLockInfo = _questFunctions.GetMsqLevelLockInfo();
|
|
bool item4 = msqLevelLockInfo.isLevelLocked;
|
|
int item5 = msqLevelLockInfo.levelsNeeded;
|
|
int item6 = msqLevelLockInfo.requiredLevel;
|
|
string item7 = msqLevelLockInfo.questName;
|
|
int currentPlayerLevel = _objectTable.LocalPlayer?.Level ?? 0;
|
|
if (item4 && _autoDutyIpc.IsConfiguredToRunLevelingMode(currentPlayerLevel) && item7 != null)
|
|
{
|
|
ImGui.PushTextWrapPos(cursorPosX + num);
|
|
Vector4 col = ImGuiColors.DalamudYellow;
|
|
ImU8String text = new ImU8String(22, 2);
|
|
text.AppendLiteral("MSQ '");
|
|
text.AppendFormatted(item7);
|
|
text.AppendLiteral("' requires level ");
|
|
text.AppendFormatted(item6);
|
|
ImGui.TextColored(in col, text);
|
|
using (ImRaii.PushColor(ImGuiCol.Text, UiThemeUtils.DimTextColor))
|
|
{
|
|
ImU8String text2 = new ImU8String(57, 2);
|
|
text2.AppendLiteral("Need ");
|
|
text2.AppendFormatted(item5);
|
|
text2.AppendLiteral(" more level");
|
|
text2.AppendFormatted((item5 == 1) ? string.Empty : "s");
|
|
text2.AppendLiteral(" - Leveling mode will start automatically");
|
|
ImGui.TextUnformatted(text2);
|
|
}
|
|
ImGui.PopTextWrapPos();
|
|
float frameHeight = ImGui.GetFrameHeight();
|
|
using (ImRaii.Disabled(_questController.IsRunning || _gatheringController.IsRunning || _fishingController.IsRunning || _fateController.IsRunning || _seasonalDutyController.IsRunning || _customDeliveryController.IsRunning || _attunementController.IsRunning || !_autoDutyIpc.IsStopped()))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Button, UiThemeUtils.PlayButtonColor))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.ButtonHovered, UiThemeUtils.PlayButtonHover))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.ButtonActive, UiThemeUtils.PlayButtonActive))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Text, UiThemeUtils.PlayButtonText))
|
|
{
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.Play, frameHeight))
|
|
{
|
|
_logger.LogInformation("Start button clicked with MSQ level-locked. Starting AutoDuty leveling mode.");
|
|
if (_autoDutyIpc.StartLevelingMode())
|
|
{
|
|
_chatGui.Print($"Starting AutoDuty Leveling mode to reach level {item6} for MSQ '{item7}'.", "Questionable", 576);
|
|
}
|
|
else
|
|
{
|
|
_chatGui.PrintError("Failed to start AutoDuty Leveling mode. Please check that AutoDuty is installed and configured.", "Questionable", 576);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
|
{
|
|
if (!_autoDutyIpc.IsStopped())
|
|
{
|
|
ImGui.SetTooltip("AutoDuty is currently running.");
|
|
}
|
|
else
|
|
{
|
|
ImU8String tooltip = new ImU8String(53, 1);
|
|
tooltip.AppendLiteral("Start AutoDuty Leveling mode to reach level ");
|
|
tooltip.AppendFormatted(item6);
|
|
tooltip.AppendLiteral(" for MSQ.");
|
|
ImGui.SetTooltip(tooltip);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Text, UiThemeUtils.DimTextColor))
|
|
{
|
|
ImGui.TextUnformatted("No active quest");
|
|
}
|
|
string lastStopReason = _questController.LastStopReason;
|
|
if (lastStopReason != null)
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow))
|
|
{
|
|
UiThemeUtils.WrappedText(lastStopReason);
|
|
}
|
|
}
|
|
}
|
|
if (!isMinimized)
|
|
{
|
|
float frameHeight2 = ImGui.GetFrameHeight();
|
|
float x = ImGui.GetStyle().ItemSpacing.X;
|
|
float num2 = frameHeight2 * 2f + x;
|
|
using (ImRaii.PushColor(ImGuiCol.Text, UiThemeUtils.MutedTextColor))
|
|
{
|
|
ImU8String text3 = new ImU8String(14, 1);
|
|
text3.AppendFormatted(_questRegistry.Count);
|
|
text3.AppendLiteral(" quests loaded");
|
|
ImGui.TextUnformatted(text3);
|
|
}
|
|
ImGui.SameLine();
|
|
ImGui.SetCursorPosX(cursorPosX + num - num2);
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.Stop, frameHeight2))
|
|
{
|
|
StopAllControllers("Manual (no active quest)");
|
|
if (!_autoDutyIpc.IsStopped())
|
|
{
|
|
try
|
|
{
|
|
_autoDutyIpc.Stop();
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
_logger.LogWarning(exception, "Failed to stop AutoDuty");
|
|
}
|
|
}
|
|
}
|
|
ImGui.SameLine();
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.SortAmountDown, frameHeight2))
|
|
{
|
|
this.OpenQueueTab?.Invoke();
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UiThemeUtils.WrappedTextColored(ImGuiColors.DalamudRed, ex.ToString());
|
|
}
|
|
UiThemeUtils.EndCard(item, item2, item3);
|
|
}
|
|
|
|
private void DrawQuestCard(QuestController.QuestProgress currentQuest, QuestController.ECurrentQuestType? currentQuestType)
|
|
{
|
|
QuestController.QuestProgress startedQuest = _questController.StartedQuest;
|
|
QuestSequence questSequence = currentQuest.Quest.FindSequence(currentQuest.Sequence);
|
|
QuestStep questStep = questSequence?.FindStep(currentQuest.Step);
|
|
QuestProgressInfo questProgressInfo = _questFunctions.GetQuestProgressInfo(currentQuest.Quest.Id);
|
|
(Vector2 ContentStartPos, float AvailableWidth, ImDrawListPtr DrawList) tuple = UiThemeUtils.BeginCard();
|
|
Vector2 item = tuple.ContentStartPos;
|
|
float item2 = tuple.AvailableWidth;
|
|
ImDrawListPtr item3 = tuple.DrawList;
|
|
float cursorPosX = ImGui.GetCursorPosX();
|
|
float num = ImGui.GetContentRegionAvail().X - 12f;
|
|
try
|
|
{
|
|
float frameHeight = ImGui.GetFrameHeight();
|
|
float wrapLocalPosX = cursorPosX + num - frameHeight - ImGui.GetStyle().ItemSpacing.X;
|
|
if (currentQuestType == QuestController.ECurrentQuestType.Simulated)
|
|
{
|
|
ImGui.PushTextWrapPos(wrapLocalPosX);
|
|
Vector4 col = ImGuiColors.DalamudRed;
|
|
ImU8String text = new ImU8String(11, 1);
|
|
text.AppendLiteral("Simulated: ");
|
|
text.AppendFormatted(currentQuest.Quest.Info.Name);
|
|
ImGui.TextColored(in col, text);
|
|
ImGui.PopTextWrapPos();
|
|
}
|
|
else
|
|
{
|
|
if (startedQuest != null && startedQuest.Quest.Source == Questionable.Model.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.");
|
|
}
|
|
}
|
|
string text2 = ((startedQuest != null) ? startedQuest.Quest.Info.Name : currentQuest.Quest.Info.Name);
|
|
ImGui.PushTextWrapPos(wrapLocalPosX);
|
|
ImGui.TextColored(in UiThemeUtils.AccentColor, text2);
|
|
ImGui.PopTextWrapPos();
|
|
if (startedQuest != null && startedQuest.Quest.Root.Disabled)
|
|
{
|
|
ImGui.SameLine();
|
|
ImGui.TextColored(ImGuiColors.DalamudRed, "Disabled");
|
|
}
|
|
}
|
|
ImGui.SameLine();
|
|
ImGui.SetCursorPosX(cursorPosX + num - frameHeight);
|
|
FontAwesomeIcon icon = (_questCardExpanded ? FontAwesomeIcon.ChevronUp : FontAwesomeIcon.ChevronDown);
|
|
using (ImRaii.PushColor(ImGuiCol.Button, Vector4.Zero))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.ButtonHovered, UiThemeUtils.SubtleActiveColor))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.ButtonActive, UiThemeUtils.SubtlePressColor))
|
|
{
|
|
if (UiThemeUtils.IconButton(icon, frameHeight))
|
|
{
|
|
_questCardExpanded = !_questCardExpanded;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
string text3 = null;
|
|
if (_combatController.IsRunning)
|
|
{
|
|
text3 = "In Combat";
|
|
}
|
|
else
|
|
{
|
|
string currentTaskState = _questController.CurrentTaskState;
|
|
if (currentTaskState != null)
|
|
{
|
|
text3 = currentTaskState;
|
|
}
|
|
else if (!string.IsNullOrEmpty(_questController.DebugState))
|
|
{
|
|
text3 = _questController.DebugState;
|
|
}
|
|
}
|
|
ImGui.PushTextWrapPos(cursorPosX + num);
|
|
using (ImRaii.PushColor(ImGuiCol.Text, UiThemeUtils.DimTextColor))
|
|
{
|
|
ImGui.TextUnformatted(text3 ?? " ");
|
|
}
|
|
ImGui.PopTextWrapPos();
|
|
int num2 = questSequence?.Steps.Count ?? 0;
|
|
float fraction = ((num2 > 0) ? ((float)currentQuest.Step / (float)num2) : 0f);
|
|
using (UiThemeUtils.PushProgressBarColors())
|
|
{
|
|
ImGui.ProgressBar(fraction, new Vector2(num, 4f), string.Empty);
|
|
}
|
|
ImGui.Spacing();
|
|
ImGui.Spacing();
|
|
int value = Math.Min(currentQuest.Step + 1, Math.Max(num2, 1));
|
|
ImGui.AlignTextToFramePadding();
|
|
using (ImRaii.PushColor(ImGuiCol.Text, UiThemeUtils.MutedTextColor))
|
|
{
|
|
ImU8String text4 = new ImU8String(9, 2);
|
|
text4.AppendLiteral("Step ");
|
|
text4.AppendFormatted(value);
|
|
text4.AppendLiteral(" of ");
|
|
text4.AppendFormatted(num2);
|
|
ImGui.TextUnformatted(text4);
|
|
}
|
|
float frameHeight2 = ImGui.GetFrameHeight();
|
|
float x = ImGui.GetStyle().ItemSpacing.X;
|
|
Vector2 vector;
|
|
using (ImRaii.PushFont(UiBuilder.IconFont))
|
|
{
|
|
vector = ImGui.CalcTextSize(FontAwesomeIcon.Play.ToIconString());
|
|
}
|
|
float x2 = ImGui.CalcTextSize("Play").X;
|
|
float num3 = ImGui.GetStyle().FramePadding.X * 3f * 2f + vector.X + 6f + x2;
|
|
bool disabled = _questController.IsRunning || _gatheringController.IsRunning || _fishingController.IsRunning || _fateController.IsRunning || _seasonalDutyController.IsRunning || _customDeliveryController.IsRunning || _attunementController.IsRunning;
|
|
float num4 = num3 + (frameHeight2 + x) * 3f;
|
|
ImGui.SameLine();
|
|
ImGui.SetCursorPosX(cursorPosX + num - num4);
|
|
using (ImRaii.Disabled(disabled))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Button, UiThemeUtils.PlayButtonColor))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.ButtonHovered, UiThemeUtils.PlayButtonHover))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.ButtonActive, UiThemeUtils.PlayButtonActive))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Text, UiThemeUtils.PlayButtonText))
|
|
{
|
|
if (UiThemeUtils.IconTextButton(FontAwesomeIcon.Play, "Play", num3))
|
|
{
|
|
if (questProgressInfo == null)
|
|
{
|
|
_questController.SetNextQuest(currentQuest.Quest);
|
|
}
|
|
_questController.Start("UI start");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
|
{
|
|
ImGui.SetTooltip("Start automation");
|
|
}
|
|
}
|
|
ImGui.SameLine();
|
|
using (ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 1f))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Border, UiThemeUtils.CardBorderHighColor))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Button, new Vector4(0.12f, 0.1f, 0.18f, 1f)))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.ButtonHovered, new Vector4(0.2f, 0.16f, 0.28f, 1f)))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.ButtonActive, new Vector4(0.25f, 0.2f, 0.35f, 1f)))
|
|
{
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.StepForward, frameHeight2))
|
|
{
|
|
_questController.StartSingleStep("UI step");
|
|
}
|
|
if (ImGui.IsItemHovered())
|
|
{
|
|
ImGui.SetTooltip("Execute single step");
|
|
}
|
|
ImGui.SameLine();
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.Stop, frameHeight2))
|
|
{
|
|
StopAllControllers("UI stop");
|
|
}
|
|
DrawStopConditionTooltip();
|
|
ImGui.SameLine();
|
|
using (ImRaii.Disabled(questStep == currentQuest.Quest.FindSequence(currentQuest.Sequence)?.Steps.LastOrDefault()))
|
|
{
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.Forward, frameHeight2))
|
|
{
|
|
_movementController.Stop();
|
|
_questController.Skip(currentQuest.Quest.Id, currentQuest.Sequence);
|
|
}
|
|
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
|
{
|
|
ImGui.SetTooltip("Skip current step");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (_questCardExpanded)
|
|
{
|
|
ImGui.Spacing();
|
|
ImGui.PushTextWrapPos(cursorPosX + num);
|
|
if (startedQuest != null)
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Text, UiThemeUtils.DimTextColor))
|
|
{
|
|
ImU8String text5 = new ImU8String(15, 3);
|
|
text5.AppendFormatted(startedQuest.Quest.Id);
|
|
text5.AppendLiteral(" / Seq ");
|
|
text5.AppendFormatted(startedQuest.Sequence);
|
|
text5.AppendLiteral(" / Step ");
|
|
text5.AppendFormatted(startedQuest.Step);
|
|
ImGui.TextUnformatted(text5);
|
|
}
|
|
}
|
|
if (questProgressInfo != null)
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Text, UiThemeUtils.DimTextColor))
|
|
{
|
|
ImU8String text6 = new ImU8String(0, 1);
|
|
text6.AppendFormatted(questProgressInfo);
|
|
ImGui.TextUnformatted(text6);
|
|
if (ImGui.IsItemClicked())
|
|
{
|
|
string text7 = MultipleWhitespaceRegex().Replace(questProgressInfo.ToString(), " ");
|
|
ImGui.SetClipboardText(text7);
|
|
_chatGui.Print("Copied '" + text7 + "' to clipboard");
|
|
}
|
|
if (ImGui.IsItemHovered())
|
|
{
|
|
ImGui.SameLine();
|
|
ImGui.PushFont(UiBuilder.IconFont);
|
|
ImGui.Text(FontAwesomeIcon.Copy.ToIconString());
|
|
ImGui.PopFont();
|
|
}
|
|
if (currentQuest.Quest.Info.AlliedSociety != EAlliedSociety.None)
|
|
{
|
|
ImGui.SameLine();
|
|
ImU8String text8 = new ImU8String(2, 1);
|
|
text8.AppendLiteral("/ ");
|
|
text8.AppendFormatted(questProgressInfo.ClassJob);
|
|
ImGui.Text(text8);
|
|
}
|
|
}
|
|
}
|
|
using (ImRaii.ColorDisposable colorDisposable = new ImRaii.ColorDisposable())
|
|
{
|
|
bool flag;
|
|
if (questStep != null)
|
|
{
|
|
EInteractionType interactionType = questStep.InteractionType;
|
|
if (interactionType == EInteractionType.WaitForManualProgress || interactionType == EInteractionType.Snipe || interactionType == EInteractionType.Instruction)
|
|
{
|
|
flag = true;
|
|
goto IL_0935;
|
|
}
|
|
}
|
|
flag = false;
|
|
goto IL_0935;
|
|
IL_0935:
|
|
if (flag)
|
|
{
|
|
colorDisposable.Push(ImGuiCol.Text, ImGuiColors.DalamudOrange);
|
|
}
|
|
string text9 = questStep?.Comment ?? questSequence?.Comment ?? currentQuest.Quest.Root.Comment;
|
|
if (!string.IsNullOrEmpty(text9))
|
|
{
|
|
ImGui.TextUnformatted(text9);
|
|
}
|
|
}
|
|
ImGui.TextUnformatted(_questController.ToStatString());
|
|
QuestController.QuestProgress nextQuest = _questController.NextQuest;
|
|
if (nextQuest != null)
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow))
|
|
{
|
|
ImU8String text10 = new ImU8String(9, 2);
|
|
text10.AppendLiteral("Next: ");
|
|
text10.AppendFormatted(Shorten(nextQuest.Quest.Info.Name));
|
|
text10.AppendLiteral(" (");
|
|
text10.AppendFormatted(nextQuest.Quest.Id);
|
|
text10.AppendLiteral(")");
|
|
ImGui.TextUnformatted(text10);
|
|
}
|
|
}
|
|
ImGui.PopTextWrapPos();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UiThemeUtils.WrappedTextColored(ImGuiColors.DalamudRed, ex.ToString());
|
|
_logger.LogError(ex, "Could not handle active quest card");
|
|
}
|
|
UiThemeUtils.EndCard(item, item2, item3);
|
|
DrawSimulationControls();
|
|
}
|
|
|
|
private void DrawSimulationControls()
|
|
{
|
|
if (_questController.SimulatedQuest == null)
|
|
{
|
|
return;
|
|
}
|
|
QuestController.QuestProgress simulatedQuest = _questController.SimulatedQuest;
|
|
UiThemeUtils.SectionSpacing();
|
|
var (contentStartPos, availableWidth, drawList) = UiThemeUtils.BeginCard();
|
|
UiThemeUtils.SectionHeader("Simulation");
|
|
UiThemeUtils.WrappedTextColored(ImGuiColors.DalamudRed, "Quest sim active (experimental)");
|
|
UiThemeUtils.WrappedText($"Sequence: {simulatedQuest.Sequence}");
|
|
ImGui.BeginDisabled(simulatedQuest.Sequence == 0);
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.Minus, ImGui.GetFrameHeight()))
|
|
{
|
|
_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 (UiThemeUtils.IconButton(FontAwesomeIcon.Plus, ImGui.GetFrameHeight()))
|
|
{
|
|
_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)
|
|
{
|
|
using (ImRaii.PushId("SimulatedStep"))
|
|
{
|
|
UiThemeUtils.WrappedText($"Step: {simulatedQuest.Step} / {questSequence.Steps.Count - 1}");
|
|
ImGui.BeginDisabled(simulatedQuest.Step == 0);
|
|
if (UiThemeUtils.IconButton(FontAwesomeIcon.Minus, ImGui.GetFrameHeight()))
|
|
{
|
|
_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 (UiThemeUtils.IconButton(FontAwesomeIcon.Plus, ImGui.GetFrameHeight()))
|
|
{
|
|
_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");
|
|
}
|
|
}
|
|
}
|
|
UiThemeUtils.EndCard(contentStartPos, availableWidth, drawList);
|
|
}
|
|
|
|
private static string Shorten(string text)
|
|
{
|
|
if (text.Length > 35)
|
|
{
|
|
return string.Concat(text.AsSpan(0, 30).Trim(), ((SeIconChar)57434).ToIconString().AsSpan());
|
|
}
|
|
return text;
|
|
}
|
|
}
|