muffin v7.4.15

This commit is contained in:
alydev 2026-03-01 00:29:23 +10:00
parent 9bf3dbdf69
commit 0b1b2d38c7
14 changed files with 1215 additions and 1057 deletions

View file

@ -52,6 +52,11 @@
},
"minItems": 1
},
"RequiredQuestId": {
"description": "Quest ID that must be completed before this FATE can be farmed",
"type": "integer",
"minimum": 1
},
"RequiredStatusId": {
"description": "Status effect required to participate in the FATE",
"type": "string"
@ -65,6 +70,10 @@
"description": "Position of the transform NPC",
"$ref": "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/Questionable.Model/common-vector3.json"
},
"StopAction": {
"description": "Action to use when stopping FATE farming (e.g. to remove a transformation debuff). Only used if the player has RequiredStatusId.",
"type": "string"
},
"EventExpiry": {
"description": "If this is a seasonal/event FATE, the date and time (in UTC) when it is no longer available. Date-only values are treated as ending at daily reset (14:59:59 UTC).",
"format": "date-time",

View file

@ -478824,10 +478824,7 @@ public static class AssemblyQuestLoader
reference212 = obj228;
index2++;
ref QuestStep reference213 = ref span297[index2];
QuestStep obj229 = new QuestStep(EInteractionType.FateAction, null, new Vector3(-38.322124f, 3.9999998f, -144.23155f), 130)
{
Comment = "Use correct Cheer Rhythm color on each randomly-appearing performer NPC"
};
QuestStep questStep20 = new QuestStep(EInteractionType.FateAction, null, new Vector3(-38.322124f, 3.9999998f, -144.23155f), 130);
index3 = 4;
List<FateActionTarget> list299 = new List<FateActionTarget>(index3);
CollectionsMarshal.SetCount(list299, index3);
@ -478856,13 +478853,13 @@ public static class AssemblyQuestLoader
DataId = 18859u,
Action = EAction.CheerRhythmRed
};
obj229.FateActionTargets = list299;
reference213 = obj229;
questStep20.FateActionTargets = list299;
reference213 = questStep20;
obj227.Steps = list297;
reference211 = obj227;
num++;
ref QuestSequence reference214 = ref span287[num];
QuestSequence obj230 = new QuestSequence
QuestSequence obj229 = new QuestSequence
{
Sequence = byte.MaxValue
};
@ -478875,8 +478872,8 @@ public static class AssemblyQuestLoader
{
NextQuestId = new QuestId(5445)
};
obj230.Steps = list300;
reference214 = obj230;
obj229.Steps = list300;
reference214 = obj229;
questRoot25.QuestSequence = list287;
AddQuest(questId25, questRoot25);
QuestId questId26 = new QuestId(5445);
@ -478896,7 +478893,7 @@ public static class AssemblyQuestLoader
Span<QuestSequence> span302 = CollectionsMarshal.AsSpan(list302);
num = 0;
ref QuestSequence reference215 = ref span302[num];
QuestSequence obj231 = new QuestSequence
QuestSequence obj230 = new QuestSequence
{
Sequence = 0
};
@ -478916,11 +478913,11 @@ public static class AssemblyQuestLoader
}
}
};
obj231.Steps = list303;
reference215 = obj231;
obj230.Steps = list303;
reference215 = obj230;
num++;
ref QuestSequence reference216 = ref span302[num];
QuestSequence obj232 = new QuestSequence
QuestSequence obj231 = new QuestSequence
{
Sequence = 1
};
@ -478930,11 +478927,11 @@ public static class AssemblyQuestLoader
Span<QuestStep> span304 = CollectionsMarshal.AsSpan(list304);
num2 = 0;
span304[num2] = new QuestStep(EInteractionType.Interact, 1056476u, new Vector3(-35.1416f, 5.000001f, -130.38837f), 130);
obj232.Steps = list304;
reference216 = obj232;
obj231.Steps = list304;
reference216 = obj231;
num++;
ref QuestSequence reference217 = ref span302[num];
QuestSequence obj233 = new QuestSequence
QuestSequence obj232 = new QuestSequence
{
Sequence = byte.MaxValue
};
@ -478944,8 +478941,8 @@ public static class AssemblyQuestLoader
Span<QuestStep> span305 = CollectionsMarshal.AsSpan(list305);
index2 = 0;
span305[index2] = new QuestStep(EInteractionType.CompleteQuest, 1056476u, new Vector3(-35.1416f, 5.000001f, -130.38837f), 130);
obj233.Steps = list305;
reference217 = obj233;
obj232.Steps = list305;
reference217 = obj232;
questRoot26.QuestSequence = list302;
AddQuest(questId26, questRoot26);
}

View file

@ -218,6 +218,10 @@ public sealed class ActionConverter : EnumConverter<EAction>
{
EAction.CheerRhythmYellow,
"Cheer Rhythm: Yellow"
},
{
EAction.CurtainCall,
"Curtain Call"
}
};

View file

@ -66,6 +66,7 @@ public enum EAction
CheerRhythmBlue = 44502,
CheerRhythmGreen = 44503,
CheerRhythmYellow = 44504,
CurtainCall = 11063,
Prospect = 227,
CollectMiner = 240,
LuckOfTheMountaineer = 4081,

View file

@ -31,5 +31,9 @@ public sealed class FateDefinition
public List<DialogueChoice>? TransformDialogueChoices { get; set; }
public ushort? RequiredQuestId { get; set; }
public EAction? StopAction { get; set; }
public DateTime? EventExpiry { get; set; }
}

View file

@ -63,7 +63,7 @@ internal static class FateAction
}
foreach (FateActionTarget target in base.Task.Targets)
{
IGameObject gameObject = gameFunctions.FindObjectByDataId(target.DataId);
IGameObject gameObject = gameFunctions.FindObjectByDataId(target.DataId, null, warnIfMissing: false);
if (gameObject != null && gameObject.IsTargetable)
{
bool flag = gameFunctions.UseAction(gameObject, target.Action);

View file

@ -21,9 +21,12 @@ internal static class FateFarming
{
private DateTime _nextPollAt = DateTime.MinValue;
private bool _loggedWaitingForFate;
protected override bool Start()
{
logger.LogInformation("Waiting for FATE targets to appear ({Count} targets)", base.Task.Targets.Count);
_loggedWaitingForFate = false;
return true;
}
@ -33,12 +36,24 @@ internal static class FateFarming
{
return ETaskResult.StillRunning;
}
ushort currentFateId = gameFunctions.GetCurrentFateId();
if (currentFateId == 0)
{
if (!_loggedWaitingForFate)
{
logger.LogInformation("No active FATE yet, waiting for FATE to start before checking targets");
_loggedWaitingForFate = true;
}
_nextPollAt = DateTime.Now.AddSeconds(1.0);
return ETaskResult.StillRunning;
}
_loggedWaitingForFate = false;
foreach (FateActionTarget target in base.Task.Targets)
{
IGameObject gameObject = gameFunctions.FindObjectByDataId(target.DataId);
IGameObject gameObject = gameFunctions.FindObjectByDataId(target.DataId, null, warnIfMissing: false);
if (gameObject != null && gameObject.IsTargetable)
{
logger.LogInformation("FATE target {DataId} is now targetable", target.DataId);
logger.LogInformation("FATE {FateId} active and target {DataId} is targetable", currentFateId, target.DataId);
return ETaskResult.TaskComplete;
}
}
@ -86,7 +101,7 @@ internal static class FateFarming
}
}
internal sealed record FateActionLoop(IReadOnlyList<FateActionTarget> Targets) : ITask
internal sealed record FateActionLoop(IReadOnlyList<FateActionTarget> Targets, EStatus? RequiredStatusId = null) : ITask
{
public bool ShouldRedoOnInterrupt()
{
@ -103,12 +118,12 @@ internal static class FateFarming
{
private DateTime _nextActionAt = DateTime.MinValue;
private bool _fateWasActive;
private ushort _trackedFateId;
protected override bool Start()
{
logger.LogInformation("Starting FATE action loop with {Count} targets", base.Task.Targets.Count);
_fateWasActive = gameFunctions.GetCurrentFateId() != 0;
_trackedFateId = gameFunctions.GetCurrentFateId();
logger.LogInformation("Starting FATE action loop with {Count} targets, tracking FATE {FateId}", base.Task.Targets.Count, _trackedFateId);
return true;
}
@ -118,33 +133,31 @@ internal static class FateFarming
{
return ETaskResult.StillRunning;
}
bool flag = gameFunctions.GetCurrentFateId() != 0;
if (_fateWasActive && !flag)
if (base.Task.RequiredStatusId.HasValue && !gameFunctions.HasStatus(base.Task.RequiredStatusId.Value))
{
bool flag2 = false;
foreach (FateActionTarget target in base.Task.Targets)
logger.LogInformation("Required status {StatusId} lost during FATE action loop, ending cycle to re-apply", base.Task.RequiredStatusId.Value);
return ETaskResult.TaskComplete;
}
if (_trackedFateId == 0)
{
_trackedFateId = gameFunctions.GetCurrentFateId();
if (_trackedFateId != 0)
{
IGameObject gameObject = gameFunctions.FindObjectByDataId(target.DataId);
if (gameObject != null && gameObject.IsTargetable)
{
flag2 = true;
break;
}
}
if (!flag2)
{
logger.LogInformation("FATE completed (was active, now inactive, no targetable NPCs)");
return ETaskResult.TaskComplete;
logger.LogInformation("Now tracking FATE {FateId}", _trackedFateId);
}
}
_fateWasActive = flag;
foreach (FateActionTarget target2 in base.Task.Targets)
if (_trackedFateId != 0 && !gameFunctions.IsFateStillActive(_trackedFateId))
{
IGameObject gameObject2 = gameFunctions.FindObjectByDataId(target2.DataId);
if (gameObject2 != null && gameObject2.IsTargetable)
logger.LogInformation("FATE {FateId} is no longer running, cycle complete", _trackedFateId);
return ETaskResult.TaskComplete;
}
foreach (FateActionTarget target in base.Task.Targets)
{
IGameObject gameObject = gameFunctions.FindObjectByDataId(target.DataId, null, warnIfMissing: false);
if (gameObject != null && gameObject.IsTargetable)
{
bool flag3 = gameFunctions.UseAction(gameObject2, target2.Action);
_nextActionAt = (flag3 ? DateTime.Now.AddSeconds(2.5) : DateTime.Now.AddSeconds(0.5));
bool flag = gameFunctions.UseAction(gameObject, target.Action);
_nextActionAt = (flag ? DateTime.Now.AddSeconds(2.5) : DateTime.Now.AddSeconds(0.5));
return ETaskResult.StillRunning;
}
}

View file

@ -107,13 +107,13 @@ internal static class Interact
public SkipStepConditions? SkipConditions { get; init; }
public EStatus? RequiredStatusId { get; init; }
public EStatus? CompletionStatusId { get; init; }
public List<QuestWorkValue?> CompletionQuestVariablesFlags { get; }
public bool HasCompletionQuestVariablesFlags { get; }
public Task(uint DataId, Quest? Quest, EInteractionType InteractionType, bool SkipMarkerCheck = false, uint? PickUpItemId = null, byte? TaxiStandId = null, SkipStepConditions? SkipConditions = null, List<QuestWorkValue?>? CompletionQuestVariablesFlags = null, EStatus? RequiredStatusId = null)
public Task(uint DataId, Quest? Quest, EInteractionType InteractionType, bool SkipMarkerCheck = false, uint? PickUpItemId = null, byte? TaxiStandId = null, SkipStepConditions? SkipConditions = null, List<QuestWorkValue?>? CompletionQuestVariablesFlags = null, EStatus? CompletionStatusId = null)
{
this.DataId = DataId;
this.Quest = Quest;
@ -122,7 +122,7 @@ internal static class Interact
this.PickUpItemId = PickUpItemId;
this.TaxiStandId = TaxiStandId;
this.SkipConditions = SkipConditions;
this.RequiredStatusId = RequiredStatusId;
this.CompletionStatusId = CompletionStatusId;
this.CompletionQuestVariablesFlags = CompletionQuestVariablesFlags ?? new List<QuestWorkValue>();
HasCompletionQuestVariablesFlags = Quest != null && CompletionQuestVariablesFlags != null && QuestWorkUtils.HasCompletionFlags(CompletionQuestVariablesFlags);
base._002Ector();
@ -139,7 +139,7 @@ internal static class Interact
}
[CompilerGenerated]
public void Deconstruct(out uint DataId, out Quest? Quest, out EInteractionType InteractionType, out bool SkipMarkerCheck, out uint? PickUpItemId, out byte? TaxiStandId, out SkipStepConditions? SkipConditions, out List<QuestWorkValue?>? CompletionQuestVariablesFlags, out EStatus? RequiredStatusId)
public void Deconstruct(out uint DataId, out Quest? Quest, out EInteractionType InteractionType, out bool SkipMarkerCheck, out uint? PickUpItemId, out byte? TaxiStandId, out SkipStepConditions? SkipConditions, out List<QuestWorkValue?>? CompletionQuestVariablesFlags, out EStatus? CompletionStatusId)
{
DataId = this.DataId;
Quest = this.Quest;
@ -149,7 +149,7 @@ internal static class Interact
TaxiStandId = this.TaxiStandId;
SkipConditions = this.SkipConditions;
CompletionQuestVariablesFlags = this.CompletionQuestVariablesFlags;
RequiredStatusId = this.RequiredStatusId;
CompletionStatusId = this.CompletionStatusId;
}
}
@ -228,10 +228,10 @@ internal static class Interact
}
_needsUnmount = false;
}
EStatus? requiredStatusId = base.Task.RequiredStatusId;
if (requiredStatusId.HasValue)
EStatus? completionStatusId = base.Task.CompletionStatusId;
if (completionStatusId.HasValue)
{
EStatus valueOrDefault = requiredStatusId.GetValueOrDefault();
EStatus valueOrDefault = completionStatusId.GetValueOrDefault();
if (gameFunctions.HasStatus(valueOrDefault))
{
return ETaskResult.TaskComplete;

View file

@ -102,16 +102,12 @@ internal sealed class FateController : MiniTaskController<FateController>
}
if (_currentFate.RequiredStatusId.HasValue && _currentFate.TransformNpcDataId.HasValue && _currentFate.TransformNpcPosition.HasValue && !_gameFunctions.HasStatus(_currentFate.RequiredStatusId.Value))
{
ILogger<FateController> logger = _logger;
object[] array = new object[1];
EStatus? requiredStatusId = _currentFate.RequiredStatusId;
array[0] = requiredStatusId.Value;
logger.LogInformation("Player missing required status {StatusId}, enqueuing transform", array);
_logger.LogInformation("Player missing required status {StatusId}, enqueuing transform", _currentFate.RequiredStatusId.Value);
_taskQueue.Enqueue(new MoveTask(_currentFate.TerritoryId, _currentFate.TransformNpcPosition.Value, null, 3f));
_taskQueue.Enqueue(new Mount.UnmountTask());
TaskQueue taskQueue = _taskQueue;
uint value = _currentFate.TransformNpcDataId.Value;
requiredStatusId = _currentFate.RequiredStatusId.Value;
EStatus? requiredStatusId = _currentFate.RequiredStatusId;
taskQueue.Enqueue(new Interact.Task(value, null, EInteractionType.Interact, SkipMarkerCheck: true, null, null, null, null, requiredStatusId));
_taskQueue.Enqueue(new WaitAtEnd.WaitDelay(TimeSpan.FromSeconds(2L)));
}
@ -119,7 +115,7 @@ internal sealed class FateController : MiniTaskController<FateController>
_taskQueue.Enqueue(new Mount.UnmountTask());
_taskQueue.Enqueue(new FateFarming.WaitForFateTargets(_currentFate.Targets));
_taskQueue.Enqueue(new FateFarming.SyncFateLevel());
_taskQueue.Enqueue(new FateFarming.FateActionLoop(_currentFate.Targets));
_taskQueue.Enqueue(new FateFarming.FateActionLoop(_currentFate.Targets, _currentFate.RequiredStatusId));
_taskQueue.Enqueue(new WaitAtEnd.WaitDelay(TimeSpan.FromSeconds(3L)));
}
}
@ -129,6 +125,11 @@ internal sealed class FateController : MiniTaskController<FateController>
if (_currentFate != null)
{
_logger.LogInformation("Stopping FATE farming: {Label} (completed {Cycles} cycles)", label, _completedCycles);
if (_currentFate.StopAction.HasValue && _currentFate.RequiredStatusId.HasValue && _gameFunctions.HasStatus(_currentFate.RequiredStatusId.Value))
{
_logger.LogInformation("Using stop action {Action} to remove transformation", _currentFate.StopAction.Value);
_gameFunctions.UseAction(_currentFate.StopAction.Value);
}
_currentFate = null;
_completedCycles = 0;
_cycleLimit = null;

File diff suppressed because it is too large Load diff

View file

@ -121,7 +121,7 @@ internal sealed class GameFunctions
return false;
}
public IGameObject? FindObjectByDataId(uint dataId, Dalamud.Game.ClientState.Objects.Enums.ObjectKind? kind = null)
public IGameObject? FindObjectByDataId(uint dataId, Dalamud.Game.ClientState.Objects.Enums.ObjectKind? kind = null, bool warnIfMissing = true)
{
foreach (IGameObject item in _objectTable)
{
@ -132,7 +132,10 @@ internal sealed class GameFunctions
return item;
}
}
_logger.LogWarning("Could not find GameObject with dataId {DataId}", dataId);
if (warnIfMissing)
{
_logger.LogWarning("Could not find GameObject with dataId {DataId}", dataId);
}
return null;
}
@ -581,6 +584,25 @@ internal sealed class GameFunctions
return ptr->CurrentFate->FateId;
}
public unsafe bool IsFateStillActive(ushort fateId)
{
if (fateId == 0)
{
return false;
}
FateManager* ptr = FateManager.Instance();
if (ptr == null)
{
return false;
}
FateContext* fateById = ptr->GetFateById(fateId);
if (fateById == null)
{
return false;
}
return fateById->State == FateState.Running;
}
public uint GetItemLevel(uint itemId)
{
return (_dataManager.GetExcelSheet<Item>()?.GetRowOrDefault(itemId))?.LevelItem.RowId ?? 0;

View file

@ -87,6 +87,11 @@ internal sealed class ActiveQuestComponent
public void Draw(bool isMinimized)
{
if (_fateController.IsRunning)
{
DrawFateActive(isMinimized);
return;
}
(QuestController.QuestProgress, QuestController.ECurrentQuestType)? currentQuestDetails = _questController.CurrentQuestDetails;
QuestController.QuestProgress questProgress = currentQuestDetails?.Item1;
QuestController.ECurrentQuestType? currentQuestType = currentQuestDetails?.Item2;
@ -131,12 +136,12 @@ internal sealed class ActiveQuestComponent
if (interactionType == EInteractionType.WaitForManualProgress || interactionType == EInteractionType.Snipe || interactionType == EInteractionType.Instruction)
{
flag = true;
goto IL_0154;
goto IL_0169;
}
}
flag = false;
goto IL_0154;
IL_0154:
goto IL_0169;
IL_0169:
if (flag)
{
color.Push(ImGuiCol.Text, ImGuiColors.DalamudOrange);
@ -178,7 +183,7 @@ internal sealed class ActiveQuestComponent
text2.AppendFormatted((item2 == 1) ? string.Empty : "s");
text2.AppendLiteral(" - Leveling mode will start automatically");
ImGui.TextColored(in col, text2);
using (ImRaii.Disabled(_questController.IsRunning || !_autoDutyIpc.IsStopped()))
using (ImRaii.Disabled(_questController.IsRunning || _fateController.IsRunning || !_autoDutyIpc.IsStopped()))
{
if (ImGuiComponents.IconButton(FontAwesomeIcon.Play))
{
@ -247,6 +252,32 @@ internal sealed class ActiveQuestComponent
}
}
private void DrawFateActive(bool isMinimized)
{
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.ParsedGold))
{
ImU8String text = new ImU8String(6, 1);
text.AppendLiteral("FATE: ");
text.AppendFormatted(Shorten(_fateController.CurrentFate.Name));
ImGui.TextUnformatted(text);
}
IList<string> remainingTaskNames = _fateController.GetRemainingTaskNames();
if (remainingTaskNames.Count > 0)
{
ImGui.TextColored(ImGuiColors.DalamudGrey, remainingTaskNames[0]);
}
if (!isMinimized)
{
string text2 = (_fateController.CycleLimit.HasValue ? $"Cycle {_fateController.CompletedCycles + 1} / {_fateController.CycleLimit}" : $"Cycle {_fateController.CompletedCycles + 1}");
ImGui.TextColored(ImGuiColors.DalamudGrey3, text2);
}
if (ImGuiComponents.IconButton(FontAwesomeIcon.Stop))
{
_fateController.Stop("UI stop");
_movementController.Stop();
}
}
private void DrawQuestNames(QuestController.QuestProgress currentQuest, QuestController.ECurrentQuestType? currentQuestType)
{
if (currentQuestType == QuestController.ECurrentQuestType.Simulated)
@ -563,7 +594,7 @@ internal sealed class ActiveQuestComponent
private void DrawQuestButtons(QuestController.QuestProgress currentQuest, QuestStep? currentStep, QuestProgressInfo? questProgressInfo, bool isMinimized)
{
using (ImRaii.Disabled(_questController.IsRunning))
using (ImRaii.Disabled(_questController.IsRunning || _fateController.IsRunning))
{
if (ImGuiComponents.IconButton(FontAwesomeIcon.Play))
{

View file

@ -13,6 +13,8 @@ using Dalamud.Interface.Windowing;
using LLib.ImGui;
using Questionable.Controller;
using Questionable.Data;
using Questionable.Functions;
using Questionable.Model;
using Questionable.Model.Questing;
using Questionable.Windows.QuestComponents;
@ -28,17 +30,23 @@ internal sealed class FateSelectionWindow : LWindow
private readonly MovementController _movementController;
private readonly QuestFunctions _questFunctions;
private readonly QuestData _questData;
private readonly TerritoryData _territoryData;
private int _cycleLimit;
public FateSelectionWindow(FateController fateController, FateDefinitionRegistry fateDefinitionRegistry, QuestController questController, MovementController movementController, TerritoryData territoryData)
public FateSelectionWindow(FateController fateController, FateDefinitionRegistry fateDefinitionRegistry, QuestController questController, MovementController movementController, QuestFunctions questFunctions, QuestData questData, TerritoryData territoryData)
: base("FATE Farming###QuestionableFateFarming")
{
_fateController = fateController;
_fateDefinitionRegistry = fateDefinitionRegistry;
_questController = questController;
_movementController = movementController;
_questFunctions = questFunctions;
_questData = questData;
_territoryData = territoryData;
base.Size = new Vector2(600f, 400f);
base.SizeCondition = ImGuiCond.FirstUseEver;
@ -335,12 +343,31 @@ internal sealed class FateSelectionWindow : LWindow
private void DrawFateRowActions(FateDefinition fate, bool disabled)
{
using (ImRaii.Disabled(disabled))
bool flag = fate.RequiredQuestId.HasValue && !_questFunctions.IsQuestComplete(new QuestId(fate.RequiredQuestId.Value));
ImU8String id = new ImU8String(5, 1);
id.AppendLiteral("fate_");
id.AppendFormatted(fate.Name);
using (ImRaii.PushId(id))
{
ImU8String id = new ImU8String(5, 1);
id.AppendLiteral("fate_");
id.AppendFormatted(fate.Name);
using (ImRaii.PushId(id))
if (flag)
{
using (ImRaii.PushFont(UiBuilder.IconFont))
{
ImGui.TextColored(ImGuiColors.DalamudRed, FontAwesomeIcon.Times.ToIconString());
}
if (ImGui.IsItemHovered())
{
IQuestInfo questInfo;
string value = (_questData.TryGetQuestInfo(new QuestId(fate.RequiredQuestId.Value), out questInfo) ? questInfo.Name : fate.RequiredQuestId.Value.ToString(CultureInfo.InvariantCulture));
ImU8String tooltip = new ImU8String(33, 1);
tooltip.AppendLiteral("Requires \"");
tooltip.AppendFormatted(value);
tooltip.AppendLiteral("\" to be completed first");
ImGui.SetTooltip(tooltip);
}
return;
}
using (ImRaii.Disabled(disabled))
{
if (ImGuiComponents.IconButton(FontAwesomeIcon.Play))
{
@ -350,16 +377,16 @@ internal sealed class FateSelectionWindow : LWindow
_fateController.Start(fate, cycleLimit);
}
}
}
if (disabled && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
{
if (_fateController.IsRunning)
if (disabled && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
{
ImGui.SetTooltip("Already farming a FATE");
}
else
{
ImGui.SetTooltip("Stop quest automation first");
if (_fateController.IsRunning)
{
ImGui.SetTooltip("Already farming a FATE");
}
else
{
ImGui.SetTooltip("Stop quest automation first");
}
}
}
}

View file

@ -18,6 +18,8 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
{
private static readonly Version PluginVersion = typeof(QuestionablePlugin).Assembly.GetName().Version;
private const string TestingSuffix = "";
private readonly IDalamudPluginInterface _pluginInterface;
private readonly QuestController _questController;