Skipping quest steps based on CompletionFlags now works v0.9
authorLiza Carvelli <liza@carvel.li>
Mon, 10 Jun 2024 22:06:35 +0000 (00:06 +0200)
committerLiza Carvelli <liza@carvel.li>
Mon, 10 Jun 2024 22:07:01 +0000 (00:07 +0200)
QuestPaths/Endwalker/MSQ/B-Garlemald/4397_Sea of Sorrow.json
QuestPaths/Endwalker/MSQ/C-MareLamentorum/4402_A Taste of the Moon.json
QuestPaths/Endwalker/MSQ/F-Labyrinthos2/4448_Bonds of Adamantite.json
QuestPaths/Endwalker/MSQ/G-UltimaThule/4456_Roads Paved of Sacrifice.json
QuestPaths/Endwalker/MSQ/G-UltimaThule/4461_Hello World.json
Questionable/Controller/MovementController.cs
Questionable/Controller/Steps/BaseFactory/SkipCondition.cs
Questionable/Controller/Steps/BaseFactory/WaitAtEnd.cs
Questionable/GameFunctions.cs
Questionable/Model/V1/QuestStep.cs
Questionable/Questionable.csproj

index a5c0d5edc4b8ba81504749513b3049796fd164d5..f6f1d860ffcc94700c606f3356f85f323381ef29 100644 (file)
@@ -89,7 +89,7 @@
             "Z": 419.7605
           },
           "TerritoryId": 959,
-          "InteractionType": "Instruction",
+          "InteractionType": "WaitForManualProgress",
           "Comment": "Follow Argos"
         },
         {
             "Z": 523.5217
           },
           "TerritoryId": 959,
-          "InteractionType": "Instruction",
+          "InteractionType": "WaitForManualProgress",
           "Comment": "Follow Argos"
         },
         {
index 9a6ffa06a45d27cf42f6c33c9a6ee772805325ae..cf4874dbf4c98cd4bfc2ed03133e9b874d141888 100644 (file)
           "InteractionType": "Jump",
           "JumpDestination": {
             "Position": {
-              "X": -444.84818,
-              "Y": -160.76439,
-              "Z": -645.7075
+              "X": -443.62042,
+              "Y": -160.7644,
+              "Z": -644.7719
             }
           },
           "Comment": "Platform 4"
         },
         {
           "Position": {
-            "X": -444.84818,
-            "Y": -160.76439,
-            "Z": -645.7075
+            "X": -443.62042,
+            "Y": -160.7644,
+            "Z": -644.7719
           },
           "TerritoryId": 959,
           "InteractionType": "Jump",
             "Z": -620.05035
           },
           "TerritoryId": 959,
-          "InteractionType": "Interact"
+          "InteractionType": "Interact",
+          "Comment": "FIXME Auto-playing quests seems to get stuck here/do nothing"
         }
       ]
     }
index d0dae4ea3a4d5b5ee27067dc6b0cc265ed6cebd4..32147f0169812b769527ffa2b962254a09df9c14 100644 (file)
             "Z": 301.63266
           },
           "TerritoryId": 956,
-          "InteractionType": "Interact",
-          "Comment": "TODO Should cancel navmesh if condition is [OccupiedInCutsceneEvent OR BetweenAreas]; then verify next marker distance"
+          "InteractionType": "WalkTo"
         }
       ]
     },
index 9752d9eda64b9c3cfb1c8945deeff6f957a26ddc..8b00f3f79b02e9b17db22fc471928c6217c30484 100644 (file)
     {
       "Sequence": 5,
       "Steps": [
+        {
+          "Position": {
+            "X": 26.119669,
+            "Y": 269.043,
+            "Z": -587.29144
+          },
+          "TerritoryId": 960,
+          "InteractionType": "WalkTo",
+          "CompletionQuestVariablesFlags": [
+            null,
+            null,
+            null,
+            null,
+            null,
+            -128
+          ]
+        },
         {
           "DataId": 2012354,
           "Position": {
index 62bce9feebac4f418ad1ce3a4e97ebccbe3bed6a..6f125f2eb0c0c9bf70edef86912dd6929ff4f5ea 100644 (file)
@@ -45,7 +45,7 @@
           },
           "TerritoryId": 960,
           "InteractionType": "WaitForManualProgress",
-          "Comment": "Identify Anomaly (Elbow/Knee)"
+          "Comment": "Identify Anomaly (Head, Elbow or Knee)"
         }
       ]
     },
index 999ecc9ade8fc9a1bd861e31a88829bff42b33b9..a802434f7a787d4b981291cb55b52753733106d5 100644 (file)
@@ -112,6 +112,12 @@ internal sealed class MovementController : IDisposable
 
         if (IsPathRunning && Destination != null)
         {
+            if (_gameFunctions.IsLoadingScreenVisible())
+            {
+                Stop();
+                return;
+            }
+
             Vector3 localPlayerPosition = _clientState.LocalPlayer?.Position ?? Vector3.Zero;
             if ((localPlayerPosition - Destination.Position).Length() < Destination.StopDistance)
             {
index f025a622ca5ba8019a08a9b81700dd7c7395f4df..b7fa8e40dd783c6f1d8b521bc43267453a2e2b60 100644 (file)
@@ -76,7 +76,7 @@ internal static class SkipCondition
             }
 
             QuestWork? questWork = gameFunctions.GetQuestEx(QuestId);
-            if (questWork != null && Step.MatchesQuestVariables(questWork.Value))
+            if (questWork != null && Step.MatchesQuestVariables(questWork.Value, true))
             {
                 logger.LogInformation("Skipping step, as quest variables match");
                 return true;
index 91a43e262db12e2493d1468cf9ed2fd4dc0a0ad3..22d14d666f1423df07582e3061758265519506a4 100644 (file)
@@ -18,7 +18,7 @@ internal static class WaitAtEnd
     {
         public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
         {
-            if (step.CompletionQuestVariablesFlags.Count == 6)
+            if (step.CompletionQuestVariablesFlags.Count == 6 && step.CompletionQuestVariablesFlags.Any(x => x is > 0))
             {
                 var task = serviceProvider.GetRequiredService<WaitForCompletionFlags>()
                     .With(quest, step);
@@ -129,7 +129,7 @@ internal static class WaitAtEnd
         public ETaskResult Update()
         {
             QuestWork? questWork = gameFunctions.GetQuestEx(Quest.QuestId);
-            return questWork != null && Step.MatchesQuestVariables(questWork.Value)
+            return questWork != null && Step.MatchesQuestVariables(questWork.Value, false)
                 ? ETaskResult.TaskComplete
                 : ETaskResult.StillRunning;
         }
index f9bb1183f5b0fff718a06e2f15f931f6f7c11fc8..4542b5a045fde198f32ed0560a7afd9030c055c6 100644 (file)
@@ -534,9 +534,7 @@ internal sealed unsafe class GameFunctions
 
     public bool IsOccupied()
     {
-        if (_gameGui.TryGetAddonByName("FadeMiddle", out AtkUnitBase* fade) &&
-            LAddon.IsAddonReady(fade) &&
-            fade->IsVisible)
+        if (IsLoadingScreenVisible())
             return true;
 
         return _condition[ConditionFlag.Occupied] || _condition[ConditionFlag.Occupied30] ||
@@ -546,4 +544,11 @@ internal sealed unsafe class GameFunctions
                _condition[ConditionFlag.Casting] || _condition[ConditionFlag.Unknown57] ||
                _condition[ConditionFlag.BetweenAreas] || _condition[ConditionFlag.BetweenAreas51];
     }
+
+    public bool IsLoadingScreenVisible()
+    {
+        return _gameGui.TryGetAddonByName("FadeMiddle", out AtkUnitBase* fade) &&
+               LAddon.IsAddonReady(fade) &&
+               fade->IsVisible;
+    }
 }
index 31013f2cee68a362cad9d8f4d4e9dd5612075623..44e3ce446ac069e0875fe157984154b1ca1b051f 100644 (file)
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
 using System.Numerics;
 using System.Text.Json.Serialization;
@@ -50,7 +51,11 @@ internal sealed class QuestStep
     public IList<short?> CompletionQuestVariablesFlags { get; set; } = new List<short?>();
     public IList<DialogueChoice> DialogueChoices { get; set; } = new List<DialogueChoice>();
 
-    public unsafe bool MatchesQuestVariables(QuestWork questWork)
+    /// <summary>
+    /// Positive values: Must be set to this value; will wait for the step to have these set.
+    /// Negative values: Will skip if set to this value, won't wait for this to be set.
+    /// </summary>
+    public unsafe bool MatchesQuestVariables(QuestWork questWork, bool forSkip)
     {
         if (CompletionQuestVariablesFlags.Count != 6)
             return false;
@@ -62,11 +67,19 @@ internal sealed class QuestStep
                 continue;
 
             byte actualValue = questWork.Variables[i];
-            byte expectedValue = check > 0 ? (byte)check : (byte)0;
             byte checkByte = check > 0 ? (byte)check : (byte)-check;
-
-            if ((actualValue & checkByte) != expectedValue)
-                return false;
+            if (forSkip)
+            {
+                byte expectedValue = (byte)Math.Abs(check.Value);
+                if ((actualValue & checkByte) != expectedValue)
+                    return false;
+            }
+            else if (!forSkip && check > 0)
+            {
+                byte expectedValue = check > 0 ? (byte)check : (byte)0;
+                if ((actualValue & checkByte) != expectedValue)
+                    return false;
+            }
         }
 
         return true;
index e4675d69e49addac298ae71b9cf72475b48055d9..dc5c89b7fe000e291f2d18c7a6b417e188c0e654 100644 (file)
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
     <PropertyGroup>
         <TargetFramework>net8.0-windows</TargetFramework>
-        <Version>0.8</Version>
+        <Version>0.9</Version>
         <LangVersion>12</LangVersion>
         <Nullable>enable</Nullable>
         <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>