Update validation for instant quests
authorLiza Carvelli <liza@carvel.li>
Fri, 19 Jul 2024 07:14:18 +0000 (09:14 +0200)
committerLiza Carvelli <liza@carvel.li>
Fri, 19 Jul 2024 07:14:18 +0000 (09:14 +0200)
QuestPaths/5.x - Shadowbringers/Unlocks/Instant/3603_The Boutique Always Wins.json
QuestPaths/7.x - Dawntrail/Side Quests/Shaaloani/5126_A Refined Perspective.json
QuestPaths/7.x - Dawntrail/Unlocks/Instant/5003_Leves of Tuliyollal.json [new file with mode: 0644]
QuestPaths/7.x - Dawntrail/Unlocks/Instant/5006_Sights of the West.json [new file with mode: 0644]
QuestPaths/7.x - Dawntrail/Unlocks/Instant/5007_Sights of the West and Beyond.json
QuestPaths/7.x - Dawntrail/Unlocks/Instant/5008_Dawn of a New Deal.json
Questionable/Controller/QuestController.cs
Questionable/Model/QuestInfo.cs
Questionable/Validation/Validators/BasicSequenceValidator.cs
Questionable/Windows/QuestSelectionWindow.cs
Questionable/Windows/QuestWindow.cs

index 43e1af19e18ca46b45befa8bcdef85cf4cf64bde..4c51e613e6b483be37ed87d51659b78eafe58c25 100644 (file)
@@ -13,8 +13,7 @@
             "Z": -25.223206
           },
           "TerritoryId": 820,
-          "InteractionType": "AcceptQuest",
-          "Comment": "Quest is completed instantly"
+          "InteractionType": "AcceptQuest"
         }
       ]
     }
index 5b67efc941f4457d27e987c26b0887ebb836b74a..03a6cbcd0c5a69bf5c90f875caf15d34e1d93a4e 100644 (file)
@@ -29,7 +29,7 @@
           },
           "TerritoryId": 1190,
           "InteractionType": "Instruction",
-          "Comment": "(from left to right) pump, middle of the connecting pipes, barrels"
+          "Comment": "Click (from left to right) pump, middle of the connecting pipes, barrels"
         }
       ]
     },
diff --git a/QuestPaths/7.x - Dawntrail/Unlocks/Instant/5003_Leves of Tuliyollal.json b/QuestPaths/7.x - Dawntrail/Unlocks/Instant/5003_Leves of Tuliyollal.json
new file mode 100644 (file)
index 0000000..0f5b27e
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1048390,
+          "Position": {
+            "X": 15.243713,
+            "Y": -14.000001,
+            "Z": 85.83191
+          },
+          "TerritoryId": 1185,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/7.x - Dawntrail/Unlocks/Instant/5006_Sights of the West.json b/QuestPaths/7.x - Dawntrail/Unlocks/Instant/5006_Sights of the West.json
new file mode 100644 (file)
index 0000000..6d5abcc
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1048510,
+          "Position": {
+            "X": 28.67163,
+            "Y": 50.13025,
+            "Z": -40.940002
+          },
+          "TerritoryId": 1185,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    }
+  ]
+}
index fd2ab340b0f98d26d88565947cc17e091e3f8597..17c970cb94dd9cca2379b9911ba1f47176bc4830 100644 (file)
@@ -13,8 +13,7 @@
             "Z": -52.99463
           },
           "TerritoryId": 1186,
-          "InteractionType": "AcceptQuest",
-          "Comment": "Quest is completed instantly"
+          "InteractionType": "AcceptQuest"
         }
       ]
     }
index 4cc2f982fdd355229bd2c20a9c0ed0a9ff766794..40a70b2e195d33b2d9ba91989291653568283705 100644 (file)
@@ -13,8 +13,7 @@
             "Z": -38.132385
           },
           "TerritoryId": 1186,
-          "InteractionType": "AcceptQuest",
-          "Comment": "Quest is completed instantly"
+          "InteractionType": "AcceptQuest"
         }
       ]
     }
index 2f5de9f1964c6bd7e192d95872eea64c06c5e1fe..141bc91d68ed4372281f430fd1d34158865e206c 100644 (file)
@@ -83,7 +83,6 @@ internal sealed class QuestController
     public QuestProgress? NextQuest => _nextQuest;
 
     public string? DebugState { get; private set; }
-    public string? Comment { get; private set; }
 
     public void Reload()
     {
@@ -212,7 +211,6 @@ internal sealed class QuestController
             if (questToRun == null)
             {
                 DebugState = "No quest active";
-                Comment = null;
                 Stop("No quest active");
                 return;
             }
@@ -240,7 +238,6 @@ internal sealed class QuestController
             if (sequence == null)
             {
                 DebugState = "Sequence not found";
-                Comment = null;
                 Stop("Unknown sequence");
                 return;
             }
@@ -248,7 +245,6 @@ internal sealed class QuestController
             if (questToRun.Step == 255)
             {
                 DebugState = "Step completed";
-                Comment = null;
                 if (_currentTask != null || _taskQueue.Count > 0)
                     Stop("Step complete", continueIfAutomatic: true);
                 return;
@@ -257,14 +253,11 @@ internal sealed class QuestController
             if (questToRun.Step >= sequence.Steps.Count)
             {
                 DebugState = "Step not found";
-                Comment = null;
                 Stop("Unknown step");
                 return;
             }
 
-            var step = sequence.Steps[questToRun.Step];
             DebugState = null;
-            Comment = step.Comment ?? sequence.Comment ?? q.Root.Comment;
         }
     }
 
index 5b7523e81d6759f22d80942e516546d38440d141..4ae135471b934cd0df5a64a1733139f412ab7ec4 100644 (file)
@@ -22,6 +22,7 @@ internal sealed class QuestInfo
         QuestLocks = quest.QuestLock.Select(x => (ushort)(x.Row & 0xFFFFF)).Where(x => x != 0).ToImmutableList();
         QuestLockJoin = (QuestJoin)quest.QuestLockJoin;
         IsMainScenarioQuest = quest.JournalGenre?.Value?.JournalCategory?.Value?.JournalSection?.Row is 0 or 1;
+        CompletesInstantly = quest.ToDoCompleteSeq[0] == 0;
     }
 
     public ushort QuestId { get; }
@@ -31,9 +32,10 @@ internal sealed class QuestInfo
     public bool IsRepeatable { get; }
     public ImmutableList<ushort> PreviousQuests { get; }
     public QuestJoin PreviousQuestJoin { get; }
-    public bool IsMainScenarioQuest { get; }
     public ImmutableList<ushort> QuestLocks { get; set; }
     public QuestJoin QuestLockJoin { get; set; }
+    public bool IsMainScenarioQuest { get; }
+    public bool CompletesInstantly { get; set; }
 
     public string SimplifiedName => Name
         .TrimStart(SeIconChar.QuestSync.ToIconChar(), SeIconChar.QuestRepeatable.ToIconChar(), ' ');
index 8ea19a14235f471da0795ead4c96a7876f3243d8..c8d40a36988ec03108f80df18d97ff01f300e3d3 100644 (file)
@@ -27,21 +27,37 @@ internal sealed class BasicSequenceValidator : IQuestValidator
             yield break;
         }
 
-        int maxSequence = sequences.Select(x => x.Sequence)
-            .Where(x => x != 255)
-            .Max();
-
-        for (int i = 0; i < maxSequence; i++)
+        if (quest.Info.CompletesInstantly)
         {
-            var foundSequences = sequences.Where(x => x.Sequence == i).ToList();
-            var issue = ValidateSequences(quest, i, foundSequences);
-            if (issue != null)
-                yield return issue;
-        }
+            foreach (var sequence in sequences)
+            {
+                if (sequence == foundStart)
+                    continue;
 
-        // some quests finish instantly
-        if (maxSequence > 0 || foundStart.Steps.Count > 1)
+                yield return new ValidationIssue
+                {
+                    QuestId = quest.QuestId,
+                    Sequence = (byte)sequence.Sequence,
+                    Step = null,
+                    Severity = EIssueSeverity.Error,
+                    Description = "Instant quest should not have any sequences after the start",
+                };
+            }
+        }
+        else
         {
+            int maxSequence = sequences.Select(x => x.Sequence)
+                .Where(x => x != 255)
+                .Max();
+
+            for (int i = 0; i < maxSequence; i++)
+            {
+                var foundSequences = sequences.Where(x => x.Sequence == i).ToList();
+                var issue = ValidateSequences(quest, i, foundSequences);
+                if (issue != null)
+                    yield return issue;
+            }
+
             var foundEnding = sequences.Where(x => x.Sequence == 255).ToList();
             var endingIssue = ValidateSequences(quest, 255, foundEnding);
             if (endingIssue != null)
index 4ff4c3c0c33184ae254c0591acf2b67c52d2c1b6..9ed5c439f4515f38d00a677d7a6382f0c8089c1f 100644 (file)
@@ -172,7 +172,13 @@ internal sealed class QuestSelectionWindow : LWindow
                             ImGui.TextUnformatted("Repeatable");
                         }
 
-                        if (!_questRegistry.IsKnownQuest(quest.QuestId))
+                        if (quest.CompletesInstantly)
+                        {
+                            ImGui.SameLine();
+                            ImGui.TextUnformatted("Instant");
+                        }
+
+                        if (!isKnownQuest)
                         {
                             ImGui.SameLine();
                             ImGui.TextUnformatted("NoQuestPath");
index 0ebe5517322ff21c9fd542528984ea3dc730717e..a5e3044a2aa9624f1284c453b3ebb0c4f009e46d 100644 (file)
@@ -220,11 +220,19 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
             else
             {
                 ImGui.BeginDisabled();
-                ImGui.TextUnformatted(_questController.DebugState ?? "--");
+                ImGui.TextUnformatted(_questController.DebugState ?? string.Empty);
                 ImGui.EndDisabled();
             }
 
-            ImGui.TextUnformatted(_questController.Comment ?? "--");
+            QuestSequence? currentSequence = currentQuest.Quest.FindSequence(currentQuest.Sequence);
+            QuestStep? currentStep = currentSequence?.FindStep(currentQuest.Step);
+            bool colored = currentStep is
+                { InteractionType: EInteractionType.Instruction or EInteractionType.WaitForManualProgress };
+            if (colored)
+                ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudOrange);
+            ImGui.TextUnformatted(currentStep?.Comment ?? currentSequence?.Comment ?? currentQuest.Quest.Root.Comment ?? string.Empty);
+            if (colored)
+                ImGui.PopStyleColor();
 
             //var nextStep = _questController.GetNextStep();
             //ImGui.BeginDisabled(nextStep.Step == null);
@@ -257,15 +265,12 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
                 _questController.Stop("Manual");
             }
 
-            QuestStep? currentStep = currentQuest.Quest
-                .FindSequence(currentQuest.Sequence)
-                ?.FindStep(currentQuest.Step);
             bool lastStep = currentStep ==
                             currentQuest.Quest.FindSequence(currentQuest.Sequence)?.Steps.LastOrDefault();
-            bool colored = currentStep != null
-                           && !lastStep
-                           && currentStep.InteractionType == EInteractionType.Instruction
-                           && _questController.HasCurrentTaskMatching<WaitAtEnd.WaitNextStepOrSequence>();
+            colored = currentStep != null
+                      && !lastStep
+                      && currentStep.InteractionType == EInteractionType.Instruction
+                      && _questController.HasCurrentTaskMatching<WaitAtEnd.WaitNextStepOrSequence>();
 
             ImGui.BeginDisabled(lastStep);
             if (colored)