Make it possible to redo explicit actions when taking damage
authorLiza Carvelli <liza@carvel.li>
Wed, 20 Aug 2025 19:07:52 +0000 (21:07 +0200)
committerLiza Carvelli <liza@carvel.li>
Wed, 20 Aug 2025 19:07:52 +0000 (21:07 +0200)
Questionable/Controller/Steps/Interactions/Action.cs
Questionable/Controller/Steps/Interactions/Combat.cs

index cf82942e9c14db4efe4964c24392aae2991fcd62..57adc80d940405e0f636502de43426ced4997612 100644 (file)
@@ -5,6 +5,7 @@ using Dalamud.Game.ClientState.Objects.Types;
 using FFXIVClientStructs.FFXIV.Client.Game;
 using Microsoft.Extensions.Logging;
 using Questionable.Controller.Steps.Common;
+using Questionable.Controller.Utils;
 using Questionable.Functions;
 using Questionable.Model;
 using Questionable.Model.Questing;
@@ -22,14 +23,14 @@ internal static class Action
 
             ArgumentNullException.ThrowIfNull(step.Action);
 
-            var task = OnObject(step.DataId, step.Action.Value);
+            var task = OnObject(step.DataId, quest, step.Action.Value, step.CompletionQuestVariablesFlags);
             if (step.Action.Value.RequiresMount())
                 return [task];
             else
                 return [new Mount.UnmountTask(), task];
         }
 
-        public static ITask OnObject(uint? dataId, EAction action)
+        public static ITask OnObject(uint? dataId, Quest quest, EAction action, List<QuestWorkValue?>? completionQuestVariablesFlags)
         {
             if (action is EAction.FumaShuriken or EAction.Katon or EAction.Raiton)
             {
@@ -37,13 +38,15 @@ internal static class Action
                 return new UseMudraOnObject(dataId.Value, action);
             }
             else
-                return new UseOnObject(dataId, action);
+                return new UseOnObject(dataId, quest, action, completionQuestVariablesFlags);
         }
     }
 
     internal sealed record UseOnObject(
         uint? DataId,
-        EAction Action) : ITask
+        Quest? Quest,
+        EAction Action,
+        List<QuestWorkValue?>? CompletionQuestVariablesFlags) : ITask
     {
         public bool ShouldRedoOnInterrupt() => true;
         public override string ToString() => $"Action({Action})";
@@ -51,6 +54,7 @@ internal static class Action
 
     internal sealed class UseOnObjectExecutor(
         GameFunctions gameFunctions,
+        QuestFunctions questFunctions,
         ILogger<UseOnObject> logger) : TaskExecutor<UseOnObject>
     {
         private bool _usedAction;
@@ -123,13 +127,27 @@ internal static class Action
                 return ETaskResult.StillRunning;
             }
 
+            if (Task.Quest != null &&
+                Task.CompletionQuestVariablesFlags != null &&
+                QuestWorkUtils.HasCompletionFlags(Task.CompletionQuestVariablesFlags))
+            {
+                var questWork = questFunctions.GetQuestProgressInfo(Task.Quest.Id);
+                return questWork != null &&
+                       QuestWorkUtils.MatchesQuestWork(Task.CompletionQuestVariablesFlags, questWork)
+                    ? ETaskResult.TaskComplete
+                    : ETaskResult.StillRunning;
+            }
+
             return ETaskResult.TaskComplete;
         }
 
         public override bool ShouldInterruptOnDamage() => true;
     }
 
-    internal sealed record UseMudraOnObject(uint DataId, EAction Action) : ITask
+    internal sealed record UseMudraOnObject(
+        uint DataId,
+        EAction Action)
+        : ITask
     {
         public override string ToString() => $"Mudra({Action})";
     }
index bb700f62f3a88f666a83c553107a17c72fcb4fa5..d6db7d488d21e951bd5487b5c578298e39490d39 100644 (file)
@@ -77,7 +77,7 @@ internal static class Combat
 
                     if (!step.Action.Value.RequiresMount())
                         yield return new Mount.UnmountTask();
-                    yield return new Action.UseOnObject(step.DataId.Value, step.Action.Value);
+                    yield return new Action.UseOnObject(step.DataId.Value, null, step.Action.Value, null);
                     yield return new WaitAtEnd.WaitDelay(TimeSpan.FromSeconds(1));
                     yield return CreateTask(quest, sequence, step);
                     break;