Very experimental combat implementation (requires RSR)
authorLiza Carvelli <liza@carvel.li>
Sun, 14 Jul 2024 01:42:30 +0000 (03:42 +0200)
committerLiza Carvelli <liza@carvel.li>
Sun, 14 Jul 2024 01:42:30 +0000 (03:42 +0200)
44 files changed:
QuestPathGenerator/QuestSourceGenerator.cs
QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3690_A Flowery Frolic.json [new file with mode: 0644]
QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3691_Sharing Is Caring.json [new file with mode: 0644]
QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3692_The Aesthetician of Il Mheg.json [new file with mode: 0644]
QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3693_Sweet as Honey.json [new file with mode: 0644]
QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3694_I Dream of Shinies.json [new file with mode: 0644]
QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3695_The Wonder of Witchweed.json [new file with mode: 0644]
QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3696_Of Marvelous Mallow.json [new file with mode: 0644]
QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3697_The Moss Fungus Menace.json [new file with mode: 0644]
QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3703_Raiders of the Lost Pork.json [new file with mode: 0644]
QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3704_Pebble without a Cause.json [new file with mode: 0644]
QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3709_No Accounting for Taste.json [new file with mode: 0644]
QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/~template.json [new file with mode: 0644]
QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Progress/3685_The Heart's Oasis.json [new file with mode: 0644]
QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Unlock/3683_Manic Pixie Dream Realm.json [new file with mode: 0644]
QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4552_Deal by the Docks.json [new file with mode: 0644]
QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4553_Do It for the Vine.json [new file with mode: 0644]
QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4554_Missing Rider.json [new file with mode: 0644]
QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4557_Gulal Generosity.json [new file with mode: 0644]
QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4558_Essential Eggredients.json [new file with mode: 0644]
QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4559_Darling Defender.json [new file with mode: 0644]
QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4564_Olfactory Warfare.json
QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4565_Ridin' Hazards.json
QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4566_Hippo Scrub.json
QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4567_Vanaspati's Blessing.json
QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4568_Hells Hath No Fury as a Hippo Scorned.json
QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4569_Tusk Trouble.json
QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/~template.json [new file with mode: 0644]
QuestPaths/quest-v1.json
Questionable/Controller/CombatController.cs [new file with mode: 0644]
Questionable/Controller/CombatModules/ICombatModule.cs [new file with mode: 0644]
Questionable/Controller/CombatModules/RotationSolverRebornModule.cs [new file with mode: 0644]
Questionable/Controller/GameUiController.cs
Questionable/Controller/QuestController.cs
Questionable/Controller/QuestRegistry.cs
Questionable/Controller/Steps/Interactions/Combat.cs
Questionable/Controller/Steps/Shared/SkipCondition.cs
Questionable/Controller/Steps/Shared/WaitAtEnd.cs
Questionable/Controller/Utils/QuestWorkUtils.cs [new file with mode: 0644]
Questionable/Data/QuestData.cs
Questionable/Model/EMovementType.cs
Questionable/Model/V1/QuestStepExtensions.cs [deleted file]
Questionable/QuestionablePlugin.cs
Questionable/Windows/QuestWindow.cs

index 595cdb8807addd4f6d78c709e193af42928214ca..66f060ec96453323fe82f96ea6520e2824e2ffde 100644 (file)
@@ -55,6 +55,9 @@ public class QuestSourceGenerator : ISourceGenerator
                 continue;
 
             string name = Path.GetFileName(additionalFile.Path);
+            if (!name.Contains('_'))
+                continue;
+
             ushort id = ushort.Parse(name.Substring(0, name.IndexOf('_')));
 
             var text = additionalFile.GetText();
diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3690_A Flowery Frolic.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3690_A Flowery Frolic.json
new file mode 100644 (file)
index 0000000..7dc3f16
--- /dev/null
@@ -0,0 +1,56 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 2010859,
+          "Position": {
+            "X": -743.86206,
+            "Y": 78.96533,
+            "Z": 457.14502
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Combat",
+          "EnemySpawnType": "AfterInteraction",
+          "KillEnemyDataIds": [
+            11443
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "CompleteQuest",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3691_Sharing Is Caring.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3691_Sharing Is Caring.json
new file mode 100644 (file)
index 0000000..80b35d7
--- /dev/null
@@ -0,0 +1,57 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 1032140,
+          "Position": {
+            "X": -459.89166,
+            "Y": 42.65948,
+            "Z": -305.71454
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Say",
+          "ChatMessage": {
+            "Key": "TEXT_BANPIX103_03691_SAYTODO_000_030"
+          },
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Il Mheg - Lydha Lran",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3692_The Aesthetician of Il Mheg.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3692_The Aesthetician of Il Mheg.json
new file mode 100644 (file)
index 0000000..330fd10
--- /dev/null
@@ -0,0 +1,106 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Comment": "TODO Has multiple possible targets, unsure if QW works",
+      "Steps": [
+        {
+          "Position": {
+            "X": -342.05676,
+            "Y": 37.5036,
+            "Z": 434.53723
+          },
+          "TerritoryId": 816,
+          "InteractionType": "WalkTo",
+          "Fly": true,
+          "CompletionQuestVariablesFlags": [
+            null,
+            null,
+            null,
+            null,
+            null,
+            -128
+          ]
+        },
+        {
+          "DataId": 2010860,
+          "Position": {
+            "X": -340.38306,
+            "Y": 38.77307,
+            "Z": 434.07336
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Interact",
+          "CompletionQuestVariablesFlags": [
+            null,
+            null,
+            null,
+            null,
+            null,
+            128
+          ]
+        },
+        {
+          "DataId": 2010861,
+          "Position": {
+            "X": -332.44836,
+            "Y": 44.47998,
+            "Z": 462.15002
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Interact",
+          "SkipIf": [
+            "NotTargetable"
+          ]
+        },
+        {
+          "DataId": 2010863,
+          "Position": {
+            "X": -293.08008,
+            "Y": 42.70996,
+            "Z": 463.61487
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Interact",
+          "SkipIf": [
+            "NotTargetable"
+          ],
+          "IgnoreDistanceToObject": true
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "CompleteQuest",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3693_Sweet as Honey.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3693_Sweet as Honey.json
new file mode 100644 (file)
index 0000000..6ddd637
--- /dev/null
@@ -0,0 +1,57 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 2010864,
+          "Position": {
+            "X": 3.8909912,
+            "Y": 13.90094,
+            "Z": 637.23206
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Combat",
+          "EnemySpawnType": "AfterInteraction",
+          "KillEnemyDataIds": [
+            11444
+          ],
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "CompleteQuest",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3694_I Dream of Shinies.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3694_I Dream of Shinies.json
new file mode 100644 (file)
index 0000000..bd3cf85
--- /dev/null
@@ -0,0 +1,75 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "Position": {
+            "X": -338.70084,
+            "Y": 9.922639,
+            "Z": -181.90271
+          },
+          "TerritoryId": 816,
+          "InteractionType": "WalkTo",
+          "Fly": true
+        },
+        {
+          "Position": {
+            "X": -332.49713,
+            "Y": -44.52391,
+            "Z": -242.4296
+          },
+          "TerritoryId": 816,
+          "InteractionType": "WalkTo",
+          "Fly": true,
+          "DisableNavmesh": true
+        },
+        {
+          "DataId": 2010866,
+          "Position": {
+            "X": -335.59174,
+            "Y": -54.154297,
+            "Z": -293.41577
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Interact",
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Il Mheg - Lydha Lran",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3695_The Wonder of Witchweed.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3695_The Wonder of Witchweed.json
new file mode 100644 (file)
index 0000000..900ec02
--- /dev/null
@@ -0,0 +1,58 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 2010868,
+          "Position": {
+            "X": -504.32596,
+            "Y": 77.22583,
+            "Z": -410.11676
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Combat",
+          "EnemySpawnType": "AfterInteraction",
+          "KillEnemyDataIds": [
+            11445
+          ],
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Il Mheg - Lydha Lran",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3696_Of Marvelous Mallow.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3696_Of Marvelous Mallow.json
new file mode 100644 (file)
index 0000000..a689011
--- /dev/null
@@ -0,0 +1,81 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 2010888,
+          "Position": {
+            "X": -171.58777,
+            "Y": 5.2338257,
+            "Z": -252.88782
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Interact",
+          "Fly": true,
+          "CompletionQuestVariablesFlags": [
+            null,
+            null,
+            null,
+            null,
+            null,
+            128
+          ]
+        },
+        {
+          "DataId": 2010889,
+          "Position": {
+            "X": -170.1839,
+            "Y": 4.9591064,
+            "Z": -283.0396
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Interact",
+          "Fly": true,
+          "CompletionQuestVariablesFlags": [
+            null,
+            null,
+            null,
+            null,
+            null,
+            64
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Il Mheg - Lydha Lran",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3697_The Moss Fungus Menace.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3697_The Moss Fungus Menace.json
new file mode 100644 (file)
index 0000000..ef2fc0f
--- /dev/null
@@ -0,0 +1,59 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 2010890,
+          "Position": {
+            "X": 10.0251465,
+            "Y": 32.944214,
+            "Z": -608.6061
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Combat",
+          "EnemySpawnType": "AfterInteraction",
+          "KillEnemyDataIds": [
+            11446
+          ],
+          "AetheryteShortcut": "Il Mheg - Wolekdorf",
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Il Mheg - Lydha Lran",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3703_Raiders of the Lost Pork.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3703_Raiders of the Lost Pork.json
new file mode 100644 (file)
index 0000000..5f4962f
--- /dev/null
@@ -0,0 +1,53 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 1032167,
+          "Position": {
+            "X": -416.52557,
+            "Y": 20.303928,
+            "Z": 221.75928
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Interact",
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "CompleteQuest",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3704_Pebble without a Cause.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3704_Pebble without a Cause.json
new file mode 100644 (file)
index 0000000..940bafb
--- /dev/null
@@ -0,0 +1,59 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 2010901,
+          "Position": {
+            "X": -413.96204,
+            "Y": -0.10687256,
+            "Z": -55.77173
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Combat",
+          "EnemySpawnType": "AfterInteraction",
+          "KillEnemyDataIds": [
+            11451
+          ],
+          "Fly": true,
+          "Comment": "TODO Combat is optional, check where we should walk"
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Il Mheg - Lydha Lran",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3709_No Accounting for Taste.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/3709_No Accounting for Taste.json
new file mode 100644 (file)
index 0000000..774fe04
--- /dev/null
@@ -0,0 +1,57 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 2010909,
+          "Position": {
+            "X": -242.08441,
+            "Y": 0.83917236,
+            "Z": 223.80408
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Combat",
+          "EnemySpawnType": "AfterInteraction",
+          "KillEnemyDataIds": [
+            11450
+          ],
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "CompleteQuest",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/~template.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Dailies/~template.json
new file mode 100644 (file)
index 0000000..7b587be
--- /dev/null
@@ -0,0 +1,43 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1031809,
+          "Position": {
+            "X": -454.3069,
+            "Y": 71.43217,
+            "Z": 575.1278
+          },
+          "TerritoryId": 816,
+          "InteractionType": "CompleteQuest",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Progress/3685_The Heart's Oasis.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Progress/3685_The Heart's Oasis.json
new file mode 100644 (file)
index 0000000..39263b7
--- /dev/null
@@ -0,0 +1,231 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031806,
+          "Position": {
+            "X": -464.59143,
+            "Y": 71.76874,
+            "Z": 573.8766
+          },
+          "TerritoryId": 816,
+          "InteractionType": "AcceptQuest",
+          "DialogueChoices": [
+            {
+              "Type": "List",
+              "Prompt": "TEXT_BANPIX003_03685_Q1_000_000",
+              "Answer": "TEXT_BANPIX003_03685_A1_000_003"
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 1031892,
+          "Position": {
+            "X": -461.5702,
+            "Y": 72.51754,
+            "Z": 586.48047
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Interact",
+          "TargetTerritoryId": 891
+        },
+        {
+          "DataId": 1031866,
+          "Position": {
+            "X": 78.690796,
+            "Y": 0.15887591,
+            "Z": 50.0343
+          },
+          "TerritoryId": 891,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 2,
+      "Steps": [
+        {
+          "DataId": 1031865,
+          "Position": {
+            "X": 76.37134,
+            "Y": 0.15887591,
+            "Z": 51.987427
+          },
+          "TerritoryId": 891,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 3,
+      "Steps": [
+        {
+          "DataId": 1031867,
+          "Position": {
+            "X": 303.15088,
+            "Y": 1.4685827,
+            "Z": -313.34406
+          },
+          "TerritoryId": 815,
+          "InteractionType": "Interact",
+          "AetheryteShortcut": "Amh Araeng - Mord Souq",
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 4,
+      "Steps": [
+        {
+          "Position": {
+            "X": 201.67809,
+            "Y": 7.1558266,
+            "Z": -137.17564
+          },
+          "TerritoryId": 815,
+          "InteractionType": "WalkTo",
+          "Fly": true
+        },
+        {
+          "DataId": 1031869,
+          "Position": {
+            "X": 201.06812,
+            "Y": 7.1558266,
+            "Z": -138.81134
+          },
+          "TerritoryId": 815,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 5,
+      "Steps": [
+        {
+          "Position": {
+            "X": 355.25076,
+            "Y": -19.54202,
+            "Z": -4.2170615
+          },
+          "StopDistance": 0.5,
+          "TerritoryId": 815,
+          "InteractionType": "Combat",
+          "EnemySpawnType": "AutoOnEnterArea",
+          "KillEnemyDataIds": [
+            11439
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 6,
+      "Steps": [
+        {
+          "DataId": 1031871,
+          "Position": {
+            "X": 350.05713,
+            "Y": -18.544811,
+            "Z": -15.793152
+          },
+          "StopDistance": 7,
+          "TerritoryId": 815,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 7,
+      "Steps": [
+        {
+          "Position": {
+            "X": 201.67809,
+            "Y": 7.1558266,
+            "Z": -137.17564
+          },
+          "TerritoryId": 815,
+          "InteractionType": "WalkTo",
+          "Fly": true
+        },
+        {
+          "DataId": 1031869,
+          "Position": {
+            "X": 201.06812,
+            "Y": 7.1558266,
+            "Z": -138.81134
+          },
+          "TerritoryId": 815,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 8,
+      "Steps": [
+        {
+          "DataId": 1031892,
+          "Position": {
+            "X": -461.5702,
+            "Y": 72.51754,
+            "Z": 586.48047
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Interact",
+          "TargetTerritoryId": 891,
+          "AetheryteShortcut": "Il Mheg - Lydha Lran",
+          "Fly": true
+        },
+        {
+          "DataId": 1032030,
+          "Position": {
+            "X": 90.40967,
+            "Y": 40.45613,
+            "Z": -105.48566
+          },
+          "TerritoryId": 891,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 9,
+      "Steps": [
+        {
+          "DataId": 1032352,
+          "Position": {
+            "X": 95.994385,
+            "Y": 38.906254,
+            "Z": -89.37213
+          },
+          "TerritoryId": 891,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1031806,
+          "Position": {
+            "X": -464.59143,
+            "Y": 71.76874,
+            "Z": 573.8766
+          },
+          "TerritoryId": 816,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Il Mheg - Lydha Lran",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Unlock/3683_Manic Pixie Dream Realm.json b/QuestPaths/5.x - Shadowbringers/Tribal/Pixies/Unlock/3683_Manic Pixie Dream Realm.json
new file mode 100644 (file)
index 0000000..302a217
--- /dev/null
@@ -0,0 +1,214 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031839,
+          "Position": {
+            "X": 95.628296,
+            "Y": 1.490116E-08,
+            "Z": 204.11987
+          },
+          "TerritoryId": 819,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 1031843,
+          "Position": {
+            "X": 152.48328,
+            "Y": 0.21766767,
+            "Z": 655.4512
+          },
+          "TerritoryId": 813,
+          "InteractionType": "Interact",
+          "AetheryteShortcut": "Lakeland - Fort Jobb",
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 2,
+      "Steps": [
+        {
+          "DataId": 1031845,
+          "Position": {
+            "X": -200.09155,
+            "Y": 2.2048368,
+            "Z": 737.8804
+          },
+          "TerritoryId": 813,
+          "InteractionType": "Interact",
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 3,
+      "Steps": [
+        {
+          "Position": {
+            "X": 234.24565,
+            "Y": 10.83118,
+            "Z": 738.46594
+          },
+          "StopDistance": 1,
+          "TerritoryId": 813,
+          "InteractionType": "Combat",
+          "EnemySpawnType": "AutoOnEnterArea",
+          "KillEnemyDataIds": [
+            11437
+          ],
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 4,
+      "Steps": [
+        {
+          "DataId": 1031847,
+          "Position": {
+            "X": 231.92188,
+            "Y": 9.887029,
+            "Z": 726.74133
+          },
+          "StopDistance": 7,
+          "TerritoryId": 813,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 5,
+      "Steps": [
+        {
+          "DataId": 1031846,
+          "Position": {
+            "X": -204.76086,
+            "Y": 2.4649847,
+            "Z": 739.9557
+          },
+          "TerritoryId": 813,
+          "InteractionType": "Interact",
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 6,
+      "Steps": [
+        {
+          "DataId": 1031808,
+          "Position": {
+            "X": -461.53967,
+            "Y": 72.51729,
+            "Z": 586.48047
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Interact",
+          "AetheryteShortcut": "Il Mheg - Lydha Lran",
+          "Fly": true,
+          "DialogueChoices": [
+            {
+              "Type": "YesNo",
+              "Prompt": "TEXT_BANPIX001_03683_EVENTAREA_WARP_000_133",
+              "Yes": true
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 7,
+      "Steps": [
+        {
+          "Position": {
+            "X": 0,
+            "Y": 0,
+            "Z": 0
+          },
+          "TerritoryId": 1,
+          "InteractionType": "WalkTo",
+          "Comment": "Filler"
+        }
+      ]
+    },
+    {
+      "Sequence": 8,
+      "Steps": [
+        {
+          "DataId": 1031850,
+          "Position": {
+            "X": 55.588623,
+            "Y": -1.6532946,
+            "Z": 48.599854
+          },
+          "TerritoryId": 889,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 9,
+      "Steps": [
+        {
+          "Position": {
+            "X": 0,
+            "Y": 0,
+            "Z": 0
+          },
+          "TerritoryId": 1,
+          "InteractionType": "WalkTo",
+          "Comment": "Filler"
+        }
+      ]
+    },
+    {
+      "Sequence": 10,
+      "Steps": [
+        {
+          "DataId": 1032348,
+          "Position": {
+            "X": -18.295654,
+            "Y": 6.8822618,
+            "Z": -67.338135
+          },
+          "TerritoryId": 890,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1031806,
+          "Position": {
+            "X": -464.59143,
+            "Y": 71.76874,
+            "Z": 573.8766
+          },
+          "TerritoryId": 816,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Il Mheg - Lydha Lran",
+          "Fly": true,
+          "DialogueChoices": [
+            {
+              "Type": "List",
+              "Prompt": "TEXT_BANPIX001_03683_Q3_000_000",
+              "Answer": "TEXT_BANPIX001_03683_A3_000_001"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4552_Deal by the Docks.json b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4552_Deal by the Docks.json
new file mode 100644 (file)
index 0000000..3d6aba3
--- /dev/null
@@ -0,0 +1,70 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1042301,
+          "Position": {
+            "X": -66.02582,
+            "Y": 39.994705,
+            "Z": 321.06494
+          },
+          "TerritoryId": 957,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 1037644,
+          "Position": {
+            "X": -293.72095,
+            "Y": 1.4600283,
+            "Z": 551.0491
+          },
+          "TerritoryId": 957,
+          "InteractionType": "Interact",
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 2,
+      "Steps": [
+        {
+          "DataId": 1042366,
+          "Position": {
+            "X": 185.56494,
+            "Y": 1.8742322,
+            "Z": 760.4332
+          },
+          "TerritoryId": 957,
+          "InteractionType": "Interact",
+          "AetheryteShortcut": "Thavnair - Yedlihmad",
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1042301,
+          "Position": {
+            "X": -66.02582,
+            "Y": 39.994705,
+            "Z": 321.06494
+          },
+          "TerritoryId": 957,
+          "InteractionType": "CompleteQuest",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4553_Do It for the Vine.json b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4553_Do It for the Vine.json
new file mode 100644 (file)
index 0000000..9f22b89
--- /dev/null
@@ -0,0 +1,58 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1042301,
+          "Position": {
+            "X": -66.02582,
+            "Y": 39.994705,
+            "Z": 321.06494
+          },
+          "TerritoryId": 957,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 2012850,
+          "Position": {
+            "X": -399.74066,
+            "Y": 58.91504,
+            "Z": -354.97064
+          },
+          "TerritoryId": 957,
+          "InteractionType": "Combat",
+          "EnemySpawnType": "AfterInteraction",
+          "KillEnemyDataIds": [
+            14674,
+            14675
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1042301,
+          "Position": {
+            "X": -66.02582,
+            "Y": 39.994705,
+            "Z": 321.06494
+          },
+          "TerritoryId": 957,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Thavnair - Yedlihmad",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4554_Missing Rider.json b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4554_Missing Rider.json
new file mode 100644 (file)
index 0000000..f9767ce
--- /dev/null
@@ -0,0 +1,110 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1042301,
+          "Position": {
+            "X": -66.02582,
+            "Y": 39.994705,
+            "Z": 321.06494
+          },
+          "TerritoryId": 957,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 1042367,
+          "Position": {
+            "X": 507.01135,
+            "Y": 12.589098,
+            "Z": -482.96332
+          },
+          "TerritoryId": 957,
+          "InteractionType": "Interact",
+          "AetheryteShortcut": "Thavnair - Palaka's Stand",
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 2,
+      "Steps": [
+        {
+          "DataId": 2012851,
+          "Position": {
+            "X": 427.4204,
+            "Y": 18.44812,
+            "Z": -451.37714
+          },
+          "TerritoryId": 957,
+          "InteractionType": "Interact",
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 3,
+      "Steps": [
+        {
+          "DataId": 2012851,
+          "Position": {
+            "X": 427.4204,
+            "Y": 18.44812,
+            "Z": -451.37714
+          },
+          "TerritoryId": 957,
+          "InteractionType": "Interact",
+          "SkipIf": [
+            "NotTargetable"
+          ]
+        },
+        {
+          "Position": {
+            "X": 436.76804,
+            "Y": 21.84539,
+            "Z": -466.46533
+          },
+          "TerritoryId": 957,
+          "InteractionType": "WalkTo",
+          "DisableNavmesh": true
+        },
+        {
+          "DataId": 1042367,
+          "Position": {
+            "X": 507.01135,
+            "Y": 12.589098,
+            "Z": -482.96332
+          },
+          "TerritoryId": 957,
+          "InteractionType": "Interact",
+          "DisableNavmesh": true
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1042301,
+          "Position": {
+            "X": -66.02582,
+            "Y": 39.994705,
+            "Z": 321.06494
+          },
+          "TerritoryId": 957,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Thavnair - Yedlihmad",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4557_Gulal Generosity.json b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4557_Gulal Generosity.json
new file mode 100644 (file)
index 0000000..f2476fc
--- /dev/null
@@ -0,0 +1,175 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1042301,
+          "Position": {
+            "X": -66.02582,
+            "Y": 39.994705,
+            "Z": 321.06494
+          },
+          "TerritoryId": 957,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 1042302,
+          "Position": {
+            "X": -102.43384,
+            "Y": 40.00001,
+            "Z": 331.89893
+          },
+          "TerritoryId": 957,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 2,
+      "Steps": [
+        {
+          "Position": {
+            "X": 436.3157,
+            "Y": 3.1168795,
+            "Z": -241.61731
+          },
+          "TerritoryId": 957,
+          "InteractionType": "WalkTo",
+          "Fly": true,
+          "Land": true,
+          "CompletionQuestVariablesFlags": [
+            null,
+            null,
+            null,
+            null,
+            null,
+            -32
+          ]
+        },
+        {
+          "DataId": 1042372,
+          "Position": {
+            "X": 441.062,
+            "Y": 3.5405273,
+            "Z": -238.78845
+          },
+          "StopDistance": 5,
+          "TerritoryId": 957,
+          "InteractionType": "Action",
+          "Action": "Yellow Gulal",
+          "CompletionQuestVariablesFlags": [
+            null,
+            null,
+            null,
+            null,
+            null,
+            32
+          ]
+        },
+        {
+          "Position": {
+            "X": 378.90213,
+            "Y": 3.1168797,
+            "Z": -226.82733
+          },
+          "TerritoryId": 957,
+          "InteractionType": "WalkTo",
+          "Fly": true,
+          "Land": true,
+          "CompletionQuestVariablesFlags": [
+            null,
+            null,
+            null,
+            null,
+            null,
+            -64
+          ]
+        },
+        {
+          "DataId": 1042371,
+          "Position": {
+            "X": 376.7605,
+            "Y": 3.3540652,
+            "Z": -225.33002
+          },
+          "StopDistance": 5,
+          "TerritoryId": 957,
+          "InteractionType": "Action",
+          "Action": "Blue Gulal",
+          "CompletionQuestVariablesFlags": [
+            null,
+            null,
+            null,
+            null,
+            null,
+            64
+          ]
+        },
+        {
+          "Position": {
+            "X": 404.06558,
+            "Y": 13.027411,
+            "Z": -307.05457
+          },
+          "TerritoryId": 957,
+          "InteractionType": "WalkTo",
+          "Fly": true,
+          "Land": true,
+          "CompletionQuestVariablesFlags": [
+            null,
+            null,
+            null,
+            null,
+            null,
+            -128
+          ]
+        },
+        {
+          "DataId": 1042373,
+          "Position": {
+            "X": 406.1189,
+            "Y": 13.0274105,
+            "Z": -311.0857
+          },
+          "StopDistance": 5,
+          "TerritoryId": 957,
+          "InteractionType": "Action",
+          "Action": "Red Gulal",
+          "CompletionQuestVariablesFlags": [
+            null,
+            null,
+            null,
+            null,
+            null,
+            128
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1042301,
+          "Position": {
+            "X": -66.02582,
+            "Y": 39.994705,
+            "Z": 321.06494
+          },
+          "TerritoryId": 957,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Thavnair - Yedlihmad",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4558_Essential Eggredients.json b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4558_Essential Eggredients.json
new file mode 100644 (file)
index 0000000..92f8f29
--- /dev/null
@@ -0,0 +1,70 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1042301,
+          "Position": {
+            "X": -66.02582,
+            "Y": 39.994705,
+            "Z": 321.06494
+          },
+          "TerritoryId": 957,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 1042376,
+          "Position": {
+            "X": 205.34058,
+            "Y": 63.981293,
+            "Z": -640.4059
+          },
+          "TerritoryId": 957,
+          "InteractionType": "Interact",
+          "AetheryteShortcut": "Thavnair - Palaka's Stand",
+          "Fly": true
+        }
+      ]
+    },
+    {
+      "Sequence": 2,
+      "Steps": [
+        {
+          "DataId": 2012908,
+          "Position": {
+            "X": 208.23987,
+            "Y": 65.62903,
+            "Z": -642.1149
+          },
+          "TerritoryId": 957,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1042301,
+          "Position": {
+            "X": -66.02582,
+            "Y": 39.994705,
+            "Z": 321.06494
+          },
+          "TerritoryId": 957,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Thavnair - Yedlihmad",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4559_Darling Defender.json b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/4559_Darling Defender.json
new file mode 100644 (file)
index 0000000..44068d3
--- /dev/null
@@ -0,0 +1,73 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1042301,
+          "Position": {
+            "X": -66.02582,
+            "Y": 39.994705,
+            "Z": 321.06494
+          },
+          "TerritoryId": 957,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "Position": {
+            "X": -605.46277,
+            "Y": 2.1626635,
+            "Z": -336.87347
+          },
+          "StopDistance": 0.25,
+          "TerritoryId": 957,
+          "InteractionType": "Combat",
+          "EnemySpawnType": "AutoOnEnterArea",
+          "KillEnemyDataIds": [
+            14676
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 2,
+      "Steps": [
+        {
+          "DataId": 1042378,
+          "Position": {
+            "X": -605.46277,
+            "Y": 2.1626635,
+            "Z": -336.87347
+          },
+          "StopDistance": 5,
+          "TerritoryId": 957,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1042301,
+          "Position": {
+            "X": -66.02582,
+            "Y": 39.994705,
+            "Z": 321.06494
+          },
+          "TerritoryId": 957,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Thavnair - Yedlihmad",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
index 1c2b4997463636eb09ec175883469e439b6b1881..acfd58ad79341139042749f6f315720205f1ec95 100644 (file)
@@ -13,7 +13,7 @@
             "Z": 321.06494
           },
           "TerritoryId": 957,
-          "InteractionType": "Interact"
+          "InteractionType": "AcceptQuest"
         }
       ]
     },
index c2578b9a997f80442b347bac98ec23600285c360..8425fa74b4267241a76f094f868e74b9d2f78a32 100644 (file)
@@ -13,7 +13,7 @@
             "Z": 321.06494
           },
           "TerritoryId": 957,
-          "InteractionType": "Interact"
+          "InteractionType": "AcceptQuest"
         }
       ]
     },
index 25dd87c31156f36c9c0d090f2700a7783cf95644..5bb38148e43ec439a3f1c03888ac01c0bbc43ba5 100644 (file)
@@ -13,7 +13,7 @@
             "Z": 321.06494
           },
           "TerritoryId": 957,
-          "InteractionType": "Interact"
+          "InteractionType": "AcceptQuest"
         }
       ]
     },
index 18b9b83de1e98b4bc459c3cf82d2bf35040ee614..d486bec6c99e6e126896c6d9a9f1705ffaa11542 100644 (file)
@@ -13,7 +13,7 @@
             "Z": 321.06494
           },
           "TerritoryId": 957,
-          "InteractionType": "Interact"
+          "InteractionType": "AcceptQuest"
         }
       ]
     },
index 0a0aaa800a125a5ab944f842f7615b91af7bdbd9..477fae19507f05427fd529ffc190716bf32fb726 100644 (file)
@@ -13,7 +13,7 @@
             "Z": 321.06494
           },
           "TerritoryId": 957,
-          "InteractionType": "Interact"
+          "InteractionType": "AcceptQuest"
         }
       ]
     },
index 0d01f3861cefe929b01970258db685b514ca27a4..acafd9fa3e4999e015f99afccb93e2f81e9113e0 100644 (file)
@@ -13,7 +13,7 @@
             "Z": 321.06494
           },
           "TerritoryId": 957,
-          "InteractionType": "Interact"
+          "InteractionType": "AcceptQuest"
         }
       ]
     },
diff --git a/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/~template.json b/QuestPaths/6.x - Endwalker/Tribal/Arkasodara/Dailies/~template.json
new file mode 100644 (file)
index 0000000..f7be2e8
--- /dev/null
@@ -0,0 +1,43 @@
+{
+  "$schema": "https://carvel.li/questionable/quest-1.0",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1042301,
+          "Position": {
+            "X": -66.02582,
+            "Y": 39.994705,
+            "Z": 321.06494
+          },
+          "TerritoryId": 957,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1042301,
+          "Position": {
+            "X": -66.02582,
+            "Y": 39.994705,
+            "Z": 321.06494
+          },
+          "TerritoryId": 957,
+          "InteractionType": "CompleteQuest",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
index 34fe820102b509e2ddaed160656d5bf6613ac8e4..31d0f17ac2356c076937d2fc0fa4739dc18f69b0 100644 (file)
         },
         "required": [
           "Sequence"
-        ]
+        ],
+        "additionalProperties": false
       }
     }
   },
   "required": [
     "QuestSequence",
     "Author"
-  ]
+  ],
+  "additionalProperties": false
 }
diff --git a/Questionable/Controller/CombatController.cs b/Questionable/Controller/CombatController.cs
new file mode 100644 (file)
index 0000000..5b31530
--- /dev/null
@@ -0,0 +1,155 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Dalamud.Game.ClientState.Conditions;
+using Dalamud.Game.ClientState.Objects;
+using Dalamud.Game.ClientState.Objects.Enums;
+using Dalamud.Game.ClientState.Objects.Types;
+using Dalamud.Plugin.Services;
+using FFXIVClientStructs.FFXIV.Client.Game.Object;
+using Microsoft.Extensions.Logging;
+using Questionable.Controller.CombatModules;
+
+namespace Questionable.Controller;
+
+internal sealed class CombatController
+{
+    private readonly List<ICombatModule> _combatModules;
+    private readonly ITargetManager _targetManager;
+    private readonly IObjectTable _objectTable;
+    private readonly ICondition _condition;
+    private readonly IClientState _clientState;
+    private readonly ILogger<CombatController> _logger;
+
+    private CurrentFight? _currentFight;
+
+    public CombatController(IEnumerable<ICombatModule> combatModules, ITargetManager targetManager,
+        IObjectTable objectTable, ICondition condition, IClientState clientState, ILogger<CombatController> logger)
+    {
+        _combatModules = combatModules.ToList();
+        _targetManager = targetManager;
+        _objectTable = objectTable;
+        _condition = condition;
+        _clientState = clientState;
+        _logger = logger;
+    }
+
+    public bool IsRunning => _currentFight != null;
+
+    public bool Start(CombatData combatData)
+    {
+        Stop();
+
+        var combatModule = _combatModules.FirstOrDefault(x => x.IsLoaded);
+        if (combatModule == null)
+            return false;
+
+        if (combatModule.Start())
+        {
+            _currentFight = new CurrentFight
+            {
+                Module = combatModule,
+                Data = combatData,
+            };
+            return true;
+        }
+        else
+            return false;
+    }
+
+    /// <returns>true if still in combat, false otherwise</returns>
+    public bool Update()
+    {
+        if (_currentFight == null)
+            return false;
+
+        var target = _targetManager.Target;
+        if (target != null)
+        {
+            if (IsEnemyToKill(target))
+                return true;
+
+            var nextTarget = FindNextTarget();
+            if (nextTarget != null)
+            {
+                _logger.LogInformation("Changing next target to {TargetName} ({TargetId:X8})",
+                    nextTarget.Name.ToString(), nextTarget.GameObjectId);
+                _targetManager.Target = nextTarget;
+                _currentFight.Module.SetTarget(nextTarget);
+            }
+            else
+            {
+                _logger.LogInformation("Resetting next target");
+                _targetManager.Target = null;
+            }
+        }
+        else
+        {
+            var nextTarget = FindNextTarget();
+            if (nextTarget != null)
+            {
+                _logger.LogInformation("Setting next target to {TargetName} ({TargetId:X8})",
+                    nextTarget.Name.ToString(), nextTarget.GameObjectId);
+                _targetManager.Target = nextTarget;
+                _currentFight.Module.SetTarget(nextTarget);
+            }
+        }
+
+        return _condition[ConditionFlag.InCombat];
+    }
+
+    private IGameObject? FindNextTarget()
+    {
+        return _objectTable.Where(IsEnemyToKill).MinBy(x => (x.Position - _clientState.LocalPlayer!.Position).Length());
+    }
+
+    private unsafe bool IsEnemyToKill(IGameObject gameObject)
+    {
+        if (gameObject is IBattleChara battleChara)
+        {
+            if (battleChara.IsDead)
+                return false;
+
+            if (!battleChara.IsTargetable)
+                return false;
+
+            if (battleChara.TargetObjectId == _clientState.LocalPlayer?.GameObjectId)
+                return true;
+
+            if (_currentFight != null && _currentFight.Data.KillEnemyDataIds.Contains(battleChara.DataId))
+                return true;
+
+            if (battleChara.StatusFlags.HasFlag(StatusFlags.Hostile))
+            {
+                var gameObjectStruct = (GameObject*)gameObject.Address;
+                return gameObjectStruct->NamePlateIconId != 0;
+            }
+            else
+                return false;
+        }
+        else
+            return false;
+    }
+
+    public void Stop()
+    {
+        if (_currentFight != null)
+        {
+            _logger.LogInformation("Stopping current fight");
+            _currentFight.Module.Stop();
+        }
+
+        _currentFight = null;
+    }
+
+    private sealed class CurrentFight
+    {
+        public required ICombatModule Module { get; init; }
+        public required CombatData Data { get; init; }
+    }
+
+    public sealed class CombatData
+    {
+        public required ReadOnlyCollection<uint> KillEnemyDataIds { get; init; }
+    }
+}
diff --git a/Questionable/Controller/CombatModules/ICombatModule.cs b/Questionable/Controller/CombatModules/ICombatModule.cs
new file mode 100644 (file)
index 0000000..1a8d003
--- /dev/null
@@ -0,0 +1,14 @@
+using Dalamud.Game.ClientState.Objects.Types;
+
+namespace Questionable.Controller.CombatModules;
+
+internal interface ICombatModule
+{
+    bool IsLoaded { get; }
+
+    bool Start();
+
+    bool Stop();
+
+    void SetTarget(IGameObject nextTarget);
+}
diff --git a/Questionable/Controller/CombatModules/RotationSolverRebornModule.cs b/Questionable/Controller/CombatModules/RotationSolverRebornModule.cs
new file mode 100644 (file)
index 0000000..23e94b3
--- /dev/null
@@ -0,0 +1,98 @@
+using System;
+using System.Numerics;
+using Dalamud.Game.ClientState.Objects.Types;
+using Dalamud.Plugin;
+using Dalamud.Plugin.Ipc;
+using Dalamud.Plugin.Ipc.Exceptions;
+using Dalamud.Plugin.Services;
+using Microsoft.Extensions.Logging;
+using Questionable.Model;
+
+namespace Questionable.Controller.CombatModules;
+
+internal sealed class RotationSolverRebornModule : ICombatModule, IDisposable
+{
+    private readonly ILogger<RotationSolverRebornModule> _logger;
+    private readonly MovementController _movementController;
+    private readonly IClientState _clientState;
+    private readonly ICallGateSubscriber<string, object> _test;
+    private readonly ICallGateSubscriber<StateCommandType, object> _changeOperationMode;
+
+    public RotationSolverRebornModule(ILogger<RotationSolverRebornModule> logger, MovementController movementController,
+        IClientState clientState, IDalamudPluginInterface pluginInterface)
+    {
+        _logger = logger;
+        _movementController = movementController;
+        _clientState = clientState;
+        _test = pluginInterface.GetIpcSubscriber<string, object>("RotationSolverReborn.Test");
+        _changeOperationMode =
+            pluginInterface.GetIpcSubscriber<StateCommandType, object>("RotationSolverReborn.ChangeOperatingMode");
+    }
+
+    public bool IsLoaded
+    {
+        get
+        {
+            try
+            {
+                _test.InvokeAction("Validate RSR is callable from Questionable");
+                return true;
+            }
+            catch (IpcError)
+            {
+                return false;
+            }
+        }
+    }
+
+    public bool Start()
+    {
+        try
+        {
+            _changeOperationMode.InvokeAction(StateCommandType.Manual);
+            return true;
+        }
+        catch (IpcError e)
+        {
+            _logger.LogWarning(e, "Could not start combat");
+            return false;
+        }
+    }
+
+    public bool Stop()
+    {
+        try
+        {
+            _changeOperationMode.InvokeAction(StateCommandType.Off);
+            return true;
+        }
+        catch (IpcError e)
+        {
+            _logger.LogWarning(e, "Could not turn off combat");
+            return false;
+        }
+    }
+
+    public void SetTarget(IGameObject gameObject)
+    {
+        var player = _clientState.LocalPlayer;
+        if (player == null)
+            return; // uh oh
+
+        float hitboxOffset = player.HitboxRadius + gameObject.HitboxRadius;
+        float actualDistance = Vector3.Distance(player.Position, gameObject.Position);
+        float maxDistance = player.ClassJob.GameData?.Role is 3 or 4 ? 25f : 3f;
+        if (actualDistance - hitboxOffset > maxDistance)
+            _movementController.NavigateTo(EMovementType.Combat, null, [gameObject.Position], false, false,
+                maxDistance + hitboxOffset - 0.25f, true);
+    }
+
+    public void Dispose() => Stop();
+
+    enum StateCommandType : byte
+    {
+        Off,
+        Auto,
+        Manual,
+    }
+}
index 5f11dbf5f6fd4a83d8052df3b514a12f4da40221..658be365200ed9d846cf8c6c3d63bb4fd94b4569 100644 (file)
@@ -151,10 +151,7 @@ internal sealed class GameUiController : IDisposable
         if (string.IsNullOrEmpty(actualPrompt))
             actualPrompt = null;
 
-        List<string?> answers = new();
-        for (ushort i = 0; i < addonSelectIconString->AtkUnitBase.AtkValues[5].Int; i++)
-            answers.Add(addonSelectIconString->AtkUnitBase.AtkValues[i * 3 + 7].ReadAtkString());
-
+        var answers = GetChoices(addonSelectIconString);
         int? answer = HandleListChoice(actualPrompt, answers, checkAllSteps);
         if (answer != null)
         {
@@ -173,6 +170,14 @@ internal sealed class GameUiController : IDisposable
         }
     }
 
+    public static unsafe List<string?> GetChoices(AddonSelectIconString* addonSelectIconString)
+    {
+        List<string?> answers = new();
+        for (ushort i = 0; i < addonSelectIconString->AtkUnitBase.AtkValues[5].Int; i++)
+            answers.Add( addonSelectIconString->AtkValues[i * 3 + 7].ReadAtkString());
+
+        return answers;
+    }
 
     private int? HandleListChoice(string? actualPrompt, List<string?> answers, bool checkAllSteps)
     {
@@ -503,7 +508,7 @@ internal sealed class GameUiController : IDisposable
     /// <summary>
     /// Ensures characters like '-' are handled equally in both strings.
     /// </summary>
-    private static bool GameStringEquals(string? a, string? b)
+    public static bool GameStringEquals(string? a, string? b)
     {
         if (a == null)
             return b == null;
index de00083c51603c42b28c7f70e3a60e2c78a4a66a..37f139d16e100542b2c31d79daa09b23a09aa5b3 100644 (file)
@@ -17,6 +17,7 @@ internal sealed class QuestController
     private readonly IClientState _clientState;
     private readonly GameFunctions _gameFunctions;
     private readonly MovementController _movementController;
+    private readonly CombatController _combatController;
     private readonly ILogger<QuestController> _logger;
     private readonly QuestRegistry _questRegistry;
     private readonly IKeyState _keyState;
@@ -38,6 +39,7 @@ internal sealed class QuestController
         IClientState clientState,
         GameFunctions gameFunctions,
         MovementController movementController,
+        CombatController combatController,
         ILogger<QuestController> logger,
         QuestRegistry questRegistry,
         IKeyState keyState,
@@ -48,6 +50,7 @@ internal sealed class QuestController
         _clientState = clientState;
         _gameFunctions = gameFunctions;
         _movementController = movementController;
+        _combatController = combatController;
         _logger = logger;
         _questRegistry = questRegistry;
         _keyState = keyState;
@@ -106,6 +109,7 @@ internal sealed class QuestController
             {
                 Stop("ESC pressed");
                 _movementController.Stop();
+                _combatController.Stop();
             }
         }
 
@@ -322,6 +326,7 @@ internal sealed class QuestController
             _taskQueue.Clear();
 
         _yesAlreadyIpc.RestoreYesAlready();
+        _combatController.Stop();
     }
 
     public void Stop(string label, bool continueIfAutomatic = false)
@@ -473,6 +478,7 @@ internal sealed class QuestController
         }
 
         _movementController.Stop();
+        _combatController.Stop();
 
         var newTasks = _taskFactories
             .SelectMany(x =>
index c6137ffc082ce6e2c2e33b72aa0a0037bcceb3ef..b7450c534394cac766483859ab8cbdb4ea8ffe91 100644 (file)
@@ -57,15 +57,34 @@ internal sealed class QuestRegistry
                 new DirectoryInfo(Path.Combine(solutionDirectory.FullName, "QuestPaths"));
             if (pathProjectDirectory.Exists)
             {
-                LoadFromDirectory(new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "2.x - A Realm Reborn")));
-                LoadFromDirectory(new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "5.x - Shadowbringers")));
-                LoadFromDirectory(new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "6.x - Endwalker")));
-                LoadFromDirectory(new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "7.x - Dawntrail")));
+                try
+                {
+                    LoadFromDirectory(
+                        new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "2.x - A Realm Reborn")));
+                    LoadFromDirectory(
+                        new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "5.x - Shadowbringers")));
+                    LoadFromDirectory(
+                        new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "6.x - Endwalker")));
+                    LoadFromDirectory(
+                        new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "7.x - Dawntrail")));
+                }
+                catch (Exception e)
+                {
+                    _quests.Clear();
+                    _logger.LogError(e, "Failed to load quests from project directory");
+                }
             }
         }
 #endif
 
-        LoadFromDirectory(new DirectoryInfo(Path.Combine(_pluginInterface.ConfigDirectory.FullName, "Quests")));
+        try
+        {
+            LoadFromDirectory(new DirectoryInfo(Path.Combine(_pluginInterface.ConfigDirectory.FullName, "Quests")));
+        }
+        catch (Exception e)
+        {
+            _logger.LogError(e, "Failed to load all quests from user directory (some may have been successfully loaded)");
+        }
 
 #if !RELEASE
         foreach (var quest in _quests.Values)
@@ -83,14 +102,17 @@ internal sealed class QuestRegistry
     private void LoadQuestFromStream(string fileName, Stream stream)
     {
         _logger.LogTrace("Loading quest from '{FileName}'", fileName);
-        var questId = ExtractQuestIdFromName(fileName);
+        ushort? questId = ExtractQuestIdFromName(fileName);
+        if (questId == null)
+            return;
+
         Quest quest = new Quest
         {
-            QuestId = questId,
+            QuestId = questId.Value,
             Root = JsonSerializer.Deserialize<QuestRoot>(stream)!,
-            Info = _questData.GetQuestInfo(questId),
+            Info = _questData.GetQuestInfo(questId.Value),
         };
-        _quests[questId] = quest;
+        _quests[questId.Value] = quest;
     }
 
     private void LoadFromDirectory(DirectoryInfo directory)
@@ -119,11 +141,14 @@ internal sealed class QuestRegistry
             LoadFromDirectory(childDirectory);
     }
 
-    private static ushort ExtractQuestIdFromName(string resourceName)
+    private static ushort? ExtractQuestIdFromName(string resourceName)
     {
         string name = resourceName.Substring(0, resourceName.Length - ".json".Length);
         name = name.Substring(name.LastIndexOf('.') + 1);
 
+        if (!name.Contains('_', StringComparison.Ordinal))
+            return null;
+
         string[] parts = name.Split('_', 2);
         return ushort.Parse(parts[0], CultureInfo.InvariantCulture);
     }
index 5a868bc941e44437010687eb75977681650ef5b8..f4cac34786b2287c39d7f606a2adef64ea886b70 100644 (file)
@@ -1,7 +1,9 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using Microsoft.Extensions.DependencyInjection;
 using Questionable.Controller.Steps.Common;
+using Questionable.Controller.Utils;
 using Questionable.Model;
 using Questionable.Model.V1;
 
@@ -19,29 +21,105 @@ internal static class Combat
             ArgumentNullException.ThrowIfNull(step.EnemySpawnType);
 
             var unmount = serviceProvider.GetRequiredService<UnmountTask>();
-            if (step.EnemySpawnType == EEnemySpawnType.AfterInteraction)
+            switch (step.EnemySpawnType)
             {
-                ArgumentNullException.ThrowIfNull(step.DataId);
+                case EEnemySpawnType.AfterInteraction:
+                {
+                    ArgumentNullException.ThrowIfNull(step.DataId);
 
-                var task = serviceProvider.GetRequiredService<Interact.DoInteract>()
-                    .With(step.DataId.Value, true);
-                return [unmount, task];
+                    var interaction = serviceProvider.GetRequiredService<Interact.DoInteract>()
+                        .With(step.DataId.Value, true);
+                    return [unmount, interaction, CreateTask(quest, sequence, step)];
+                }
+
+                case EEnemySpawnType.AfterItemUse:
+                {
+                    ArgumentNullException.ThrowIfNull(step.DataId);
+                    ArgumentNullException.ThrowIfNull(step.ItemId);
+
+                    var useItem = serviceProvider.GetRequiredService<UseItem.UseOnObject>()
+                        .With(step.DataId.Value, step.ItemId.Value);
+                    return [unmount, useItem, CreateTask(quest, sequence, step)];
+                }
+
+                case EEnemySpawnType.AutoOnEnterArea:
+                    // automatically triggered when entering area, i.e. only unmount
+                    return [unmount, CreateTask(quest, sequence, step)];
+
+                case EEnemySpawnType.OverworldEnemies:
+                    // TODO currently not handled
+                    return [unmount];
+
+                default:
+                    throw new ArgumentOutOfRangeException(nameof(step), $"Unknown spawn type {step.EnemySpawnType}");
             }
-            else if (step.EnemySpawnType == EEnemySpawnType.AfterItemUse)
+        }
+
+        public ITask CreateTask(Quest quest, QuestSequence sequence, QuestStep step)
+        {
+            bool isLastStep = sequence.Steps.Last() == step;
+            return serviceProvider.GetRequiredService<HandleCombat>()
+                .With(quest.QuestId, isLastStep, step.KillEnemyDataIds, step.CompletionQuestVariablesFlags);
+        }
+    }
+
+    internal sealed class HandleCombat(CombatController combatController, GameFunctions gameFunctions) : ITask
+    {
+        private ushort _questId;
+        private bool _isLastStep;
+        private CombatController.CombatData _combatData = null!;
+        private IList<short?> _completionQuestVariableFlags = null!;
+
+        public ITask With(ushort questId, bool isLastStep, IList<uint> killEnemyDataIds,
+            IList<short?> completionQuestVariablesFlags)
+        {
+            _questId = questId;
+            _isLastStep = isLastStep;
+            _combatData = new CombatController.CombatData
+            {
+                KillEnemyDataIds = killEnemyDataIds.AsReadOnly(),
+            };
+            _completionQuestVariableFlags = completionQuestVariablesFlags;
+            return this;
+        }
+
+        public bool Start() => combatController.Start(_combatData);
+
+        public ETaskResult Update()
+        {
+            if (combatController.Update())
+                return ETaskResult.StillRunning;
+
+            // if our quest step has any completion flags, we need to check if they are set
+            if (QuestWorkUtils.HasCompletionFlags(_completionQuestVariableFlags))
             {
-                ArgumentNullException.ThrowIfNull(step.DataId);
-                ArgumentNullException.ThrowIfNull(step.ItemId);
+                var questWork = gameFunctions.GetQuestEx(_questId);
+                if (questWork == null)
+                    return ETaskResult.StillRunning;
 
-                var task = serviceProvider.GetRequiredService<UseItem.UseOnObject>()
-                    .With(step.DataId.Value, step.ItemId.Value);
-                return [unmount, task];
+                if (!QuestWorkUtils.MatchesQuestWork(_completionQuestVariableFlags, questWork.Value, false))
+                    return ETaskResult.StillRunning;
             }
+
+            // the last step, by definition, can only be progressed by the game recognizing we're in a new sequence,
+            // so this is an indefinite wait
+            if (_isLastStep)
+                return ETaskResult.StillRunning;
             else
-                // automatically triggered when entering area, i.e. only unmount
-                return [unmount];
+            {
+                combatController.Stop();
+                return ETaskResult.TaskComplete;
+            }
         }
 
-        public ITask? CreateTask(Quest quest, QuestSequence sequence, QuestStep step)
-            => throw new InvalidOperationException();
+        public override string ToString()
+        {
+            if (QuestWorkUtils.HasCompletionFlags(_completionQuestVariableFlags))
+                return "HandleCombat(wait: QW flags)";
+            else if (_isLastStep)
+                return "HandleCombat(wait: next sequence)";
+            else
+                return "HandleCombat(wait: not in combat)";
+        }
     }
 }
index 30feca43f9e5768d18b97e388c4086098ab90733..fbc6ff257bca79b84b8ac16777364603f5e9da00 100644 (file)
@@ -8,6 +8,7 @@ using FFXIVClientStructs.FFXIV.Client.Game.UI;
 using FFXIVClientStructs.FFXIV.Client.System.Framework;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
+using Questionable.Controller.Utils;
 using Questionable.Model;
 using Questionable.Model.V1;
 
@@ -112,7 +113,8 @@ internal static class SkipCondition
             }
 
             QuestWork? questWork = gameFunctions.GetQuestEx(QuestId);
-            if (questWork != null && Step.MatchesQuestVariables(questWork.Value, true))
+            if (questWork != null &&
+                QuestWorkUtils.MatchesQuestWork(Step.CompletionQuestVariablesFlags, questWork.Value, true))
             {
                 logger.LogInformation("Skipping step, as quest variables match");
                 return true;
index 061626e016c46317c284859670d157ba4566ae15..27feae232990613019f41adca34e546d1351ebcf 100644 (file)
@@ -9,6 +9,7 @@ using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions;
 using FFXIVClientStructs.FFXIV.Client.Game;
 using Microsoft.Extensions.DependencyInjection;
 using Questionable.Controller.Steps.Common;
+using Questionable.Controller.Utils;
 using Questionable.Data;
 using Questionable.Model;
 using Questionable.Model.V1;
@@ -17,7 +18,10 @@ namespace Questionable.Controller.Steps.Shared;
 
 internal static class WaitAtEnd
 {
-    internal sealed class Factory(IServiceProvider serviceProvider, IClientState clientState, ICondition condition,
+    internal sealed class Factory(
+        IServiceProvider serviceProvider,
+        IClientState clientState,
+        ICondition condition,
         TerritoryData territoryData)
         : ITaskFactory
     {
@@ -106,14 +110,16 @@ internal static class WaitAtEnd
                 case EInteractionType.AcceptQuest:
                     return
                     [
-                        serviceProvider.GetRequiredService<WaitQuestAccepted>().With(step.PickupQuestId ?? quest.QuestId),
+                        serviceProvider.GetRequiredService<WaitQuestAccepted>()
+                            .With(step.PickupQuestId ?? quest.QuestId),
                         serviceProvider.GetRequiredService<WaitDelay>()
                     ];
 
                 case EInteractionType.CompleteQuest:
                     return
                     [
-                        serviceProvider.GetRequiredService<WaitQuestCompleted>().With(step.TurnInQuestId ?? quest.QuestId),
+                        serviceProvider.GetRequiredService<WaitQuestCompleted>()
+                            .With(step.TurnInQuestId ?? quest.QuestId),
                         serviceProvider.GetRequiredService<WaitDelay>()
                     ];
 
@@ -167,7 +173,8 @@ internal static class WaitAtEnd
         public ETaskResult Update()
         {
             QuestWork? questWork = gameFunctions.GetQuestEx(Quest.QuestId);
-            return questWork != null && Step.MatchesQuestVariables(questWork.Value, false)
+            return questWork != null &&
+                   QuestWorkUtils.MatchesQuestWork(Step.CompletionQuestVariablesFlags, questWork.Value, false)
                 ? ETaskResult.TaskComplete
                 : ETaskResult.StillRunning;
         }
diff --git a/Questionable/Controller/Utils/QuestWorkUtils.cs b/Questionable/Controller/Utils/QuestWorkUtils.cs
new file mode 100644 (file)
index 0000000..03ddced
--- /dev/null
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions;
+
+namespace Questionable.Controller.Utils;
+
+internal static class QuestWorkUtils
+{
+    public static bool HasCompletionFlags(IList<short?> completionQuestVariablesFlags)
+    {
+        return completionQuestVariablesFlags.Count == 6 && completionQuestVariablesFlags.Any(x => x != null);
+    }
+
+    /// <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 static bool MatchesQuestWork(IList<short?> completionQuestVariablesFlags, QuestWork questWork, bool forSkip)
+    {
+        if (!HasCompletionFlags(completionQuestVariablesFlags))
+            return false;
+
+        for (int i = 0; i < 6; ++i)
+        {
+            short? check = completionQuestVariablesFlags[i];
+            if (check == null)
+                continue;
+
+            byte actualValue = questWork.Variables[i];
+            byte checkByte = check > 0 ? (byte)check : (byte)-check;
+            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 1d309750c3f2ba096c6df8472caf6727abce22ea..bbaab3d0effd59c8ddae9dd6df931b85a1be292d 100644 (file)
@@ -5,6 +5,9 @@ using System.Linq;
 using Dalamud.Game.ClientState.Objects;
 using Dalamud.Game.Text;
 using Dalamud.Plugin.Services;
+using FFXIVClientStructs.FFXIV.Client.UI;
+using LLib.GameUI;
+using Questionable.Controller;
 using Questionable.Model;
 using Quest = Lumina.Excel.GeneratedSheets.Quest;
 
@@ -14,13 +17,15 @@ internal sealed class QuestData
 {
     private readonly ITargetManager _targetManager;
     private readonly IChatGui _chatGui;
+    private readonly IGameGui _gameGui;
 
     private readonly ImmutableDictionary<ushort, QuestInfo> _quests;
 
-    public QuestData(IDataManager dataManager, ITargetManager targetManager, IChatGui chatGui)
+    public QuestData(IDataManager dataManager, ITargetManager targetManager, IChatGui chatGui, IGameGui gameGui)
     {
         _targetManager = targetManager;
         _chatGui = chatGui;
+        _gameGui = gameGui;
 
         _quests = dataManager.GetExcelSheet<Quest>()!
             .Where(x => x.RowId > 0)
@@ -43,7 +48,7 @@ internal sealed class QuestData
 
     public bool IsIssuerOfAnyQuest(uint targetId) => _quests.Values.Any(x => x.IssuerDataId == targetId);
 
-    public void ShowQuestsIssuedByTarget()
+    public unsafe void ShowQuestsIssuedByTarget()
     {
         var targetId = _targetManager.Target?.DataId;
         if (targetId == null)
@@ -53,9 +58,20 @@ internal sealed class QuestData
         }
 
         List<QuestInfo> quests = GetAllByIssuerDataId(targetId.Value);
-        _chatGui.Print($"{quests.Count} quest(s) issued by target {_targetManager.Target?.Name}:");
+
+        if (_gameGui.TryGetAddonByName<AddonSelectIconString>("SelectIconString", out var addonSelectIconString))
+        {
+            var answers = GameUiController.GetChoices(addonSelectIconString);
+            quests = quests.Where(x => answers.Any(y => GameUiController.GameStringEquals(x.Name, y))).ToList();
+
+            _chatGui.Print($"{quests.Count} quest(s) currently offered by target {_targetManager.Target?.Name}:");
+        }
+        else
+        {
+            _chatGui.Print($"{quests.Count} quest(s) issued by target {_targetManager.Target?.Name}:");
+        }
 
         foreach (QuestInfo quest in quests)
-            _chatGui.Print($"  {quest.QuestId}_{quest.SimplifiedName}");
+                _chatGui.Print($"  {quest.QuestId}_{quest.SimplifiedName}");
     }
 }
index c02815f880c83b0b6464ac71f55b55c14ec9ecd5..bab7f48268927174c0284dc0636ef708e1911f34 100644 (file)
@@ -7,4 +7,5 @@ public enum EMovementType
     DebugWindow,
     Shortcut,
     Landing,
+    Combat,
 }
diff --git a/Questionable/Model/V1/QuestStepExtensions.cs b/Questionable/Model/V1/QuestStepExtensions.cs
deleted file mode 100644 (file)
index dedf2eb..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-using System;
-using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions;
-
-namespace Questionable.Model.V1;
-
-internal static class QuestStepExtensions
-{
-    /// <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 static unsafe bool MatchesQuestVariables(this QuestStep step, QuestWork questWork, bool forSkip)
-    {
-        if (step.CompletionQuestVariablesFlags.Count != 6)
-            return false;
-
-        for (int i = 0; i < 6; ++i)
-        {
-            short? check = step.CompletionQuestVariablesFlags[i];
-            if (check == null)
-                continue;
-
-            byte actualValue = questWork.Variables[i];
-            byte checkByte = check > 0 ? (byte)check : (byte)-check;
-            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 a2600c9207b5b85a6ca0913dac9a15ed188bdc3f..495137661f7b6f36b43298ab73d01b3a4320f584 100644 (file)
@@ -9,6 +9,7 @@ using Dalamud.Plugin.Services;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
 using Questionable.Controller;
+using Questionable.Controller.CombatModules;
 using Questionable.Controller.NavigationOverrides;
 using Questionable.Controller.Steps;
 using Questionable.Controller.Steps.Shared;
@@ -92,7 +93,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin
         serviceCollection.AddTaskWithFactory<AetherCurrent.Factory, AetherCurrent.DoAttune>();
         serviceCollection.AddTaskWithFactory<AethernetShard.Factory, AethernetShard.DoAttune>();
         serviceCollection.AddTaskWithFactory<Aetheryte.Factory, Aetheryte.DoAttune>();
-        serviceCollection.AddSingleton<ITaskFactory, Combat.Factory>();
+        serviceCollection.AddTaskWithFactory<Combat.Factory, Combat.HandleCombat>();
         serviceCollection.AddTaskWithFactory<Duty.Factory, Duty.OpenDutyFinder>();
         serviceCollection.AddTaskWithFactory<Emote.Factory, Emote.UseOnObject, Emote.Use>();
         serviceCollection.AddTaskWithFactory<Action.Factory, Action.UseOnObject>();
@@ -120,6 +121,9 @@ public sealed class QuestionablePlugin : IDalamudPlugin
         serviceCollection.AddSingleton<QuestController>();
         serviceCollection.AddSingleton<GameUiController>();
         serviceCollection.AddSingleton<NavigationShortcutController>();
+        serviceCollection.AddSingleton<CombatController>();
+
+        serviceCollection.AddSingleton<ICombatModule, RotationSolverRebornModule>();
 
         serviceCollection.AddSingleton<QuestWindow>();
         serviceCollection.AddSingleton<ConfigWindow>();
index 34b6c775634b9864451ba997c2b0f3a6f0fcd80e..583cbf654a32df4d9ee509394d443a25378af395 100644 (file)
@@ -12,7 +12,6 @@ using Dalamud.Interface.Components;
 using Dalamud.Interface.Utility.Raii;
 using Dalamud.Plugin;
 using Dalamud.Plugin.Services;
-using FFXIVClientStructs.FFXIV.Client.Game;
 using FFXIVClientStructs.FFXIV.Client.Game.Control;
 using FFXIVClientStructs.FFXIV.Client.Game.Object;
 using FFXIVClientStructs.FFXIV.Client.UI.Agent;
@@ -40,6 +39,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
     private readonly IFramework _framework;
     private readonly ITargetManager _targetManager;
     private readonly GameUiController _gameUiController;
+    private readonly CombatController _combatController;
     private readonly Configuration _configuration;
     private readonly NavmeshIpc _navmeshIpc;
     private readonly QuestRegistry _questRegistry;
@@ -57,6 +57,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
         IFramework framework,
         ITargetManager targetManager,
         GameUiController gameUiController,
+        CombatController combatController,
         Configuration configuration,
         NavmeshIpc navmeshIpc,
         QuestRegistry questRegistry,
@@ -75,6 +76,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
         _framework = framework;
         _targetManager = targetManager;
         _gameUiController = gameUiController;
+        _combatController = combatController;
         _configuration = configuration;
         _navmeshIpc = navmeshIpc;
         _questRegistry = questRegistry;
@@ -186,8 +188,17 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
                     ImGui.TextUnformatted("(Not accepted)");
             }
 
-            ImGui.TextUnformatted(_questController.DebugState ?? "--");
             ImGui.EndDisabled();
+
+            if (_combatController.IsRunning)
+                ImGui.TextColored(ImGuiColors.DalamudOrange, "In Combat");
+            else
+            {
+                ImGui.BeginDisabled();
+                ImGui.TextUnformatted(_questController.DebugState ?? "--");
+                ImGui.EndDisabled();
+            }
+
             ImGui.TextUnformatted(_questController.Comment ?? "--");
 
             //var nextStep = _questController.GetNextStep();
@@ -523,7 +534,7 @@ internal sealed class QuestWindow : LWindow, IPersistableWindowConfig
         {
             _movementController.Destination = null;
             _chatFunctions.ExecuteCommand(
-                $"/vnav {(_gameFunctions.IsFlyingUnlockedInCurrentZone() ? "flyflag" : "moveflag")}");
+                $"/vnav {(_condition[ConditionFlag.Mounted] && _gameFunctions.IsFlyingUnlockedInCurrentZone() ? "flyflag" : "moveflag")}");
         }
 
         ImGui.EndDisabled();