forked from liza/Questionable
Handle 'Action canceled, you are under attack' while e.g. talking to an NPC
This commit is contained in:
parent
21fde119ba
commit
5288cc6e31
@ -1,5 +1,5 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.3</Version>
|
||||
<Version>3.4</Version>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
@ -13,4 +13,5 @@ public enum EEnemySpawnType
|
||||
AutoOnEnterArea,
|
||||
OverworldEnemies,
|
||||
FateEnemies,
|
||||
QuestInterruption,
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ internal sealed class CombatController : IDisposable
|
||||
Module = combatModule,
|
||||
Data = combatData,
|
||||
};
|
||||
_wasInCombat = combatData.SpawnType == EEnemySpawnType.QuestInterruption;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -86,7 +87,9 @@ internal sealed class CombatController : IDisposable
|
||||
if (_currentFight == null)
|
||||
return EStatus.Complete;
|
||||
|
||||
if (_movementController.IsPathfinding || _movementController.IsPathRunning || _movementController.MovementStartedAt > DateTime.Now.AddSeconds(-1))
|
||||
if (_movementController.IsPathfinding ||
|
||||
_movementController.IsPathRunning ||
|
||||
_movementController.MovementStartedAt > DateTime.Now.AddSeconds(-1))
|
||||
return EStatus.Moving;
|
||||
|
||||
var target = _targetManager.Target;
|
||||
@ -111,6 +114,8 @@ internal sealed class CombatController : IDisposable
|
||||
else
|
||||
{
|
||||
var nextTarget = FindNextTarget();
|
||||
_logger.LogInformation("NT → {NT}", nextTarget);
|
||||
|
||||
if (nextTarget is { IsDead: false })
|
||||
SetTarget(nextTarget);
|
||||
}
|
||||
@ -335,7 +340,7 @@ internal sealed class CombatController : IDisposable
|
||||
|
||||
public sealed class CombatData
|
||||
{
|
||||
public required ElementId ElementId { get; init; }
|
||||
public required ElementId? ElementId { get; init; }
|
||||
public required EEnemySpawnType SpawnType { get; init; }
|
||||
public required List<uint> KillEnemyDataIds { get; init; }
|
||||
public required List<ComplexCombatData> ComplexCombatDatas { get; init; }
|
||||
@ -345,6 +350,7 @@ internal sealed class CombatController : IDisposable
|
||||
|
||||
public enum EStatus
|
||||
{
|
||||
NotStarted,
|
||||
InCombat,
|
||||
Moving,
|
||||
Complete,
|
||||
|
@ -122,6 +122,10 @@ internal sealed class CommandHandler : IDisposable
|
||||
PrintMountId();
|
||||
break;
|
||||
|
||||
case "handle-interrupt":
|
||||
_questController.InterruptQueueWithCombat();
|
||||
break;
|
||||
|
||||
case "":
|
||||
_questWindow.Toggle();
|
||||
break;
|
||||
|
@ -129,7 +129,7 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
|
||||
return EStatus.Complete;
|
||||
}
|
||||
|
||||
if (_currentTask == null && _taskQueue.Count == 0)
|
||||
if (_taskQueue.AllTasksComplete)
|
||||
GoToNextNode();
|
||||
|
||||
UpdateCurrentTask();
|
||||
@ -141,8 +141,7 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
|
||||
public override void Stop(string label)
|
||||
{
|
||||
_currentRequest = null;
|
||||
_currentTask = null;
|
||||
_taskQueue.Clear();
|
||||
_taskQueue.Reset();
|
||||
}
|
||||
|
||||
private void GoToNextNode()
|
||||
@ -150,7 +149,7 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
|
||||
if (_currentRequest == null)
|
||||
return;
|
||||
|
||||
if (_taskQueue.Count > 0)
|
||||
if (!_taskQueue.AllTasksComplete)
|
||||
return;
|
||||
|
||||
var director = UIState.Instance()->DirectorTodo.Director;
|
||||
@ -267,8 +266,8 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
|
||||
|
||||
public override IList<string> GetRemainingTaskNames()
|
||||
{
|
||||
if (_currentTask != null)
|
||||
return [_currentTask.ToString() ?? "?", .. base.GetRemainingTaskNames()];
|
||||
if (_taskQueue.CurrentTask is {} currentTask)
|
||||
return [currentTask.ToString() ?? "?", .. base.GetRemainingTaskNames()];
|
||||
else
|
||||
return base.GetRemainingTaskNames();
|
||||
}
|
||||
@ -277,10 +276,10 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
|
||||
{
|
||||
if (_revisitRegex.IsMatch(message.TextValue))
|
||||
{
|
||||
if (_currentTask is IRevisitAware currentTaskRevisitAware)
|
||||
if (_taskQueue.CurrentTask is IRevisitAware currentTaskRevisitAware)
|
||||
currentTaskRevisitAware.OnRevisit();
|
||||
|
||||
foreach (ITask task in _taskQueue)
|
||||
foreach (ITask task in _taskQueue.RemainingTasks)
|
||||
{
|
||||
if (task is IRevisitAware taskRevisitAware)
|
||||
taskRevisitAware.OnRevisit();
|
||||
|
@ -12,11 +12,9 @@ internal abstract class MiniTaskController<T>
|
||||
{
|
||||
protected readonly IChatGui _chatGui;
|
||||
protected readonly ILogger<T> _logger;
|
||||
protected readonly TaskQueue _taskQueue = new();
|
||||
|
||||
protected readonly Queue<ITask> _taskQueue = new();
|
||||
protected ITask? _currentTask;
|
||||
|
||||
public MiniTaskController(IChatGui chatGui, ILogger<T> logger)
|
||||
protected MiniTaskController(IChatGui chatGui, ILogger<T> logger)
|
||||
{
|
||||
_chatGui = chatGui;
|
||||
_logger = logger;
|
||||
@ -24,7 +22,7 @@ internal abstract class MiniTaskController<T>
|
||||
|
||||
protected virtual void UpdateCurrentTask()
|
||||
{
|
||||
if (_currentTask == null)
|
||||
if (_taskQueue.CurrentTask == null)
|
||||
{
|
||||
if (_taskQueue.TryDequeue(out ITask? upcomingTask))
|
||||
{
|
||||
@ -33,7 +31,7 @@ internal abstract class MiniTaskController<T>
|
||||
_logger.LogInformation("Starting task {TaskName}", upcomingTask.ToString());
|
||||
if (upcomingTask.Start())
|
||||
{
|
||||
_currentTask = upcomingTask;
|
||||
_taskQueue.CurrentTask = upcomingTask;
|
||||
return;
|
||||
}
|
||||
else
|
||||
@ -58,13 +56,13 @@ internal abstract class MiniTaskController<T>
|
||||
ETaskResult result;
|
||||
try
|
||||
{
|
||||
result = _currentTask.Update();
|
||||
result = _taskQueue.CurrentTask.Update();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Failed to update task {TaskName}", _currentTask.ToString());
|
||||
_logger.LogError(e, "Failed to update task {TaskName}", _taskQueue.CurrentTask.ToString());
|
||||
_chatGui.PrintError(
|
||||
$"[Questionable] Failed to update task '{_currentTask}', please check /xllog for details.");
|
||||
$"[Questionable] Failed to update task '{_taskQueue.CurrentTask}', please check /xllog for details.");
|
||||
Stop("Task failed to update");
|
||||
return;
|
||||
}
|
||||
@ -76,14 +74,14 @@ internal abstract class MiniTaskController<T>
|
||||
|
||||
case ETaskResult.SkipRemainingTasksForStep:
|
||||
_logger.LogInformation("{Task} → {Result}, skipping remaining tasks for step",
|
||||
_currentTask, result);
|
||||
_currentTask = null;
|
||||
_taskQueue.CurrentTask, result);
|
||||
_taskQueue.CurrentTask = null;
|
||||
|
||||
while (_taskQueue.TryDequeue(out ITask? nextTask))
|
||||
{
|
||||
if (nextTask is ILastTask or Gather.SkipMarker)
|
||||
{
|
||||
_currentTask = nextTask;
|
||||
_taskQueue.CurrentTask = nextTask;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -92,27 +90,27 @@ internal abstract class MiniTaskController<T>
|
||||
|
||||
case ETaskResult.TaskComplete:
|
||||
_logger.LogInformation("{Task} → {Result}, remaining tasks: {RemainingTaskCount}",
|
||||
_currentTask, result, _taskQueue.Count);
|
||||
_taskQueue.CurrentTask, result, _taskQueue.RemainingTasks.Count());
|
||||
|
||||
OnTaskComplete(_currentTask);
|
||||
OnTaskComplete(_taskQueue.CurrentTask);
|
||||
|
||||
_currentTask = null;
|
||||
_taskQueue.CurrentTask = null;
|
||||
|
||||
// handled in next update
|
||||
return;
|
||||
|
||||
case ETaskResult.NextStep:
|
||||
_logger.LogInformation("{Task} → {Result}", _currentTask, result);
|
||||
_logger.LogInformation("{Task} → {Result}", _taskQueue.CurrentTask, result);
|
||||
|
||||
var lastTask = (ILastTask)_currentTask;
|
||||
_currentTask = null;
|
||||
var lastTask = (ILastTask)_taskQueue.CurrentTask;
|
||||
_taskQueue.CurrentTask = null;
|
||||
|
||||
OnNextStep(lastTask);
|
||||
return;
|
||||
|
||||
case ETaskResult.End:
|
||||
_logger.LogInformation("{Task} → {Result}", _currentTask, result);
|
||||
_currentTask = null;
|
||||
_logger.LogInformation("{Task} → {Result}", _taskQueue.CurrentTask, result);
|
||||
_taskQueue.CurrentTask = null;
|
||||
Stop("Task end");
|
||||
return;
|
||||
}
|
||||
@ -130,5 +128,5 @@ internal abstract class MiniTaskController<T>
|
||||
public abstract void Stop(string label);
|
||||
|
||||
public virtual IList<string> GetRemainingTaskNames() =>
|
||||
_taskQueue.Select(x => x.ToString() ?? "?").ToList();
|
||||
_taskQueue.RemainingTasks.Select(x => x.ToString() ?? "?").ToList();
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ internal sealed class MovementController : IDisposable
|
||||
|
||||
public bool IsPathfinding => _pathfindTask is { IsCompleted: false };
|
||||
public DestinationData? Destination { get; set; }
|
||||
public DateTime MovementStartedAt { get; private set; } = DateTime.MaxValue;
|
||||
public DateTime MovementStartedAt { get; private set; } = DateTime.Now;
|
||||
|
||||
public void Update()
|
||||
{
|
||||
|
@ -8,7 +8,9 @@ using Dalamud.Game.Gui.Toast;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using LLib;
|
||||
using LLib.GameData;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller.Steps;
|
||||
using Questionable.Controller.Steps.Interactions;
|
||||
@ -18,6 +20,8 @@ using Questionable.External;
|
||||
using Questionable.Functions;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Questing;
|
||||
using Quest = Questionable.Model.Quest;
|
||||
using Mount = Questionable.Controller.Steps.Common.Mount;
|
||||
|
||||
namespace Questionable.Controller;
|
||||
|
||||
@ -36,6 +40,10 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
private readonly Configuration _configuration;
|
||||
private readonly YesAlreadyIpc _yesAlreadyIpc;
|
||||
private readonly TaskCreator _taskCreator;
|
||||
private readonly Mount.Factory _mountFactory;
|
||||
private readonly Combat.Factory _combatFactory;
|
||||
|
||||
private readonly string _actionCanceledText;
|
||||
|
||||
private readonly object _progressLock = new();
|
||||
|
||||
@ -73,7 +81,10 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
IToastGui toastGui,
|
||||
Configuration configuration,
|
||||
YesAlreadyIpc yesAlreadyIpc,
|
||||
TaskCreator taskCreator)
|
||||
TaskCreator taskCreator,
|
||||
Mount.Factory mountFactory,
|
||||
Combat.Factory combatFactory,
|
||||
IDataManager dataManager)
|
||||
: base(chatGui, logger)
|
||||
{
|
||||
_clientState = clientState;
|
||||
@ -89,10 +100,14 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
_configuration = configuration;
|
||||
_yesAlreadyIpc = yesAlreadyIpc;
|
||||
_taskCreator = taskCreator;
|
||||
_mountFactory = mountFactory;
|
||||
_combatFactory = combatFactory;
|
||||
|
||||
_condition.ConditionChange += OnConditionChange;
|
||||
_toastGui.Toast += OnNormalToast;
|
||||
_toastGui.ErrorToast += OnErrorToast;
|
||||
|
||||
_actionCanceledText = dataManager.GetString<LogMessage>(1314, x => x.Text)!;
|
||||
}
|
||||
|
||||
public EAutomationType AutomationType
|
||||
@ -181,7 +196,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
|
||||
if (!_clientState.IsLoggedIn || _condition[ConditionFlag.Unconscious])
|
||||
{
|
||||
if (_currentTask != null || _taskQueue.Count > 0)
|
||||
if (!_taskQueue.AllTasksComplete)
|
||||
{
|
||||
Stop("HP = 0");
|
||||
_movementController.Stop();
|
||||
@ -191,7 +206,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
}
|
||||
else if (_configuration.General.UseEscToCancelQuesting && _keyState[VirtualKey.ESCAPE])
|
||||
{
|
||||
if (_currentTask != null || _taskQueue.Count > 0)
|
||||
if (!_taskQueue.AllTasksComplete)
|
||||
{
|
||||
Stop("ESC pressed");
|
||||
_movementController.Stop();
|
||||
@ -204,8 +219,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
return;
|
||||
|
||||
if (AutomationType == EAutomationType.Automatic &&
|
||||
((_currentTask == null && _taskQueue.Count == 0) ||
|
||||
_currentTask is WaitAtEnd.WaitQuestAccepted)
|
||||
(_taskQueue.AllTasksComplete || _taskQueue.CurrentTask is WaitAtEnd.WaitQuestAccepted)
|
||||
&& CurrentQuest is { Sequence: 0, Step: 0 } or { Sequence: 0, Step: 255 }
|
||||
&& DateTime.Now >= CurrentQuest.StepProgress.StartedAt.AddSeconds(15))
|
||||
{
|
||||
@ -276,8 +290,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
questToRun = _nextQuest;
|
||||
currentSequence = _nextQuest.Sequence; // by definition, this should always be 0
|
||||
if (_nextQuest.Step == 0 &&
|
||||
_currentTask == null &&
|
||||
_taskQueue.Count == 0 &&
|
||||
_taskQueue.AllTasksComplete &&
|
||||
AutomationType == EAutomationType.Automatic)
|
||||
ExecuteNextStep();
|
||||
}
|
||||
@ -286,8 +299,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
questToRun = _gatheringQuest;
|
||||
currentSequence = _gatheringQuest.Sequence;
|
||||
if (_gatheringQuest.Step == 0 &&
|
||||
_currentTask == null &&
|
||||
_taskQueue.Count == 0 &&
|
||||
_taskQueue.AllTasksComplete &&
|
||||
AutomationType == EAutomationType.Automatic)
|
||||
ExecuteNextStep();
|
||||
}
|
||||
@ -392,7 +404,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
if (questToRun.Step == 255)
|
||||
{
|
||||
DebugState = "Step completed";
|
||||
if (_currentTask != null || _taskQueue.Count > 0)
|
||||
if (!_taskQueue.AllTasksComplete)
|
||||
CheckNextTasks("Step complete");
|
||||
return;
|
||||
}
|
||||
@ -465,10 +477,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
private void ClearTasksInternal()
|
||||
{
|
||||
//_logger.LogDebug("Clearing task (internally)");
|
||||
_currentTask = null;
|
||||
|
||||
if (_taskQueue.Count > 0)
|
||||
_taskQueue.Clear();
|
||||
_taskQueue.Reset();
|
||||
|
||||
_yesAlreadyIpc.RestoreYesAlready();
|
||||
_combatController.Stop("ClearTasksInternal");
|
||||
@ -629,13 +638,15 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
|
||||
public string ToStatString()
|
||||
{
|
||||
return _currentTask == null ? $"- (+{_taskQueue.Count})" : $"{_currentTask} (+{_taskQueue.Count})";
|
||||
return _taskQueue.CurrentTask is { } currentTask
|
||||
? $"{currentTask} (+{_taskQueue.RemainingTasks.Count()})"
|
||||
: $"- (+{_taskQueue.RemainingTasks.Count()})";
|
||||
}
|
||||
|
||||
public bool HasCurrentTaskMatching<T>([NotNullWhen(true)] out T? task)
|
||||
where T : class, ITask
|
||||
{
|
||||
if (_currentTask is T t)
|
||||
if (_taskQueue.CurrentTask is T t)
|
||||
{
|
||||
task = t;
|
||||
return true;
|
||||
@ -647,7 +658,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRunning => _currentTask != null || _taskQueue.Count > 0;
|
||||
public bool IsRunning => !_taskQueue.AllTasksComplete;
|
||||
|
||||
public sealed class QuestProgress
|
||||
{
|
||||
@ -687,19 +698,19 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
{
|
||||
lock (_progressLock)
|
||||
{
|
||||
if (_currentTask is ISkippableTask)
|
||||
_currentTask = null;
|
||||
else if (_currentTask != null)
|
||||
if (_taskQueue.CurrentTask is ISkippableTask)
|
||||
_taskQueue.CurrentTask = null;
|
||||
else if (_taskQueue.CurrentTask != null)
|
||||
{
|
||||
_currentTask = null;
|
||||
while (_taskQueue.Count > 0)
|
||||
_taskQueue.CurrentTask = null;
|
||||
while (_taskQueue.TryPeek(out ITask? task))
|
||||
{
|
||||
var task = _taskQueue.Dequeue();
|
||||
_taskQueue.TryDequeue(out _);
|
||||
if (task is ISkippableTask)
|
||||
return;
|
||||
}
|
||||
|
||||
if (_taskQueue.Count == 0)
|
||||
if (_taskQueue.AllTasksComplete)
|
||||
{
|
||||
Stop("Skip");
|
||||
IncreaseStepCount(elementId, currentQuestSequence);
|
||||
@ -715,7 +726,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
|
||||
public void SkipSimulatedTask()
|
||||
{
|
||||
_currentTask = null;
|
||||
_taskQueue.CurrentTask = null;
|
||||
}
|
||||
|
||||
public bool IsInterruptible()
|
||||
@ -774,7 +785,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
|
||||
private void OnConditionChange(ConditionFlag flag, bool value)
|
||||
{
|
||||
if (_currentTask is IConditionChangeAware conditionChangeAware)
|
||||
if (_taskQueue.CurrentTask is IConditionChangeAware conditionChangeAware)
|
||||
conditionChangeAware.OnConditionChange(flag, value);
|
||||
}
|
||||
|
||||
@ -785,13 +796,33 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
|
||||
|
||||
private void OnErrorToast(ref SeString message, ref bool isHandled)
|
||||
{
|
||||
if (_currentTask is IToastAware toastAware)
|
||||
_logger.LogWarning("XXX {A} → {B} XXX", _actionCanceledText, message.TextValue);
|
||||
if (_taskQueue.CurrentTask is IToastAware toastAware)
|
||||
{
|
||||
if (toastAware.OnErrorToast(message))
|
||||
{
|
||||
isHandled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isHandled)
|
||||
{
|
||||
if (GameFunctions.GameStringEquals(_actionCanceledText, message.TextValue) &&
|
||||
!_condition[ConditionFlag.InFlight])
|
||||
InterruptQueueWithCombat();
|
||||
}
|
||||
}
|
||||
|
||||
public void InterruptQueueWithCombat()
|
||||
{
|
||||
_logger.LogWarning("Interrupted with action canceled message, attempting to resolve");
|
||||
List<ITask> tasks = [];
|
||||
if (_condition[ConditionFlag.Mounted])
|
||||
tasks.Add(_mountFactory.Unmount());
|
||||
|
||||
tasks.Add(_combatFactory.CreateTask(null, false, EEnemySpawnType.QuestInterruption, [], [], []));
|
||||
tasks.Add(new WaitAtEnd.WaitDelay());
|
||||
_taskQueue.InterruptWith(tasks);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -46,6 +46,8 @@ internal static class Mount
|
||||
private bool _mountTriggered;
|
||||
private DateTime _retryAt = DateTime.MinValue;
|
||||
|
||||
public bool ShouldRedoOnInterrupt() => true;
|
||||
|
||||
public bool Start()
|
||||
{
|
||||
if (condition[ConditionFlag.Mounted])
|
||||
@ -129,6 +131,8 @@ internal static class Mount
|
||||
private bool _unmountTriggered;
|
||||
private DateTime _continueAt = DateTime.MinValue;
|
||||
|
||||
public bool ShouldRedoOnInterrupt() => true;
|
||||
|
||||
public bool Start()
|
||||
{
|
||||
if (!condition[ConditionFlag.Mounted])
|
||||
|
@ -5,6 +5,8 @@ namespace Questionable.Controller.Steps;
|
||||
|
||||
internal interface ITask
|
||||
{
|
||||
bool ShouldRedoOnInterrupt() => false;
|
||||
|
||||
bool Start();
|
||||
|
||||
ETaskResult Update();
|
||||
|
@ -101,7 +101,7 @@ internal static class Combat
|
||||
step.CompletionQuestVariablesFlags, step.ComplexCombatData);
|
||||
}
|
||||
|
||||
private HandleCombat CreateTask(ElementId elementId, bool isLastStep, EEnemySpawnType enemySpawnType,
|
||||
internal HandleCombat CreateTask(ElementId? elementId, bool isLastStep, EEnemySpawnType enemySpawnType,
|
||||
IList<uint> killEnemyDataIds, IList<QuestWorkValue?> completionQuestVariablesFlags,
|
||||
IList<ComplexCombatData> complexCombatData)
|
||||
{
|
||||
@ -115,18 +115,21 @@ internal static class Combat
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class HandleCombat(
|
||||
internal sealed class HandleCombat(
|
||||
bool isLastStep,
|
||||
CombatController.CombatData combatData,
|
||||
IList<QuestWorkValue?> completionQuestVariableFlags,
|
||||
CombatController combatController,
|
||||
QuestFunctions questFunctions) : ITask
|
||||
{
|
||||
private CombatController.EStatus _status = CombatController.EStatus.NotStarted;
|
||||
|
||||
public bool Start() => combatController.Start(combatData);
|
||||
|
||||
public ETaskResult Update()
|
||||
{
|
||||
if (combatController.Update() != CombatController.EStatus.Complete)
|
||||
_status = combatController.Update();
|
||||
if (_status != CombatController.EStatus.Complete)
|
||||
return ETaskResult.StillRunning;
|
||||
|
||||
// if our quest step has any completion flags, we need to check if they are set
|
||||
@ -157,11 +160,11 @@ internal static class Combat
|
||||
public override string ToString()
|
||||
{
|
||||
if (QuestWorkUtils.HasCompletionFlags(completionQuestVariableFlags))
|
||||
return "HandleCombat(wait: QW flags)";
|
||||
return $"HandleCombat(wait: QW flags, s: {_status})";
|
||||
else if (isLastStep)
|
||||
return "HandleCombat(wait: next sequence)";
|
||||
return $"HandleCombat(wait: next sequence, s: {_status})";
|
||||
else
|
||||
return "HandleCombat(wait: not in combat)";
|
||||
return $"HandleCombat(wait: not in combat, s: {_status})";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -173,6 +173,8 @@ internal static class MoveTo
|
||||
_canRestart = moveParams.RestartNavigation;
|
||||
}
|
||||
|
||||
public bool ShouldRedoOnInterrupt() => true;
|
||||
|
||||
public bool Start()
|
||||
{
|
||||
float stopDistance = _moveParams.StopDistance ?? QuestStep.DefaultStopDistance;
|
||||
@ -313,6 +315,8 @@ internal static class MoveTo
|
||||
GameFunctions gameFunctions,
|
||||
IClientState clientState) : ITask
|
||||
{
|
||||
public bool ShouldRedoOnInterrupt() => true;
|
||||
|
||||
public bool Start() => true;
|
||||
|
||||
public ETaskResult Update()
|
||||
@ -333,6 +337,8 @@ internal static class MoveTo
|
||||
private bool _landing;
|
||||
private DateTime _continueAt;
|
||||
|
||||
public bool ShouldRedoOnInterrupt() => true;
|
||||
|
||||
public bool Start()
|
||||
{
|
||||
if (!condition[ConditionFlag.InFlight])
|
||||
|
67
Questionable/Controller/Steps/TaskQueue.cs
Normal file
67
Questionable/Controller/Steps/TaskQueue.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
namespace Questionable.Controller.Steps;
|
||||
|
||||
internal sealed class TaskQueue
|
||||
{
|
||||
private readonly List<ITask> _tasks = [];
|
||||
private int _currentTaskIndex;
|
||||
public ITask? CurrentTask { get; set; }
|
||||
|
||||
public IEnumerable<ITask> RemainingTasks => _tasks.Skip(_currentTaskIndex);
|
||||
public bool AllTasksComplete => CurrentTask == null && _currentTaskIndex >= _tasks.Count;
|
||||
|
||||
public void Enqueue(ITask task)
|
||||
{
|
||||
_tasks.Add(task);
|
||||
}
|
||||
|
||||
public bool TryDequeue([NotNullWhen(true)] out ITask? task)
|
||||
{
|
||||
if (_currentTaskIndex >= _tasks.Count)
|
||||
{
|
||||
task = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
task = _tasks[_currentTaskIndex];
|
||||
if (task.ShouldRedoOnInterrupt())
|
||||
_currentTaskIndex++;
|
||||
else
|
||||
_tasks.RemoveAt(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryPeek([NotNullWhen(true)] out ITask? task)
|
||||
{
|
||||
if (_currentTaskIndex >= _tasks.Count)
|
||||
{
|
||||
task = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
task = _tasks[_currentTaskIndex];
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_tasks.Clear();
|
||||
_currentTaskIndex = 0;
|
||||
CurrentTask = null;
|
||||
}
|
||||
|
||||
public void InterruptWith(List<ITask> interruptionTasks)
|
||||
{
|
||||
if (CurrentTask != null)
|
||||
{
|
||||
_tasks.Insert(0, CurrentTask);
|
||||
CurrentTask = null;
|
||||
_currentTaskIndex = 0;
|
||||
}
|
||||
|
||||
_tasks.InsertRange(0, interruptionTasks);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user