forked from liza/Questionable
Various fixes
This commit is contained in:
parent
73fef2677e
commit
564f1adc01
@ -77,7 +77,7 @@
|
||||
"Z": 365.7129
|
||||
},
|
||||
"TerritoryId": 958,
|
||||
"InteractionType": "WaitForManualProgress",
|
||||
"InteractionType": "SinglePlayerDuty",
|
||||
"Comment": "Follow Alphinaud and Alisaie",
|
||||
"DialogueChoices": [
|
||||
{
|
||||
|
@ -76,7 +76,7 @@
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
128
|
||||
-128
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -52,7 +52,15 @@
|
||||
"Z": -503.2578
|
||||
},
|
||||
"TerritoryId": 958,
|
||||
"InteractionType": "Interact"
|
||||
"InteractionType": "Interact",
|
||||
"CompletionQuestVariablesFlags": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
128
|
||||
]
|
||||
},
|
||||
{
|
||||
"DataId": 2012094,
|
||||
@ -64,7 +72,15 @@
|
||||
"TerritoryId": 958,
|
||||
"InteractionType": "Interact",
|
||||
"Comment": "Map",
|
||||
"Mount": true
|
||||
"Mount": true,
|
||||
"CompletionQuestVariablesFlags": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
64
|
||||
]
|
||||
},
|
||||
{
|
||||
"DataId": 2012005,
|
||||
@ -86,7 +102,15 @@
|
||||
},
|
||||
"TerritoryId": 958,
|
||||
"InteractionType": "Interact",
|
||||
"Comment": "Warmachine Wreckage"
|
||||
"Comment": "Warmachine Wreckage",
|
||||
"CompletionQuestVariablesFlags": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
32
|
||||
]
|
||||
},
|
||||
{
|
||||
"DataId": 2012096,
|
||||
@ -97,7 +121,15 @@
|
||||
},
|
||||
"TerritoryId": 958,
|
||||
"InteractionType": "Interact",
|
||||
"Comment": "Children's Slide"
|
||||
"Comment": "Children's Slide",
|
||||
"CompletionQuestVariablesFlags": [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
16
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -21,6 +21,16 @@
|
||||
{
|
||||
"Sequence": 1,
|
||||
"Steps": [
|
||||
{
|
||||
"Position": {
|
||||
"X": -148.48793,
|
||||
"Y": -10.30035,
|
||||
"Z": -247.25652
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "WalkTo",
|
||||
"Comment": "Avoids Combat"
|
||||
},
|
||||
{
|
||||
"DataId": 2011987,
|
||||
"Position": {
|
||||
@ -43,6 +53,16 @@
|
||||
"Mount": true,
|
||||
"DisableNavmesh": true
|
||||
},
|
||||
{
|
||||
"Position": {
|
||||
"X": -480.30975,
|
||||
"Y": -22.946651,
|
||||
"Z": -145.08534
|
||||
},
|
||||
"TerritoryId": 956,
|
||||
"InteractionType": "WalkTo",
|
||||
"Comment": "Avoids Combat (typically)"
|
||||
},
|
||||
{
|
||||
"DataId": 2011988,
|
||||
"Position": {
|
||||
|
@ -71,7 +71,8 @@ internal sealed class QuestController
|
||||
|
||||
if (_keyState[VirtualKey.ESCAPE])
|
||||
{
|
||||
Stop();
|
||||
if (_currentTask != null || _taskQueue.Count > 0)
|
||||
Stop("ESC pressed");
|
||||
_movementController.Stop();
|
||||
}
|
||||
|
||||
@ -92,7 +93,7 @@ internal sealed class QuestController
|
||||
{
|
||||
_logger.LogInformation("No current quest, resetting data");
|
||||
CurrentQuest = null;
|
||||
Stop();
|
||||
Stop("Resetting current quest");
|
||||
}
|
||||
}
|
||||
else if (CurrentQuest == null || CurrentQuest.Quest.QuestId != currentQuestId)
|
||||
@ -101,14 +102,15 @@ internal sealed class QuestController
|
||||
{
|
||||
_logger.LogInformation("New quest: {QuestName}", quest.Name);
|
||||
CurrentQuest = new QuestProgress(quest, currentSequence, 0);
|
||||
Stop("Different Quest");
|
||||
}
|
||||
else if (CurrentQuest != null)
|
||||
{
|
||||
_logger.LogInformation("No active quest anymore? Not sure what happened...");
|
||||
CurrentQuest = null;
|
||||
Stop("No active Quest");
|
||||
}
|
||||
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -116,7 +118,7 @@ internal sealed class QuestController
|
||||
{
|
||||
DebugState = "No quest active";
|
||||
Comment = null;
|
||||
Stop();
|
||||
Stop("No quest active");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -140,11 +142,7 @@ internal sealed class QuestController
|
||||
if (CurrentQuest.Sequence != currentSequence)
|
||||
{
|
||||
CurrentQuest = CurrentQuest with { Sequence = currentSequence, Step = 0 };
|
||||
|
||||
bool automatic = _automatic;
|
||||
Stop();
|
||||
if (automatic)
|
||||
ExecuteNextStep(true);
|
||||
Stop("New sequence", continueIfAutomatic: true);
|
||||
}
|
||||
|
||||
var q = CurrentQuest.Quest;
|
||||
@ -153,7 +151,7 @@ internal sealed class QuestController
|
||||
{
|
||||
DebugState = "Sequence not found";
|
||||
Comment = null;
|
||||
Stop();
|
||||
Stop("Unknown sequence");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -161,7 +159,8 @@ internal sealed class QuestController
|
||||
{
|
||||
DebugState = "Step completed";
|
||||
Comment = null;
|
||||
Stop();
|
||||
if (_currentTask != null || _taskQueue.Count > 0)
|
||||
Stop("Step complete", continueIfAutomatic: true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -169,7 +168,7 @@ internal sealed class QuestController
|
||||
{
|
||||
DebugState = "Step not found";
|
||||
Comment = null;
|
||||
Stop();
|
||||
Stop("Unknown step");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -249,15 +248,31 @@ internal sealed class QuestController
|
||||
*/
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
private void ClearTasksInternal()
|
||||
{
|
||||
_currentTask = null;
|
||||
|
||||
if (_taskQueue.Count > 0)
|
||||
_taskQueue.Clear();
|
||||
}
|
||||
|
||||
public void Stop(string label, bool continueIfAutomatic = false)
|
||||
{
|
||||
using var scope = _logger.BeginScope(label);
|
||||
|
||||
ClearTasksInternal();
|
||||
|
||||
// reset task queue
|
||||
_automatic = false;
|
||||
if (continueIfAutomatic && _automatic)
|
||||
{
|
||||
if (CurrentQuest?.Step is >= 0 and < 255)
|
||||
ExecuteNextStep(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("Stopping automatic questing");
|
||||
_automatic = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCurrentTask()
|
||||
@ -286,7 +301,7 @@ internal sealed class QuestController
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Failed to start task {TaskName}", upcomingTask.ToString());
|
||||
Stop();
|
||||
Stop("Task failed to start");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -302,7 +317,7 @@ internal sealed class QuestController
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Failed to update task {TaskName}", _currentTask.ToString());
|
||||
Stop();
|
||||
Stop("Task failed to update");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -312,7 +327,8 @@ internal sealed class QuestController
|
||||
return;
|
||||
|
||||
case ETaskResult.SkipRemainingTasksForStep:
|
||||
_logger.LogInformation("Result: {Result}, skipping remaining tasks for step", result);
|
||||
_logger.LogInformation("{Task} → {Result}, skipping remaining tasks for step",
|
||||
_currentTask, result);
|
||||
_currentTask = null;
|
||||
|
||||
while (_taskQueue.TryDequeue(out ITask? nextTask))
|
||||
@ -327,28 +343,28 @@ internal sealed class QuestController
|
||||
return;
|
||||
|
||||
case ETaskResult.TaskComplete:
|
||||
_logger.LogInformation("Result: {Result}, remaining tasks: {RemainingTaskCount}", result,
|
||||
_taskQueue.Count);
|
||||
_logger.LogInformation("{Task} → {Result}, remaining tasks: {RemainingTaskCount}",
|
||||
_currentTask, result, _taskQueue.Count);
|
||||
_currentTask = null;
|
||||
|
||||
// handled in next update
|
||||
return;
|
||||
|
||||
case ETaskResult.NextStep:
|
||||
_logger.LogInformation("Result: {Result}", result);
|
||||
_logger.LogInformation("{Task} → {Result}", _currentTask, result);
|
||||
IncreaseStepCount(true);
|
||||
return;
|
||||
|
||||
case ETaskResult.End:
|
||||
_logger.LogInformation("Result: {Result}", result);
|
||||
Stop();
|
||||
_logger.LogInformation("{Task} → {Result}", _currentTask, result);
|
||||
Stop("Task end");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteNextStep(bool automatic)
|
||||
{
|
||||
Stop();
|
||||
ClearTasksInternal();
|
||||
_automatic = automatic;
|
||||
|
||||
(QuestSequence? seq, QuestStep? step) = GetNextStep();
|
||||
@ -382,6 +398,9 @@ internal sealed class QuestController
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Tasks for {QuestId}, {Sequence}, {Step}: {Tasks}",
|
||||
CurrentQuest.Quest.QuestId, seq.Sequence, seq.Steps.IndexOf(step),
|
||||
string.Join(", ", newTasks.Select(x => x.ToString())));
|
||||
foreach (var task in newTasks)
|
||||
_taskQueue.Enqueue(task);
|
||||
}
|
||||
@ -394,6 +413,9 @@ internal sealed class QuestController
|
||||
return _currentTask == null ? $"- (+{_taskQueue.Count})" : $"{_currentTask} (+{_taskQueue.Count})";
|
||||
}
|
||||
|
||||
public bool HasCurrentTaskMatching<T>() =>
|
||||
_currentTask is T;
|
||||
|
||||
public sealed record QuestProgress(
|
||||
Quest Quest,
|
||||
byte Sequence,
|
||||
|
@ -14,10 +14,10 @@ internal static class SkipCondition
|
||||
{
|
||||
public ITask? CreateTask(Quest quest, QuestSequence sequence, QuestStep step)
|
||||
{
|
||||
if (step.SkipIf.Count == 0)
|
||||
if (step.SkipIf.Contains(ESkipCondition.Never))
|
||||
return null;
|
||||
|
||||
if (step.SkipIf.Contains(ESkipCondition.Never))
|
||||
if (step.SkipIf.Count == 0 && step.CompletionQuestVariablesFlags.Count == 0)
|
||||
return null;
|
||||
|
||||
return serviceProvider.GetRequiredService<CheckTask>()
|
||||
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Questionable.Controller.Steps.BaseTasks;
|
||||
@ -13,7 +14,7 @@ namespace Questionable.Controller.Steps.BaseFactory;
|
||||
|
||||
internal static class WaitAtEnd
|
||||
{
|
||||
internal sealed class Factory(IServiceProvider serviceProvider) : ITaskFactory
|
||||
internal sealed class Factory(IServiceProvider serviceProvider, IClientState clientState) : ITaskFactory
|
||||
{
|
||||
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
|
||||
{
|
||||
@ -54,6 +55,36 @@ internal static class WaitAtEnd
|
||||
new NextStep()
|
||||
];
|
||||
|
||||
case EInteractionType.Interact when step.TargetTerritoryId != null:
|
||||
ITask waitInteraction;
|
||||
if (step.TerritoryId != step.TargetTerritoryId)
|
||||
{
|
||||
// interaction moves to a different territory
|
||||
waitInteraction = new WaitConditionTask(() => clientState.TerritoryType == step.TerritoryId,
|
||||
$"Wait(tp to territory: {step.TerritoryId})");
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 lastPosition = step.Position ?? clientState.LocalPlayer?.Position ?? Vector3.Zero;
|
||||
waitInteraction = new WaitConditionTask(() =>
|
||||
{
|
||||
Vector3? currentPosition = clientState.LocalPlayer?.Position;
|
||||
if (currentPosition == null)
|
||||
return false;
|
||||
|
||||
// interaction moved to elsewhere in the zone
|
||||
return (lastPosition - currentPosition.Value).Length() > 20;
|
||||
}, $"Wait(tp away from {lastPosition.ToString("G", CultureInfo.InvariantCulture)})");
|
||||
}
|
||||
|
||||
return
|
||||
[
|
||||
waitInteraction,
|
||||
serviceProvider.GetRequiredService<WaitDelay>(),
|
||||
new NextStep()
|
||||
];
|
||||
|
||||
case EInteractionType.Interact:
|
||||
default:
|
||||
return [serviceProvider.GetRequiredService<WaitDelay>(), new NextStep()];
|
||||
}
|
||||
@ -136,7 +167,7 @@ internal static class WaitAtEnd
|
||||
|
||||
public ETaskResult Update() => ETaskResult.NextStep;
|
||||
|
||||
public override string ToString() => "Next Step";
|
||||
public override string ToString() => "NextStep";
|
||||
}
|
||||
|
||||
internal sealed class EndAutomation : ILastTask
|
||||
@ -145,6 +176,6 @@ internal static class WaitAtEnd
|
||||
|
||||
public ETaskResult Update() => ETaskResult.End;
|
||||
|
||||
public override string ToString() => "End automation";
|
||||
public override string ToString() => "EndAutomation";
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,10 @@ internal sealed class MountTask(
|
||||
}
|
||||
|
||||
if (gameFunctions.HasStatusPreventingSprintOrMount())
|
||||
{
|
||||
logger.LogInformation("Can't mount due to status preventing sprint or mount");
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.LogInformation("Step wants a mount, trying to mount in territory {Id}...", _territoryId);
|
||||
if (!condition[ConditionFlag.InCombat])
|
||||
@ -48,6 +51,12 @@ internal sealed class MountTask(
|
||||
{
|
||||
if (!_mountTriggered)
|
||||
{
|
||||
if (gameFunctions.HasStatusPreventingSprintOrMount())
|
||||
{
|
||||
logger.LogInformation("Can't mount due to status preventing sprint or mount");
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
|
||||
_mountTriggered = gameFunctions.Mount();
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ internal static class Combat
|
||||
ArgumentNullException.ThrowIfNull(step.DataId);
|
||||
|
||||
var task = serviceProvider.GetRequiredService<Interact.DoInteract>()
|
||||
.With(step.DataId.Value);
|
||||
.With(step.DataId.Value, true);
|
||||
return [unmount, task];
|
||||
}
|
||||
else if (step.EnemySpawnType == EEnemySpawnType.AfterItemUse)
|
||||
|
@ -21,21 +21,25 @@ internal static class Interact
|
||||
|
||||
ArgumentNullException.ThrowIfNull(step.DataId);
|
||||
|
||||
return serviceProvider.GetRequiredService<DoInteract>().With(step.DataId.Value);
|
||||
return serviceProvider.GetRequiredService<DoInteract>()
|
||||
.With(step.DataId.Value, step.TargetTerritoryId != null);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DoInteract(GameFunctions gameFunctions, ICondition condition, ILogger<DoInteract> logger)
|
||||
: ITask
|
||||
{
|
||||
private bool _needsUnmount;
|
||||
private bool _interacted;
|
||||
private DateTime _continueAt = DateTime.MinValue;
|
||||
|
||||
private uint DataId { get; set; }
|
||||
private bool SkipMarkerCheck { get; set; }
|
||||
|
||||
public ITask With(uint dataId)
|
||||
public ITask With(uint dataId, bool skipMarkerCheck)
|
||||
{
|
||||
DataId = dataId;
|
||||
SkipMarkerCheck = skipMarkerCheck;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -51,6 +55,7 @@ internal static class Interact
|
||||
// this is only relevant for followers on quests
|
||||
if (!gameObject.IsTargetable && condition[ConditionFlag.Mounted])
|
||||
{
|
||||
_needsUnmount = true;
|
||||
gameFunctions.Unmount();
|
||||
_continueAt = DateTime.Now.AddSeconds(0.5);
|
||||
return true;
|
||||
@ -71,6 +76,18 @@ internal static class Interact
|
||||
if (DateTime.Now <= _continueAt)
|
||||
return ETaskResult.StillRunning;
|
||||
|
||||
if (_needsUnmount)
|
||||
{
|
||||
if (condition[ConditionFlag.Mounted])
|
||||
{
|
||||
gameFunctions.Unmount();
|
||||
_continueAt = DateTime.Now.AddSeconds(0.5);
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
else
|
||||
_needsUnmount = false;
|
||||
}
|
||||
|
||||
if (!_interacted)
|
||||
{
|
||||
GameObject? gameObject = gameFunctions.FindObjectByDataId(DataId);
|
||||
@ -87,7 +104,7 @@ internal static class Interact
|
||||
|
||||
private unsafe bool HasAnyMarker(GameObject gameObject)
|
||||
{
|
||||
if (gameObject.ObjectKind != ObjectKind.EventNpc)
|
||||
if (SkipMarkerCheck || gameObject.ObjectKind != ObjectKind.EventNpc)
|
||||
return true;
|
||||
|
||||
var gameObjectStruct = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)gameObject.Address;
|
||||
|
@ -54,7 +54,7 @@ internal sealed class DalamudInitializer : IDisposable
|
||||
}
|
||||
catch (MovementController.PathfindingFailedException)
|
||||
{
|
||||
_questController.Stop();
|
||||
_questController.Stop("Pathfinding failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -470,17 +470,18 @@ internal sealed unsafe class GameFunctions
|
||||
public bool Unmount()
|
||||
{
|
||||
if (!_condition[ConditionFlag.Mounted])
|
||||
return false;
|
||||
return true;
|
||||
|
||||
if (ActionManager.Instance()->GetActionStatus(ActionType.GeneralAction, 23) == 0)
|
||||
{
|
||||
_logger.LogInformation("Unmounting...");
|
||||
ActionManager.Instance()->UseAction(ActionType.GeneralAction, 23);
|
||||
return ActionManager.Instance()->UseAction(ActionType.GeneralAction, 23);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Can't unmount right now?");
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenDutyFinder(uint contentFinderConditionId)
|
||||
|
@ -4,6 +4,7 @@ using System.Globalization;
|
||||
using System.Numerics;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Components;
|
||||
using Dalamud.Interface.Windowing;
|
||||
using Dalamud.Plugin;
|
||||
@ -16,6 +17,7 @@ using ImGuiNET;
|
||||
using LLib.ImGui;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller;
|
||||
using Questionable.Controller.Steps.BaseFactory;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.V1;
|
||||
|
||||
@ -85,6 +87,7 @@ internal sealed class DebugWindow : LWindow, IPersistableWindowConfig, IDisposab
|
||||
ImGui.Separator();
|
||||
|
||||
DrawQuickAccessButtons();
|
||||
DrawRemainingTasks();
|
||||
}
|
||||
|
||||
private unsafe void DrawQuest()
|
||||
@ -141,14 +144,25 @@ internal sealed class DebugWindow : LWindow, IPersistableWindowConfig, IDisposab
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Stop))
|
||||
{
|
||||
_movementController.Stop();
|
||||
_questController.Stop();
|
||||
_questController.Stop("Manual");
|
||||
}
|
||||
|
||||
QuestStep? currentStep = currentQuest.Quest
|
||||
.FindSequence(currentQuest.Sequence)
|
||||
?.FindStep(currentQuest.Step);
|
||||
bool colored = currentStep != null && currentStep.InteractionType == EInteractionType.Instruction
|
||||
&& _questController.HasCurrentTaskMatching<WaitAtEnd.WaitNextStepOrSequence>();
|
||||
|
||||
if (colored)
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen);
|
||||
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.ArrowCircleRight, "Skip"))
|
||||
{
|
||||
_questController.Stop();
|
||||
_movementController.Stop();
|
||||
_questController.Stop("Manual");
|
||||
_questController.IncreaseStepCount();
|
||||
}
|
||||
if (colored)
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
else
|
||||
ImGui.Text("No active quest");
|
||||
@ -278,7 +292,7 @@ internal sealed class DebugWindow : LWindow, IPersistableWindowConfig, IDisposab
|
||||
if (ImGui.Button("Stop Nav"))
|
||||
{
|
||||
_movementController.Stop();
|
||||
_questController.Stop();
|
||||
_questController.Stop("Manual");
|
||||
}
|
||||
|
||||
ImGui.EndDisabled();
|
||||
@ -289,7 +303,10 @@ internal sealed class DebugWindow : LWindow, IPersistableWindowConfig, IDisposab
|
||||
_framework.RunOnTick(() => _gameUiController.HandleCurrentDialogueChoices(),
|
||||
TimeSpan.FromMilliseconds(200));
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawRemainingTasks()
|
||||
{
|
||||
var remainingTasks = _questController.GetRemainingTaskNames();
|
||||
if (remainingTasks.Count > 0)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user