If you start moving while in combat (because mounting isn't possible), use mount...
authorLiza Carvelli <liza@carvel.li>
Mon, 4 Nov 2024 16:20:42 +0000 (17:20 +0100)
committerLiza Carvelli <liza@carvel.li>
Mon, 4 Nov 2024 16:20:42 +0000 (17:20 +0100)
Questionable/Controller/Steps/Common/Mount.cs
Questionable/Controller/Steps/Shared/MoveTo.cs
Questionable/Controller/Steps/TaskExecutor.cs

index d9d38ae266ce685d5716882eea6f9645d44300d9..2fb0d2d701190a6e2b9f73c40140468bf51d893b 100644 (file)
@@ -35,21 +35,21 @@ internal static class Mount
         private bool _mountTriggered;
         private DateTime _retryAt = DateTime.MinValue;
 
-        protected override bool Start()
+        public MountResult EvaluateMountState()
         {
             if (condition[ConditionFlag.Mounted])
-                return false;
+                return MountResult.DontMount;
 
             if (!territoryData.CanUseMount(Task.TerritoryId))
             {
                 logger.LogInformation("Can't use mount in current territory {Id}", Task.TerritoryId);
-                return false;
+                return MountResult.DontMount;
             }
 
             if (gameFunctions.HasStatusPreventingMount())
             {
                 logger.LogInformation("Can't mount due to status preventing sprint or mount");
-                return false;
+                return MountResult.DontMount;
             }
 
             if (Task.MountIf == EMountIf.AwayFromPosition)
@@ -59,7 +59,7 @@ internal static class Mount
                 if (Task.TerritoryId == clientState.TerritoryType && distance < 30f && !Conditions.IsDiving)
                 {
                     logger.LogInformation("Not using mount, as we're close to the target");
-                    return false;
+                    return MountResult.DontMount;
                 }
 
                 logger.LogInformation(
@@ -72,12 +72,14 @@ internal static class Mount
             if (!condition[ConditionFlag.InCombat])
             {
                 _retryAt = DateTime.Now.AddSeconds(0.5);
-                return true;
+                return MountResult.Mount;
             }
-
-            return false;
+            else
+                return MountResult.WhenOutOfCombat;
         }
 
+        protected override bool Start() => EvaluateMountState() == MountResult.Mount;
+
         public override ETaskResult Update()
         {
             if (_mountTriggered && !condition[ConditionFlag.Mounted] && DateTime.Now > _retryAt)
@@ -108,6 +110,13 @@ internal static class Mount
         }
     }
 
+    internal enum MountResult
+    {
+        DontMount,
+        Mount,
+        WhenOutOfCombat,
+    }
+
     internal sealed record UnmountTask : ITask
     {
         public bool ShouldRedoOnInterrupt() => true;
index 89b7170a0ad9ac593de185f3a7f380cf1fb67048..eaead8ef311ab8d735049ca265acc5f64be0a05f 100644 (file)
@@ -87,19 +87,23 @@ internal static class MoveTo
         private readonly GameFunctions _gameFunctions;
         private readonly ILogger<MoveExecutor> _logger;
         private readonly IClientState _clientState;
+        private readonly ICondition _condition;
         private readonly Mount.MountExecutor _mountExecutor;
         private readonly Mount.UnmountExecutor _unmountExecutor;
 
         private Action? _startAction;
         private Vector3 _destination;
         private bool _canRestart;
-        private ITaskExecutor? _nestedExecutor;
+
+        private (ITaskExecutor Executor, ITask Task, bool Triggered)? _nestedExecutor =
+            (new NoOpTaskExecutor(), new NoOpTask(), true);
 
         public MoveExecutor(
             MovementController movementController,
             GameFunctions gameFunctions,
             ILogger<MoveExecutor> logger,
             IClientState clientState,
+            ICondition condition,
             IDataManager dataManager,
             Mount.MountExecutor mountExecutor,
             Mount.UnmountExecutor unmountExecutor)
@@ -108,6 +112,7 @@ internal static class MoveTo
             _gameFunctions = gameFunctions;
             _logger = logger;
             _clientState = clientState;
+            _condition = condition;
             _mountExecutor = mountExecutor;
             _unmountExecutor = unmountExecutor;
             _cannotExecuteAtThisTime = dataManager.GetString<LogMessage>(579, x => x.Text)!;
@@ -161,16 +166,18 @@ internal static class MoveTo
                 var mountTask = new Mount.MountTask(Task.TerritoryId, Mount.EMountIf.Always);
                 if (_mountExecutor.Start(mountTask))
                 {
-                    _nestedExecutor = _mountExecutor;
+                    _nestedExecutor = (_mountExecutor, mountTask, true);
                     return true;
                 }
+                else if (_mountExecutor.EvaluateMountState() == Mount.MountResult.WhenOutOfCombat)
+                    _nestedExecutor = (_mountExecutor, mountTask, false);
             }
             else if (Task.Mount == false)
             {
                 var mountTask = new Mount.UnmountTask();
                 if (_unmountExecutor.Start(mountTask))
                 {
-                    _nestedExecutor = _unmountExecutor;
+                    _nestedExecutor = (_unmountExecutor, mountTask, true);
                     return true;
                 }
             }
@@ -187,21 +194,43 @@ internal static class MoveTo
                     var mountTask = new Mount.MountTask(Task.TerritoryId, mountIf, _destination);
                     if (_mountExecutor.Start(mountTask))
                     {
-                        _nestedExecutor = _mountExecutor;
+                        _nestedExecutor = (_mountExecutor, mountTask, true);
                         return true;
                     }
+                    else if (_mountExecutor.EvaluateMountState() == Mount.MountResult.WhenOutOfCombat)
+                        _nestedExecutor = (_mountExecutor, mountTask, false);
                 }
             }
 
-            _nestedExecutor = new NoOpTaskExecutor();
+            if (_startAction != null && (_nestedExecutor == null || _nestedExecutor.Value.Triggered == false))
+                _startAction();
             return true;
         }
 
         public override ETaskResult Update()
         {
-            if (_nestedExecutor != null)
+            if (_nestedExecutor is { } nestedExecutor)
             {
-                if (_nestedExecutor.Update() == ETaskResult.TaskComplete)
+                if (nestedExecutor is { Triggered: false, Executor: Mount.MountExecutor mountExecutor })
+                {
+                    if (!_condition[ConditionFlag.InCombat])
+                    {
+                        if (mountExecutor.EvaluateMountState() == Mount.MountResult.DontMount)
+                            _nestedExecutor = (new NoOpTaskExecutor(), new NoOpTask(), true);
+                        else
+                        {
+                            if (_movementController.IsPathfinding || _movementController.IsPathRunning)
+                                _movementController.Stop();
+
+                            if (nestedExecutor.Executor.Start(nestedExecutor.Task))
+                            {
+                                _nestedExecutor = nestedExecutor with { Triggered = true };
+                                return ETaskResult.StillRunning;
+                            }
+                        }
+                    }
+                }
+                else if (nestedExecutor.Executor.Update() == ETaskResult.TaskComplete)
                 {
                     _nestedExecutor = null;
                     if (_startAction != null)
@@ -213,6 +242,7 @@ internal static class MoveTo
                     else
                         return ETaskResult.TaskComplete;
                 }
+
                 return ETaskResult.StillRunning;
             }
 
@@ -245,6 +275,17 @@ internal static class MoveTo
             return ETaskResult.TaskComplete;
         }
 
+        public override bool WasInterrupted()
+        {
+            if (Task.Fly && _condition[ConditionFlag.InCombat] && !_condition[ConditionFlag.Mounted] &&
+                _nestedExecutor is { Triggered: false, Executor: Mount.MountExecutor mountExecutor } &&
+                mountExecutor.EvaluateMountState() == Mount.MountResult.WhenOutOfCombat)
+            {
+                return true;
+            }
+
+            return base.WasInterrupted();
+        }
 
         public bool OnErrorToast(SeString message)
         {
@@ -255,7 +296,9 @@ internal static class MoveTo
         }
     }
 
-    private sealed class NoOpTaskExecutor : TaskExecutor<ITask>
+    private sealed record NoOpTask : ITask;
+
+    private sealed class NoOpTaskExecutor : TaskExecutor<NoOpTask>
     {
         protected override bool Start() => true;
 
@@ -306,7 +349,6 @@ internal static class MoveTo
         GameFunctions gameFunctions,
         IClientState clientState) : TaskExecutor<WaitForNearDataId>
     {
-
         protected override bool Start() => true;
 
         public override ETaskResult Update()
@@ -328,7 +370,8 @@ internal static class MoveTo
         public override string ToString() => "Land";
     }
 
-    internal sealed class LandExecutor(IClientState clientState, ICondition condition, ILogger<LandExecutor> logger) : TaskExecutor<LandTask>
+    internal sealed class LandExecutor(IClientState clientState, ICondition condition, ILogger<LandExecutor> logger)
+        : TaskExecutor<LandTask>
     {
         private bool _landing;
         private DateTime _continueAt;
index e5b2c2e95c85a195848d77e19f582198fa9b2fd6..9f1873f60d592158aea7531dd4b8ab8a313fa4fa 100644 (file)
@@ -23,7 +23,7 @@ internal abstract class TaskExecutor<T> : ITaskExecutor
     public InteractionProgressContext? ProgressContext { get; set; }
     ITask ITaskExecutor.CurrentTask => Task;
 
-    public bool WasInterrupted()
+    public virtual bool WasInterrupted()
     {
         if (ProgressContext is {} progressContext)
         {