Allow for more complex gathering (preparation) steps; add firmament aetheryte
authorLiza Carvelli <liza@carvel.li>
Thu, 15 Aug 2024 23:21:15 +0000 (01:21 +0200)
committerLiza Carvelli <liza@carvel.li>
Thu, 15 Aug 2024 23:21:15 +0000 (01:21 +0200)
100 files changed:
GatheringPathRenderer/EditorCommands.cs
GatheringPathRenderer/RendererPlugin.cs
GatheringPaths/2.x - A Realm Reborn/Central Thanalan/157_Spineless Basin_MIN.json
GatheringPaths/2.x - A Realm Reborn/Western Thanalan/154_Hammerlea_MIN.json
GatheringPaths/3.x - Heavensward/Coerthas Western Highlands/300_Twinpools_BTN.json
GatheringPaths/3.x - Heavensward/Coerthas Western Highlands/351_Red Rim_MIN.json
GatheringPaths/3.x - Heavensward/Coerthas Western Highlands/551_The Bed of Bones_MIN.json
GatheringPaths/3.x - Heavensward/Coerthas Western Highlands/552_Gorgagne Holding_BTN.json
GatheringPaths/3.x - Heavensward/The Churning Mists/355_Landlord Colony_MIN.json
GatheringPaths/3.x - Heavensward/The Churning Mists/359_Four Arms_BTN.json
GatheringPaths/3.x - Heavensward/The Churning Mists/553_Landlord Colony_MIN.json
GatheringPaths/3.x - Heavensward/The Churning Mists/554_Ohl Tahn_BTN.json
GatheringPaths/3.x - Heavensward/The Dravanian Forelands/352_Avalonia Fallen_MIN.json
GatheringPaths/3.x - Heavensward/The Dravanian Forelands/358_Avalonia Fallen_BTN.json
GatheringPaths/3.x - Heavensward/The Dravanian Hinterlands/353_The Makers' Quarter_MIN.json
GatheringPaths/3.x - Heavensward/The Dravanian Hinterlands/361_The Answering Quarter_BTN.json
GatheringPaths/3.x - Heavensward/The Sea of Clouds/354_Voor Sian Siran_MIN.json
GatheringPaths/3.x - Heavensward/The Sea of Clouds/360_The Blue Window_BTN.json
GatheringPaths/4.x - Stormblood/The Azim Steppe/495_Onsal Hakair_MIN.json
GatheringPaths/4.x - Stormblood/The Azim Steppe/519_Nhaama's Retreat_BTN.json
GatheringPaths/4.x - Stormblood/The Azim Steppe/813_Onsal Hakair_BTN.json
GatheringPaths/4.x - Stormblood/The Fringes/485_East End_MIN.json
GatheringPaths/4.x - Stormblood/The Fringes/486_The Striped Hills_MIN.json
GatheringPaths/4.x - Stormblood/The Fringes/505_East End_BTN.json
GatheringPaths/4.x - Stormblood/The Fringes/509_Dimwold_BTN.json
GatheringPaths/4.x - Stormblood/The Fringes/513_Dimwold_BTN.json
GatheringPaths/4.x - Stormblood/The Lochs/493_The High Bank_MIN.json
GatheringPaths/4.x - Stormblood/The Lochs/514_Abalathia's Skull_BTN.json
GatheringPaths/4.x - Stormblood/The Lochs/526_Abalathia's Skull_BTN.json
GatheringPaths/4.x - Stormblood/The Peaks/489_Rustrock_MIN.json
GatheringPaths/4.x - Stormblood/The Peaks/512_The Last Forest_BTN.json
GatheringPaths/4.x - Stormblood/The Peaks/531_Sleeping Stones_MIN.json
GatheringPaths/4.x - Stormblood/The Peaks/532_The Last Forest_BTN.json
GatheringPaths/4.x - Stormblood/The Ruby Sea/487_Hells' Lid_MIN.json
GatheringPaths/4.x - Stormblood/The Ruby Sea/507_Onokoro_BTN.json
GatheringPaths/4.x - Stormblood/The Ruby Sea/510_East Othard Coastline_BTN.json
GatheringPaths/4.x - Stormblood/The Ruby Sea/511_Rasen Kaikyo_BTN.json
GatheringPaths/4.x - Stormblood/The Ruby Sea/529_Rasen Kaikyo_BTN.json
GatheringPaths/4.x - Stormblood/The Ruby Sea/533_The Turquoise Trench_MIN.json
GatheringPaths/4.x - Stormblood/The Ruby Sea/534_The Isle of Bekko_BTN.json
GatheringPaths/4.x - Stormblood/Yanxia/488_The Gensui Chain_MIN.json
GatheringPaths/4.x - Stormblood/Yanxia/491_Unseen Spirits Laughing_MIN.json
GatheringPaths/4.x - Stormblood/Yanxia/508_The Heron's Flight_BTN.json
GatheringPaths/4.x - Stormblood/Yanxia/731_Yuzuka Manor_BTN.json
GatheringPaths/5.x - Shadowbringers/Kholusia/649_Stonegazer_BTN.json
GatheringPaths/5.x - Shadowbringers/Kholusia/650_Shadow Fault_MIN.json
GatheringPaths/5.x - Shadowbringers/The Rak'tika Greatwood/688__MIN.json
GatheringPaths/5.x - Shadowbringers/The Rak'tika Greatwood/689__MIN.json
GatheringPaths/6.x - Endwalker/Elpis/823_The Hungering Gardens_MIN.json
GatheringPaths/6.x - Endwalker/Elpis/846_Anagnorisis_BTN.json
GatheringPaths/6.x - Endwalker/Elysion/316__MIN.json
GatheringPaths/6.x - Endwalker/Elysion/317__MIN.json
GatheringPaths/6.x - Endwalker/Elysion/322__MIN.json
GatheringPaths/6.x - Endwalker/Elysion/336__MIN.json
GatheringPaths/6.x - Endwalker/Elysion/393__BTN.json
GatheringPaths/6.x - Endwalker/Elysion/394__BTN.json
GatheringPaths/6.x - Endwalker/Elysion/398__BTN.json
GatheringPaths/6.x - Endwalker/Elysion/399__BTN.json
GatheringPaths/6.x - Endwalker/Garlemald/822_Monitoring Station G_MIN.json
GatheringPaths/6.x - Endwalker/Garlemald/842_Camp Broken Glass_BTN.json
GatheringPaths/6.x - Endwalker/Labyrinthos/816_Lower Acrinthos_MIN.json
GatheringPaths/6.x - Endwalker/Labyrinthos/838_Meryall Agronomics_BTN.json
GatheringPaths/6.x - Endwalker/Mare Lamentorum/821_The Crushing Brand_MIN.json
GatheringPaths/6.x - Endwalker/Mare Lamentorum/902_Heimdall's Last Sight_BTN.json
GatheringPaths/6.x - Endwalker/Thavnair/820_The Hamsa Hatchery_MIN.json
GatheringPaths/6.x - Endwalker/Thavnair/840_Giantsgall Grounds_BTN.json
GatheringPaths/7.x - Dawntrail/Kozama'uka/946__BTN.json
GatheringPaths/7.x - Dawntrail/Kozama'uka/976_Uyuyub'_MIN.json
GatheringPaths/7.x - Dawntrail/Kozama'uka/986_Uyuyub'_BTN.json
GatheringPaths/7.x - Dawntrail/Shaaloani/978_Pyariyoanaan Plain_MIN.json
GatheringPaths/7.x - Dawntrail/Shaaloani/999_Yawtanane Grasslands_BTN.json
GatheringPaths/7.x - Dawntrail/Urqopacha/961__MIN.json
GatheringPaths/7.x - Dawntrail/Urqopacha/974_Chabameki_MIN.json
GatheringPaths/7.x - Dawntrail/Urqopacha/975_Sorrow_MIN.json
GatheringPaths/7.x - Dawntrail/Urqopacha/992_Chabameki_BTN.json
GatheringPaths/7.x - Dawntrail/Urqopacha/993_Chabayuqeq_MIN.json
GatheringPaths/7.x - Dawntrail/Urqopacha/994_Larh Tortoh_BTN.json
GatheringPaths/7.x - Dawntrail/Yak T'el/1000_The Xobr'it Cinderfield_BTN.json
GatheringPaths/7.x - Dawntrail/Yak T'el/955__BTN.json
GatheringPaths/7.x - Dawntrail/Yak T'el/970__MIN.json
GatheringPaths/7.x - Dawntrail/Yak T'el/979_The Ut'ohmu Horizon_MIN.json
GatheringPaths/gatheringlocation-v1.json
QuestPathGenerator/GatheringSourceGenerator.cs
QuestPaths/5.x - Shadowbringers/Custom Deliveries/Charlemend/S7_Charlemend.json
QuestPaths/5.x - Shadowbringers/Custom Deliveries/Ehll Tou/S6_Ehll Tou.json
QuestPaths/quest-v1.json
Questionable.Model/Common/EAetheryteLocation.cs
Questionable.Model/Gathering/GatheringRoot.cs
Questionable.Model/Questing/Converter/AethernetShardConverter.cs
Questionable.Model/common-schema.json
Questionable/Controller/GameUiController.cs
Questionable/Controller/GatheringController.cs
Questionable/Controller/QuestController.cs
Questionable/Controller/Steps/Shared/AethernetShortcut.cs
Questionable/Controller/Steps/Shared/GatheringRequiredItems.cs
Questionable/Controller/Steps/TaskCreator.cs [new file with mode: 0644]
Questionable/Data/AetheryteData.cs
Questionable/Functions/AetheryteFunctions.cs
Questionable/QuestionablePlugin.cs
Questionable/Validation/Validators/AethernetShortcutValidator.cs

index 75c50db60ccdd7e6302040a8367739e59a1c3045..2e9edad5d0cd1273ec54e7b24817154ec00e424d 100644 (file)
@@ -15,6 +15,7 @@ using Dalamud.Plugin.Services;
 using Lumina.Excel.GeneratedSheets;
 using Questionable.Model;
 using Questionable.Model.Gathering;
+using Questionable.Model.Questing;
 
 namespace GatheringPathRenderer;
 
@@ -186,7 +187,14 @@ internal sealed class EditorCommands : IDisposable
         var root = new GatheringRoot
         {
             Author = [_configuration.AuthorName],
-            TerritoryId = _clientState.TerritoryType,
+            Steps =
+            [
+                new QuestStep
+                {
+                    TerritoryId = _clientState.TerritoryType,
+                    InteractionType = EInteractionType.None,
+                }
+            ],
             Groups =
             [
                 new GatheringNodeGroup
index 50f9e4a749a5d6b171582fa2d423451c35f7c753..95edf94c54504c4364e651bedf360f4a5e6f1701 100644 (file)
@@ -146,7 +146,7 @@ public sealed class RendererPlugin : IDalamudPlugin
     }
 
     internal IEnumerable<GatheringLocationContext> GetLocationsInTerritory(ushort territoryId)
-        => _gatheringLocations.Where(x => x.Root.TerritoryId == territoryId);
+        => _gatheringLocations.Where(x => x.Root.Steps.LastOrDefault()?.TerritoryId == territoryId);
 
     internal void Save(FileInfo targetFile, GatheringRoot root)
     {
index 66426fb7953b12500a90608511baab2a1beb31b1..1967ad969244e13971da606ef2638c3d4749d9c3 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 141,
-  "AetheryteShortcut": "Central Thanalan - Black Brush Station",
+  "Steps": [
+    {
+      "TerritoryId": 141,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Central Thanalan - Black Brush Station"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 4a13bd8e176e8d21f1d806870071fc69f67e7c07..8c7bb8d732d0f683fdd28b007b307c588357aa81 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 140,
-  "AetheryteShortcut": "Western Thanalan - Horizon",
+  "Steps": [
+    {
+      "TerritoryId": 140,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Western Thanalan - Horizon"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 2e4c56c7a72f25d347519dc0c3211929bf3d6308..77edce8207f3a94cb4364cd4c1db17995b328eb2 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 397,
-  "AetheryteShortcut": "Coerthas Western Highlands - Falcon's Nest",
+  "Steps": [
+    {
+      "TerritoryId": 397,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Coerthas Western Highlands - Falcon's Nest"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index e61ee374530f6cbeb6df425d4da7b15cec1264cb..0b88a020366651e798b7102d1c4f3c805d2ea88b 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 397,
-  "AetheryteShortcut": "Coerthas Western Highlands - Falcon's Nest",
+  "Steps": [
+    {
+      "TerritoryId": 397,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Coerthas Western Highlands - Falcon's Nest"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
       ]
     }
   ]
-}
\ No newline at end of file
+}
index 2b7fbfb32f16a1609636338cac814aae8f413f31..1af05fc6be1b7178981746888045046649105e32 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 397,
-  "AetheryteShortcut": "Coerthas Western Highlands - Falcon's Nest",
+  "Steps": [
+    {
+      "TerritoryId": 397,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Coerthas Western Highlands - Falcon's Nest"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index ed1967beaf31906be5a225b25d433e1589a2f3fc..ba3986320ad300242d8f102b26f3a9be435a3f9d 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 397,
-  "AetheryteShortcut": "Coerthas Western Highlands - Falcon's Nest",
+  "Steps": [
+    {
+      "TerritoryId": 397,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Coerthas Western Highlands - Falcon's Nest"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 56f820ad48abb2c0a50540786f970018f7dc1672..f1e8dba9b575b847288a3309480539511e9de886 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 400,
-  "AetheryteShortcut": "The Churning Mists - Moghome",
+  "Steps": [
+    {
+      "TerritoryId": 400,
+      "InteractionType": "None",
+      "AetheryteShortcut": "The Churning Mists - Moghome"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index c4a5d4be40ccf80cf02070d3f19dd2cb7561b318..56368de85cc07545278a7a1b27c67c133699be6b 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 400,
-  "AetheryteShortcut": "The Churning Mists - Zenith",
+  "Steps": [
+    {
+      "TerritoryId": 400,
+      "InteractionType": "None",
+      "AetheryteShortcut": "The Churning Mists - Zenith"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index e6743d6203ed3b340374bccaa148f37ec00d2a4d..9b97967211749bb02a6d4647875686f812aeccad 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 400,
-  "AetheryteShortcut": "The Churning Mists - Moghome",
+  "Steps": [
+    {
+      "TerritoryId": 400,
+      "InteractionType": "None",
+      "AetheryteShortcut": "The Churning Mists - Moghome"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 3792592d8d3fa914a76eb36a48a3d4de2146a367..6a89c161869849e1b7e1a07c2bfeb5a93f574586 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 400,
-  "AetheryteShortcut": "The Churning Mists - Zenith",
+  "Steps": [
+    {
+      "TerritoryId": 400,
+      "InteractionType": "None",
+      "AetheryteShortcut": "The Churning Mists - Zenith"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 0b1e53ce89a9011889e70559c69319503187c75d..20bfeb5a5d87c60e767eba6bcfda7fefba567904 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 398,
-  "AetheryteShortcut": "The Dravanian Forelands - Anyx Trine",
+  "Steps": [
+    {
+      "TerritoryId": 398,
+      "InteractionType": "None",
+      "AetheryteShortcut": "The Dravanian Forelands - Anyx Trine"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index c672d2e4a9560fdd2c951ad388cb0588747db80a..9bb8f47251db8c1a91e7c4053f1771a7533c4638 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 398,
-  "AetheryteShortcut": "The Dravanian Forelands - Anyx Trine",
+  "Steps": [
+    {
+      "TerritoryId": 398,
+      "InteractionType": "None",
+      "AetheryteShortcut": "The Dravanian Forelands - Anyx Trine"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 3a1d347713e957fd1305acf344ff9052b3c38c82..d462b45309d9a1deb0c2e1109968601430e59810 100644 (file)
@@ -1,11 +1,16 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 399,
-  "AetheryteShortcut": "Idyllshire",
-  "AethernetShortcut": [
-    "[Idyllshire] Aetheryte Plaza",
-    "[Idyllshire] Epilogue Gate (Eastern Hinterlands)"
+  "Steps": [
+    {
+      "TerritoryId": 399,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Idyllshire",
+      "AethernetShortcut": [
+        "[Idyllshire] Aetheryte Plaza",
+        "[Idyllshire] Epilogue Gate (Eastern Hinterlands)"
+      ]
+    }
   ],
   "Groups": [
     {
index 857dd7052e3238317d41325709e9938638132b7e..64e5cb8d4beb58be459968c62bf383963ebfd04d 100644 (file)
@@ -1,11 +1,16 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 399,
-  "AetheryteShortcut": "Idyllshire",
-  "AethernetShortcut": [
-    "[Idyllshire] Aetheryte Plaza",
-    "[Idyllshire] Prologue Gate (Western Hinterlands)"
+  "Steps": [
+    {
+      "TerritoryId": 399,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Idyllshire",
+      "AethernetShortcut": [
+        "[Idyllshire] Aetheryte Plaza",
+        "[Idyllshire] Prologue Gate (Western Hinterlands)"
+      ]
+    }
   ],
   "Groups": [
     {
index e8040da62815d64443690cabd5d0b837d9317c5d..63e23e8e0d343a70576b7dd8394cfc617e360ad1 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 401,
-  "AetheryteShortcut": "The Sea of Clouds - Camp Cloudtop",
+  "Steps": [
+    {
+      "TerritoryId": 401,
+      "InteractionType": "None",
+      "AetheryteShortcut": "The Sea of Clouds - Camp Cloudtop"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index b15a0425e8795903eaae4bedfdb44afcc13e4219..11239918a6c5747f4b417cbfc1995f6916b5b37b 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 401,
-  "AetheryteShortcut": "The Sea of Clouds - Ok' Zundu",
+  "Steps": [
+    {
+      "TerritoryId": 401,
+      "InteractionType": "None",
+      "AetheryteShortcut": "The Sea of Clouds - Ok' Zundu"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 3c8c4282e86586aa41a489439f31733a2732f7c3..fb4823a68000c1d04917faea1e72a1be35cff009 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 622,
-  "AetheryteShortcut": "Azim Steppe - Dawn Throne",
+  "Steps": [
+    {
+      "TerritoryId": 622,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Azim Steppe - Dawn Throne"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index bbefc52d9579ebc9e33da48aeda7ec905522e936..d3c96970c50fe1a4f9b5359d080f9c5032078c85 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 622,
-  "AetheryteShortcut": "Azim Steppe - Dawn Throne",
+  "Steps": [
+    {
+      "TerritoryId": 622,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Azim Steppe - Dawn Throne"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 2bcf9909e0f30296de7a937db72a87c8d61f5745..89ce42a8802a01ecc4ac7678dfa9b1407d48f99a 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 622,
-  "AetheryteShortcut": "Azim Steppe - Dawn Throne",
+  "Steps": [
+    {
+      "TerritoryId": 622,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Azim Steppe - Dawn Throne"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 27eb04f1330f11cb1f2165d75e2520f9e6fc393f..d5471d643ae0ff2fe4e13a979699cebdf3408491 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 612,
-  "AetheryteShortcut": "Fringes - Castrum Oriens",
+  "Steps": [
+    {
+      "TerritoryId": 612,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Fringes - Castrum Oriens"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index eba926f8a7463d4548d51a9817fa215469974139..d93f48ade9d7ba46bd972ae7dbb1508357bab850 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 612,
-  "AetheryteShortcut": "Fringes - Castrum Oriens",
+  "Steps": [
+    {
+      "TerritoryId": 612,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Fringes - Castrum Oriens"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index a9d9ff5d07e2e86080937a019c762c061d260eaa..3d3a89d0aef1c6cc3973dfd728c04ab56659f321 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 612,
-  "AetheryteShortcut": "Fringes - Castrum Oriens",
+  "Steps": [
+    {
+      "TerritoryId": 612,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Fringes - Castrum Oriens"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index bc74413e5080a6893f6045f37595d414ad9e3660..46149bb4df6bd0a12e473f6997866bac094327d6 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 612,
-  "AetheryteShortcut": "Fringes - Castrum Oriens",
+  "Steps": [
+    {
+      "TerritoryId": 612,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Fringes - Castrum Oriens"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 9386a44c98bb7e938685f7fba19f52101fce96a0..927179cd432171f105de332ab24f00745750a170 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 612,
-  "AetheryteShortcut": "Fringes - Castrum Oriens",
+  "Steps": [
+    {
+      "TerritoryId": 612,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Fringes - Castrum Oriens"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 4d75f62ed4b829e3d830afd0eea324ebd4283be4..69b00338aa5aa4bc611c82914b153c0603d39813 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 621,
-  "AetheryteShortcut": "Lochs - Porta Praetoria",
+  "Steps": [
+    {
+      "TerritoryId": 621,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Lochs - Porta Praetoria"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 46299430c74c936b8db7ac5265861fdc1796c6ed..ebdcaf1feea7e446e66421a7708b2d1765161866 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 621,
-  "AetheryteShortcut": "Lochs - Ala Mhigan Quarter",
+  "Steps": [
+    {
+      "TerritoryId": 621,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Lochs - Ala Mhigan Quarter"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index f16197d383cdc76bd14694ee61ddca72472ffcc2..3881eff7b7ff0ca41516b036a144414d0deaba89 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 621,
-  "AetheryteShortcut": "Lochs - Porta Praetoria",
+  "Steps": [
+    {
+      "TerritoryId": 621,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Lochs - Porta Praetoria"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index c2172a4d42e3cd25e6c275559123a94afab920a1..6c0df9a8ad07ab75c3325c02dbd2dff70d032c49 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 620,
-  "AetheryteShortcut": "Peaks - Ala Gannha",
+  "Steps": [
+    {
+      "TerritoryId": 620,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Peaks - Ala Gannha"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 95642b7618a63c35b0dceb207ee96649f7c91e49..c73c08d94b69b16bc1e0a536c16e293407d681aa 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 620,
-  "AetheryteShortcut": "Peaks - Ala Gannha",
+  "Steps": [
+    {
+      "TerritoryId": 620,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Peaks - Ala Gannha"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index d9e04e5e3088e39d4b40f1eaf96d24fe9ea5c67d..871aec20026387f1eac60f38e5ee6bf0c86044dc 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 620,
-  "AetheryteShortcut": "Peaks - Ala Gannha",
+  "Steps": [
+    {
+      "TerritoryId": 620,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Peaks - Ala Gannha"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
       ]
     }
   ]
-}
\ No newline at end of file
+}
index 35f11b14734f8aea5e3a1195cac460fbf960422c..3ba97a5d3393525ee881a06b5bd5b081daee6035 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 620,
-  "AetheryteShortcut": "Peaks - Ala Gannha",
+  "Steps": [
+    {
+      "TerritoryId": 620,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Peaks - Ala Gannha"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 9649c3b79a1cb9ca06b73f44cc9972b44672d9bf..b4ef3ded73e906f92161683ae7ed2b550abdb67e 100644 (file)
@@ -1,11 +1,16 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 613,
-  "AetheryteShortcut": "Kugane",
-  "AethernetShortcut": [
-    "[Kugane] Aetheryte Plaza",
-    "[Kugane] The Ruby Price"
+  "Steps": [
+    {
+      "TerritoryId": 613,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Kugane",
+      "AethernetShortcut": [
+        "[Kugane] Aetheryte Plaza",
+        "[Kugane] The Ruby Price"
+      ]
+    }
   ],
   "Groups": [
     {
index 9ba00a291d77160ce9b041ae8b258a17433a0201..604e7d03988840c3545a7dd319fcb532d7820e88 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 613,
-  "AetheryteShortcut": "Ruby Sea - Onokoro",
+  "Steps": [
+    {
+      "TerritoryId": 613,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Ruby Sea - Onokoro"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index f3621a43dffb352b7d83f72b4f825240aa6593bd..653a07139121fa9cf7bd3c6ae876761ff8468e9c 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 613,
-  "AetheryteShortcut": "Ruby Sea - Onokoro",
+  "Steps": [
+    {
+      "TerritoryId": 613,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Ruby Sea - Onokoro"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 0972e6668d8aab6b1cf15626183775ef2be0b6ce..1b7516f4c2336b7a3678fb91911477b3d32bc2ae 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 613,
-  "AetheryteShortcut": "Ruby Sea - Tamamizu",
+  "Steps": [
+    {
+      "TerritoryId": 613,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Ruby Sea - Tamamizu"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 71f30298f411cc4e0907d3e92c49587a942fd836..e65b26a50af0edaa6e29b4f5ed0c011dd790b7a8 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 613,
-  "AetheryteShortcut": "Ruby Sea - Onokoro",
+  "Steps": [
+    {
+      "TerritoryId": 613,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Ruby Sea - Onokoro"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index f886de4f87da682eee3d05ac8423832f6465e0b7..c3dd904aaab61813fd48ab57bffb408cf3478b7f 100644 (file)
@@ -1,11 +1,16 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 613,
-  "AetheryteShortcut": "Kugane",
-  "AethernetShortcut": [
-    "[Kugane] Aetheryte Plaza",
-    "[Kugane] The Ruby Price"
+  "Steps": [
+    {
+      "TerritoryId": 613,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Kugane",
+      "AethernetShortcut": [
+        "[Kugane] Aetheryte Plaza",
+        "[Kugane] The Ruby Price"
+      ]
+    }
   ],
   "FlyBetweenNodes": true,
   "Groups": [
       ]
     }
   ]
-}
\ No newline at end of file
+}
index 9844919ba66562e71aa24b7ec1ebc0d62d847f22..ec7a85a7d399756bdafc84b73ba8a5b94f8a0f4e 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 613,
-  "AetheryteShortcut": "Ruby Sea - Tamamizu",
+  "Steps": [
+    {
+      "TerritoryId": 613,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Ruby Sea - Tamamizu"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 6e63e7c7ad32f780efdefde8ad253f5599f9ddd9..ffc19238a93b27953c53d23487612f7861a11b9e 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 614,
-  "AetheryteShortcut": "Yanxia - Namai",
+  "Steps": [
+    {
+      "TerritoryId": 614,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Yanxia - Namai"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index a832d5697987f64fa02d3de06435f315cb00aa51..bdfded1ed40e734147894cffb4a2307b8b7a8307 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 614,
-  "AetheryteShortcut": "Yanxia - Namai",
+  "Steps": [
+    {
+      "TerritoryId": 614,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Yanxia - Namai"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 6c13febf34b426a2986f4e2feceae3c101ee5f70..e08bd10df3e9d05f9da535e15af59828c96b768b 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 614,
-  "AetheryteShortcut": "Yanxia - Namai",
+  "Steps": [
+    {
+      "TerritoryId": 614,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Yanxia - Namai"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 23fae294ad46e3686fe39fb613bcfa45f7a3b206..c7d8352ace08cb5ca41d2a2a6d30b6b6b51c2a5e 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 614,
-  "AetheryteShortcut": "Yanxia - Namai",
+  "Steps": [
+    {
+      "TerritoryId": 614,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Yanxia - Namai"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 677ec3746453aa3de8f5ed65e93bc3d61b375cbf..54ae87dd9ea4fa4bfaf1638a0ecf6c4bea131d85 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 814,
-  "AetheryteShortcut": "Kholusia - Wright",
+  "Steps": [
+    {
+      "TerritoryId": 814,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Kholusia - Wright"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 83fc6092d6b6bf0f93b1d06324ec01df6d8befbb..297e8606db821a6de1de52f6966687f62f6f638f 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 814,
-  "AetheryteShortcut": "Kholusia - Wright",
+  "Steps": [
+    {
+      "TerritoryId": 814,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Kholusia - Wright"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 257ddef63651edb8cc4e7eb1db1c22db720bdfc3..ced42fa89cabd454347adaf0b5f3f8429e089bfa 100644 (file)
@@ -1,7 +1,12 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 817,
+  "Steps": [
+    {
+      "TerritoryId": 817,
+      "InteractionType": "None"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
@@ -58,4 +63,4 @@
       ]
     }
   ]
-}
\ No newline at end of file
+}
index dabf5ad7b771699fbdd5ab0244a84d29008972f0..8d6f0db11e89ec930b72d462fc3c44e62d216616 100644 (file)
@@ -1,7 +1,12 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 817,
+  "Steps": [
+    {
+      "TerritoryId": 817,
+      "InteractionType": "None"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
@@ -58,4 +63,4 @@
       ]
     }
   ]
-}
\ No newline at end of file
+}
index 4bf777b08252b143a31b7368f5098cc2cd08a023..a1303d90e2f9a480efec3b61a543484130740c91 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 961,
-  "AetheryteShortcut": "Elpis - Poieten Oikos",
+  "Steps": [
+    {
+      "TerritoryId": 961,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Elpis - Poieten Oikos"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 8262dab427d0980a8f01bb8a68455f10c94dd2dd..1079cd1c264c87ca836ce4ac5908892285c5e952 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 961,
-  "AetheryteShortcut": "Elpis - Anagnorisis",
+  "Steps": [
+    {
+      "TerritoryId": 961,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Elpis - Anagnorisis"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index d401f0dc1d8c1db548bce0cda13fbcd0f4287999..53d696f2776f6cf83cfc4f4114595fc74d5f7654 100644 (file)
@@ -1,7 +1,12 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1073,
+  "Steps": [
+    {
+      "TerritoryId": 1073,
+      "InteractionType": "None"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
@@ -58,4 +63,4 @@
       ]
     }
   ]
-}
\ No newline at end of file
+}
index 2fb86204057960cf4cef7a99b1ef8d4b701c79eb..a5a183288dc0d0c1259a4b7620ee5eb2a48f77ee 100644 (file)
@@ -1,7 +1,12 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1073,
+  "Steps": [
+    {
+      "TerritoryId": 1073,
+      "InteractionType": "None"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
@@ -54,4 +59,4 @@
       ]
     }
   ]
-}
\ No newline at end of file
+}
index 7854b51941dda4ef246c1b822c577ed055c0461d..28eafc16717450ae97143ca24a569023e47e1091 100644 (file)
@@ -1,7 +1,12 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1073,
+  "Steps": [
+    {
+      "TerritoryId": 1073,
+      "InteractionType": "None"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
@@ -58,4 +63,4 @@
       ]
     }
   ]
-}
\ No newline at end of file
+}
index c5f722ca8233a1839c4015030775fbc6532dba46..29fd7e14e94c535d936a4fc59fa70ede15530c59 100644 (file)
@@ -1,7 +1,12 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1073,
+  "Steps": [
+    {
+      "TerritoryId": 1073,
+      "InteractionType": "None"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
@@ -58,4 +63,4 @@
       ]
     }
   ]
-}
\ No newline at end of file
+}
index d4c4076d5dca1b1c9d30f3133571ab2c38cc34c5..f5b800cf59f46ed9458b44be084f36b06226b79b 100644 (file)
@@ -1,7 +1,12 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1073,
+  "Steps": [
+    {
+      "TerritoryId": 1073,
+      "InteractionType": "None"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
@@ -54,4 +59,4 @@
       ]
     }
   ]
-}
\ No newline at end of file
+}
index a405c66586ec5bfee07ce685489d9b02c64a3e16..647326f06ba87895c4b6f52baac3017bbb707e0b 100644 (file)
@@ -1,7 +1,12 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1073,
+  "Steps": [
+    {
+      "TerritoryId": 1073,
+      "InteractionType": "None"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
@@ -58,4 +63,4 @@
       ]
     }
   ]
-}
\ No newline at end of file
+}
index 8ad1fa44ee282ebb4b01cda9c9f15f75024713d6..a53db43501a5eee83dab18e0b56baf78bf03cb23 100644 (file)
@@ -1,7 +1,12 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1073,
+  "Steps": [
+    {
+      "TerritoryId": 1073,
+      "InteractionType": "None"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
@@ -58,4 +63,4 @@
       ]
     }
   ]
-}
\ No newline at end of file
+}
index 64f577788a1b7101a6651e7ee6939c88235af096..5953cde4b14acb498b0c0c0ae4164fbf9c600d9a 100644 (file)
@@ -1,7 +1,12 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1073,
+  "Steps": [
+    {
+      "TerritoryId": 1073,
+      "InteractionType": "None"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
@@ -58,4 +63,4 @@
       ]
     }
   ]
-}
\ No newline at end of file
+}
index 76477c0f088960813b87dfa05c67198bbc6b42e0..17711bbe3372454f975885c3565353d34dfb97a0 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 958,
-  "AetheryteShortcut": "Garlemald - Camp Broken Glass",
+  "Steps": [
+    {
+      "TerritoryId": 958,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Garlemald - Camp Broken Glass"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 70944b16c1c6c3cab42cb62cb69e876c05841806..ed1de864a9f13f7f044cfe06612886037994b1c4 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 958,
-  "AetheryteShortcut": "Garlemald - Camp Broken Glass",
+  "Steps": [
+    {
+      "TerritoryId": 958,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Garlemald - Camp Broken Glass"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 8749bf37e1aa73e8f0a9402d9d147a663d707a7b..68ea154cf6548769a80f4fb2b10350d25b96c566 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 956,
-  "AetheryteShortcut": "Labyrinthos - Archeion",
+  "Steps": [
+    {
+      "TerritoryId": 956,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Labyrinthos - Archeion"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
       ]
     }
   ]
-}
\ No newline at end of file
+}
index 396b05e510cf30b9f8981cf7d376a7a16124aec7..889d8c82775c5b2b3053939da0f7331e4749000c 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 956,
-  "AetheryteShortcut": "Labyrinthos - Archeion",
+  "Steps": [
+    {
+      "TerritoryId": 956,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Labyrinthos - Archeion"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 59b2e8439c011f0d879851b3ea021bd540c1ab79..5c9f4294935241d33c2bad97a562c41ba95eed2e 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 959,
-  "AetheryteShortcut": "Mare Lamentorum - Sinus Lacrimarum",
+  "Steps": [
+    {
+      "TerritoryId": 959,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Mare Lamentorum - Sinus Lacrimarum"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index ae21eaea9497f5cb4462a2cb962e696571c034d9..967e67c2a909e5699212db18661a12ec94ff19fb 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 959,
-  "AetheryteShortcut": "Mare Lamentorum - Bestways Burrow",
+  "Steps": [
+    {
+      "TerritoryId": 959,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Mare Lamentorum - Bestways Burrow"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 5ad3c30c8be5b2de7232977ca1e149b169cf5ed6..a83330097d07095c3c2ff3c98cf940dd786a32f2 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 957,
-  "AetheryteShortcut": "Thavnair - Great Work",
+  "Steps": [
+    {
+      "TerritoryId": 957,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Thavnair - Great Work"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index bf1884b5d106190189c060ec119f51446e8dfb7b..d9003049749f9d7b925e44a601f3c8c9b5f9d58e 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 957,
-  "AetheryteShortcut": "Thavnair - Great Work",
+  "Steps": [
+    {
+      "TerritoryId": 957,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Thavnair - Great Work"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index b97d0790f91a8617cb3e46f78caba9030886a6ff..bf551a66e04ca66c26e76c9aa74f80731a18e332 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1188,
-  "AetheryteShortcut": "Kozama'uka - Ok'hanu",
+  "Steps": [
+    {
+      "TerritoryId": 1188,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Kozama'uka - Ok'hanu"
+    }
+  ],
   "FlyBetweenNodes": true,
   "Groups": [
     {
index f83d5960ebd0ceae9ad67e6f35034d1c86a1f997..4b99218fb092481f7d14d9db7ae12d9b8693567b 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1188,
-  "AetheryteShortcut": "Kozama'uka - Ok'hanu",
+  "Steps": [
+    {
+      "TerritoryId": 1188,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Kozama'uka - Ok'hanu"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 5ff1849ed906a4f7ffc7456bc9730c77a4e80a76..7637ea8b27e9439d0c265c92cd0b8df4f8f01ea2 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1188,
-  "AetheryteShortcut": "Kozama'uka - Ok'hanu",
+  "Steps": [
+    {
+      "TerritoryId": 1188,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Kozama'uka - Ok'hanu"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 6c7417be007c78d8ba142d43dc91f67ad0ab3147..ef7c642e548ecc65d80464127d5c3907cdd22224 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1190,
-  "AetheryteShortcut": "Shaaloani - Mehwahhetsoan",
+  "Steps": [
+    {
+      "TerritoryId": 1190,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Shaaloani - Mehwahhetsoan"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 5d63bdea72d1b747169626c1780af83b39c1818b..38b9da9a2ecf84be183406b927720dbbfc4ab034 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1190,
-  "AetheryteShortcut": "Shaaloani - Hhusatahwi",
+  "Steps": [
+    {
+      "TerritoryId": 1190,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Shaaloani - Hhusatahwi"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 566b0c3041b50eef467313e10cce6f8a177c237e..2ed58e1e0a99dd4845d6e5b2072bbd66ff25dd2d 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1187,
-  "AetheryteShortcut": "Urqopacha - Wachunpelo",
+  "Steps": [
+    {
+      "TerritoryId": 1187,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Urqopacha - Wachunpelo"
+    }
+  ],
   "FlyBetweenNodes": false,
   "Groups": [
     {
index 3359bf54b0264da29096569cda776cdc8040136d..7dff5fe8e23cdc287b5e52b308c2e018aee48465 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1187,
-  "AetheryteShortcut": "Urqopacha - Wachunpelo",
+  "Steps": [
+    {
+      "TerritoryId": 1187,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Urqopacha - Wachunpelo"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 3075fdf89e17db056a4e5aa8841feb87c44ca826..c4162843cd8fa74928e03ea6b862659a0af4311e 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1187,
-  "AetheryteShortcut": "Urqopacha - Worlar's Echo",
+  "Steps": [
+    {
+      "TerritoryId": 1187,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Urqopacha - Worlar's Echo"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 0e80e665f4d78eff01929f464b6a9ff08c957396..67e9a8e3ac17a9e3871228abef42a34b92932340 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1187,
-  "AetheryteShortcut": "Urqopacha - Wachunpelo",
+  "Steps": [
+    {
+      "TerritoryId": 1187,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Urqopacha - Wachunpelo"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index f2bfae7254812f8a790182918a42270c1409ec61..c29cb2cbb730585299be5de08c79693796c44c22 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1187,
-  "AetheryteShortcut": "Urqopacha - Wachunpelo",
+  "Steps": [
+    {
+      "TerritoryId": 1187,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Urqopacha - Wachunpelo"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 41f6e35deb9e3d65f6d5568c543834985d41b24a..689c55b78cbf201bbdbb336dd9949a8c4d400291 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1187,
-  "AetheryteShortcut": "Urqopacha - Worlar's Echo",
+  "Steps": [
+    {
+      "TerritoryId": 1187,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Urqopacha - Worlar's Echo"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 075e07bcbeef7369549cddc45af02810b4dbc629..061dc49a849b2c834191b72868121ed0687f5b68 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1189,
-  "AetheryteShortcut": "Yak T'el - Iq Br'aax",
+  "Steps": [
+    {
+      "TerritoryId": 1189,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Yak T'el - Iq Br'aax"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index 68779daa93710b56f4501656e6d6375948a02f69..33239ba1d089e02ae567f562e99801ce0ff466a6 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1189,
-  "AetheryteShortcut": "Yak T'el - Iq Br'aax",
+  "Steps": [
+    {
+      "TerritoryId": 1189,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Yak T'el - Iq Br'aax"
+    }
+  ],
   "FlyBetweenNodes": true,
   "Groups": [
     {
index 27cfb7e2de396953c16e83fadc91e8c0399c0d6a..71eb2bd40865a40a4ff9b4f8dfd4bee7b48ce69e 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1189,
-  "AetheryteShortcut": "Yak T'el - Mamook",
+  "Steps": [
+    {
+      "TerritoryId": 1189,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Yak T'el - Mamook"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index eeb921264bb1d4a69a712f944b68eb8b34faa34e..2eaabe11f880d68f1faa8ff777510c428e9c0b7b 100644 (file)
@@ -1,8 +1,13 @@
 {
   "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
   "Author": "liza",
-  "TerritoryId": 1189,
-  "AetheryteShortcut": "Yak T'el - Iq Br'aax",
+  "Steps": [
+    {
+      "TerritoryId": 1189,
+      "InteractionType": "None",
+      "AetheryteShortcut": "Yak T'el - Iq Br'aax"
+    }
+  ],
   "Groups": [
     {
       "Nodes": [
index ffb288ab5f656ffccdf1bc7b629d47e9286e8af7..beba3b18277c97c5e39f6495352f0fdb6fd5b7b1 100644 (file)
         "type": "string"
       }
     },
-    "TerritoryId": {
-      "type": "number"
-    },
-    "AetheryteShortcut": {
-      "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
-    },
-    "AethernetShortcut": {
+    "Steps": {
       "type": "array",
-      "description": "A pair of aethernet locations (from + to) to use as a shortcut",
-      "minItems": 2,
-      "maxItems": 2,
       "items": {
-        "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/AethernetShard"
-      }
+        "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json#/$defs/Step"
+      },
+      "minItems": 1
     },
     "FlyBetweenNodes": {
       "description": "If nodes are close enough together, flying makes no sense due to the pathfinding overhead",
@@ -63,7 +55,7 @@
                     "type": "object",
                     "properties": {
                       "Position": {
-                        "$ref": "#/$defs/Vector3"
+                        "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Vector3"
                       },
                       "MinimumAngle": {
                         "type": "number",
   "required": [
     "$schema",
     "Author",
-    "TerritoryId",
+    "Steps",
     "Groups"
   ],
-  "additionalProperties": false,
-  "$defs": {
-    "Vector3": {
-      "type": "object",
-      "description": "Position to (typically) walk to",
-      "properties": {
-        "X": {
-          "type": "number"
-        },
-        "Y": {
-          "type": "number"
-        },
-        "Z": {
-          "type": "number"
-        }
-      },
-      "required": [
-        "X",
-        "Y",
-        "Z"
-      ]
-    }
-  }
+  "additionalProperties": false
 }
index 6ba6efbb1cbb516343782f3678d165ccc5b8d176..1a341ed6781f7a34cd1dc789de15777432b648e8 100644 (file)
@@ -152,13 +152,7 @@ public class GatheringSourceGenerator : ISourceGenerator
                         SeparatedList<ExpressionSyntax>(
                             SyntaxNodeList(
                                 AssignmentList(nameof(GatheringRoot.Author), root.Author).AsSyntaxNodeOrToken(),
-                                Assignment(nameof(GatheringRoot.TerritoryId), root.TerritoryId, emptyRoot.TerritoryId)
-                                    .AsSyntaxNodeOrToken(),
-                                Assignment(nameof(GatheringRoot.AetheryteShortcut), root.AetheryteShortcut,
-                                        emptyRoot.AetheryteShortcut)
-                                    .AsSyntaxNodeOrToken(),
-                                Assignment(nameof(GatheringRoot.AethernetShortcut), root.AethernetShortcut,
-                                        emptyRoot.AethernetShortcut)
+                                AssignmentList(nameof(GatheringRoot.Steps), root.Steps)
                                     .AsSyntaxNodeOrToken(),
                                 Assignment(nameof(GatheringRoot.FlyBetweenNodes), root.FlyBetweenNodes,
                                         emptyRoot.FlyBetweenNodes)
index ea885fd4acee0c794f2214b3bec1615dd74000f4..43f33bd5a7183b919288371d9e901379fcf5887a 100644 (file)
@@ -5,6 +5,25 @@
     {
       "Sequence": 0,
       "Steps": [
+        {
+          "TerritoryId": 886,
+          "InteractionType": "None",
+          "AetheryteShortcut": "Ishgard",
+          "AethernetShortcut": [
+            "[Ishgard] Aetheryte Plaza",
+            "[Ishgard] Firmament"
+          ],
+          "SkipConditions": {
+            "AetheryteShortcutIf": {
+              "InTerritory": [
+                886
+              ]
+            },
+            "AethernetShortcutIf": {
+              "InSameTerritory": true
+            }
+          }
+        },
         {
           "DataId": 1035211,
           "Position": {
           },
           "TerritoryId": 886,
           "InteractionType": "Interact",
-          "AetheryteShortcut": "Ishgard",
           "AethernetShortcut": [
-            "[Ishgard] Aetheryte Plaza",
-            "[Ishgard] Firmament"
+            "[Firmament] The Mendicant's Court",
+            "[Firmament] Western Risensong Quarter"
           ],
           "DialogueChoices": [
             {
index 6e4e68f3dae42fb575d1938824cb86472e3bdcf2..70a150918f7ddd23517209e01808d0b72c680b3e 100644 (file)
@@ -5,6 +5,25 @@
     {
       "Sequence": 0,
       "Steps": [
+        {
+          "TerritoryId": 886,
+          "InteractionType": "None",
+          "AetheryteShortcut": "Ishgard",
+          "AethernetShortcut": [
+            "[Ishgard] Aetheryte Plaza",
+            "[Ishgard] Firmament"
+          ],
+          "SkipConditions": {
+            "AetheryteShortcutIf": {
+              "InTerritory": [
+                886
+              ]
+            },
+            "AethernetShortcutIf": {
+              "InSameTerritory": true
+            }
+          }
+        },
         {
           "DataId": 1033543,
           "Position": {
           },
           "TerritoryId": 886,
           "InteractionType": "Interact",
-          "AetheryteShortcut": "Ishgard",
           "AethernetShortcut": [
-            "[Ishgard] Aetheryte Plaza",
-            "[Ishgard] Firmament"
+            "[Firmament] The Mendicant's Court",
+            "[Firmament] The Mattock"
           ],
           "DialogueChoices": [
             {
index 7db023e1061bf8e4403205da74a98c5db9ec6cd1..122c64068d996d8479892de1a2a4f5ca9acf564e 100644 (file)
           "Steps": {
             "type": "array",
             "items": {
+              "$ref": "#/$defs/Step"
+            }
+          },
+          "Comment": {
+            "type": "string"
+          }
+        },
+        "required": [
+          "Sequence"
+        ],
+        "additionalProperties": false
+      }
+    }
+  },
+  "required": [
+    "$schema",
+    "QuestSequence",
+    "Author"
+  ],
+  "additionalProperties": false,
+  "$defs": {
+    "Step": {
+      "type": "object",
+      "properties": {
+        "DataId": {
+          "type": "integer",
+          "description": "The data id of the NPC/Object/Aetheryte/Aether Current",
+          "exclusiveMinimum": 0
+        },
+        "Position": {
+          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Vector3"
+        },
+        "StopDistance": {
+          "type": [
+            "number",
+            "null"
+          ],
+          "description": "Set if pathfinding should stop closer or further away from the default stop distance",
+          "exclusiveMinimum": 0
+        },
+        "IgnoreDistanceToObject": {
+          "type": "boolean",
+          "description": "Most interactions with objects are checked for a Y (height) difference of 2 in-game units. If set to true, the game won't attempt to get any closer if the height difference is larger than this."
+        },
+        "TerritoryId": {
+          "type": "integer",
+          "description": "The territory id associated with the location",
+          "exclusiveMinimum": 0
+        },
+        "TargetTerritoryId": {
+          "type": "integer",
+          "description": "If set, this step is complete (movement-wise) if this territory id is reached",
+          "exclusiveMinimum": 0
+        },
+        "InteractionType": {
+          "type": "string",
+          "description": "What to do at the position",
+          "enum": [
+            "None",
+            "Interact",
+            "WalkTo",
+            "AttuneAethernetShard",
+            "AttuneAetheryte",
+            "AttuneAetherCurrent",
+            "Combat",
+            "UseItem",
+            "EquipItem",
+            "EquipRecommended",
+            "Say",
+            "Emote",
+            "Action",
+            "WaitForNpcAtPosition",
+            "WaitForManualProgress",
+            "Duty",
+            "SinglePlayerDuty",
+            "Jump",
+            "Dive",
+            "Instruction",
+            "AcceptQuest",
+            "CompleteQuest",
+            "InitiateLeve"
+          ]
+        },
+        "Disabled": {
+          "description": "Whether this step is disabled (see SkipIf for more control)",
+          "type": "boolean"
+        },
+        "DisableNavmesh": {
+          "description": "If true, will go to the position in a straight line instead of using pathfinding",
+          "type": "boolean"
+        },
+        "Mount": {
+          "type": [
+            "boolean",
+            "null"
+          ],
+          "description": "If true, will mount regardless of distance to position. If false, will unmount."
+        },
+        "Fly": {
+          "type": "boolean",
+          "description": "If true and flying is unlocked in a zone, will use a flight path"
+        },
+        "Land": {
+          "type": "boolean",
+          "description": "If true and flying, will attempt to land on the ground"
+        },
+        "Sprint": {
+          "type": [
+            "boolean",
+            "null"
+          ]
+        },
+        "AetheryteShortcut": {
+          "description": "The Aetheryte to teleport to (before moving)",
+          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
+        },
+        "AethernetShortcut": {
+          "type": "array",
+          "description": "A pair of aethernet locations (from + to) to use as a shortcut",
+          "minItems": 2,
+          "maxItems": 2,
+          "items": {
+            "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/AethernetShard"
+          }
+        },
+        "ItemId": {
+          "type": [
+            "number",
+            "null"
+          ],
+          "description": "The Item to use",
+          "exclusiveMinimum": 0
+        },
+        "SkipConditions": {
+          "type": "object",
+          "properties": {
+            "StepIf": {
               "type": "object",
               "properties": {
-                "DataId": {
-                  "type": "integer",
-                  "description": "The data id of the NPC/Object/Aetheryte/Aether Current",
-                  "exclusiveMinimum": 0
-                },
-                "Position": {
-                  "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Vector3"
-                },
-                "StopDistance": {
-                  "type": [
-                    "number",
-                    "null"
-                  ],
-                  "description": "Set if pathfinding should stop closer or further away from the default stop distance",
-                  "exclusiveMinimum": 0
-                },
-                "IgnoreDistanceToObject": {
-                  "type": "boolean",
-                  "description": "Most interactions with objects are checked for a Y (height) difference of 2 in-game units. If set to true, the game won't attempt to get any closer if the height difference is larger than this."
-                },
-                "TerritoryId": {
-                  "type": "integer",
-                  "description": "The territory id associated with the location",
-                  "exclusiveMinimum": 0
+                "Never": {
+                  "type": "boolean"
                 },
-                "TargetTerritoryId": {
-                  "type": "integer",
-                  "description": "If set, this step is complete (movement-wise) if this territory id is reached",
-                  "exclusiveMinimum": 0
+                "CompletionQuestVariablesFlags": {
+                  "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/CompletionFlags"
                 },
-                "InteractionType": {
+                "Flying": {
                   "type": "string",
-                  "description": "What to do at the position",
                   "enum": [
-                    "None",
-                    "Interact",
-                    "WalkTo",
-                    "AttuneAethernetShard",
-                    "AttuneAetheryte",
-                    "AttuneAetherCurrent",
-                    "Combat",
-                    "UseItem",
-                    "EquipItem",
-                    "EquipRecommended",
-                    "Say",
-                    "Emote",
-                    "Action",
-                    "WaitForNpcAtPosition",
-                    "WaitForManualProgress",
-                    "Duty",
-                    "SinglePlayerDuty",
-                    "Jump",
-                    "Dive",
-                    "Instruction",
-                    "AcceptQuest",
-                    "CompleteQuest",
-                    "InitiateLeve"
+                    "Locked",
+                    "Unlocked"
                   ]
                 },
-                "Disabled": {
-                  "description": "Whether this step is disabled (see SkipIf for more control)",
-                  "type": "boolean"
+                "Chocobo": {
+                  "type": "string",
+                  "enum": [
+                    "Locked",
+                    "Unlocked"
+                  ]
                 },
-                "DisableNavmesh": {
-                  "description": "If true, will go to the position in a straight line instead of using pathfinding",
+                "NotTargetable": {
                   "type": "boolean"
                 },
-                "Mount": {
-                  "type": [
-                    "boolean",
-                    "null"
-                  ],
-                  "description": "If true, will mount regardless of distance to position. If false, will unmount."
-                },
-                "Fly": {
-                  "type": "boolean",
-                  "description": "If true and flying is unlocked in a zone, will use a flight path"
+                "InTerritory": {
+                  "type": "array",
+                  "items": {
+                    "type": "integer"
+                  }
                 },
-                "Land": {
-                  "type": "boolean",
-                  "description": "If true and flying, will attempt to land on the ground"
+                "NotInTerritory": {
+                  "type": "array",
+                  "items": {
+                    "type": "integer"
+                  }
                 },
-                "Sprint": {
-                  "type": [
-                    "boolean",
-                    "null"
-                  ]
+                "Item": {
+                  "type": "object",
+                  "properties": {
+                    "NotInInventory": {
+                      "type": "boolean"
+                    }
+                  }
                 },
-                "AetheryteShortcut": {
-                  "description": "The Aetheryte to teleport to (before moving)",
-                  "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
+                "QuestsAccepted": {
+                  "type": "array",
+                  "items": {
+                    "type": "number"
+                  }
                 },
-                "AethernetShortcut": {
+                "QuestsCompleted": {
                   "type": "array",
-                  "description": "A pair of aethernet locations (from + to) to use as a shortcut",
-                  "minItems": 2,
-                  "maxItems": 2,
                   "items": {
-                    "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/AethernetShard"
+                    "type": "number"
                   }
                 },
-                "ItemId": {
-                  "type": [
-                    "number",
-                    "null"
-                  ],
-                  "description": "The Item to use",
-                  "exclusiveMinimum": 0
+                "AetheryteLocked": {
+                  "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
                 },
-                "SkipConditions": {
+                "AetheryteUnlocked": {
+                  "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
+                },
+                "NearPosition": {
                   "type": "object",
                   "properties": {
-                    "StepIf": {
-                      "type": "object",
-                      "properties": {
-                        "Never": {
-                          "type": "boolean"
-                        },
-                        "CompletionQuestVariablesFlags": {
-                          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/CompletionFlags"
-                        },
-                        "Flying": {
-                          "type": "string",
-                          "enum": [
-                            "Locked",
-                            "Unlocked"
-                          ]
-                        },
-                        "Chocobo": {
-                          "type": "string",
-                          "enum": [
-                            "Locked",
-                            "Unlocked"
-                          ]
-                        },
-                        "NotTargetable": {
-                          "type": "boolean"
-                        },
-                        "InTerritory": {
-                          "type": "array",
-                          "items": {
-                            "type": "integer"
-                          }
-                        },
-                        "NotInTerritory": {
-                          "type": "array",
-                          "items": {
-                            "type": "integer"
-                          }
-                        },
-                        "Item": {
-                          "type": "object",
-                          "properties": {
-                            "NotInInventory": {
-                              "type": "boolean"
-                            }
-                          }
-                        },
-                        "QuestsAccepted": {
-                          "type": "array",
-                          "items": {
-                            "type": "number"
-                          }
-                        },
-                        "QuestsCompleted": {
-                          "type": "array",
-                          "items": {
-                            "type": "number"
-                          }
-                        },
-                        "AetheryteLocked": {
-                          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
-                        },
-                        "AetheryteUnlocked": {
-                          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
-                        },
-                        "NearPosition": {
-                          "type": "object",
-                          "properties": {
-                            "Position": {
-                              "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Vector3"
-                            },
-                            "MaximumDistance": {
-                              "type": "number"
-                            }
-                          },
-                          "required": [
-                            "Position",
-                            "MaximumDistance"
-                          ],
-                          "additionalProperties": false
-                        },
-                        "ExtraCondition": {
-                          "type": "string",
-                          "enum": [
-                            "WakingSandsMainArea",
-                            "RisingStonesSolar"
-                          ]
-                        }
-                      },
-                      "additionalProperties": false
-                    },
-                    "AetheryteShortcutIf": {
-                      "type": "object",
-                      "properties": {
-                        "Never": {
-                          "type": "boolean"
-                        },
-                        "InSameTerritory": {
-                          "type": "boolean"
-                        },
-                        "InTerritory": {
-                          "type": "array",
-                          "items": {
-                            "type": "integer"
-                          }
-                        },
-                        "AetheryteLocked": {
-                          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
-                        },
-                        "AetheryteUnlocked": {
-                          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
-                        }
-                      },
-                      "additionalProperties": false
+                    "Position": {
+                      "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Vector3"
                     },
-                    "AethernetShortcutIf": {
-                      "type": "object",
-                      "properties": {
-                        "Never": {
-                          "type": "boolean"
-                        },
-                        "InSameTerritory": {
-                          "type": "boolean"
-                        },
-                        "AetheryteLocked": {
-                          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
-                        },
-                        "AetheryteUnlocked": {
-                          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
-                        }
-                      },
-                      "additionalProperties": false
+                    "MaximumDistance": {
+                      "type": "number"
                     }
                   },
+                  "required": [
+                    "Position",
+                    "MaximumDistance"
+                  ],
                   "additionalProperties": false
                 },
-                "CompletionQuestVariablesFlags": {
-                  "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/CompletionFlags"
+                "ExtraCondition": {
+                  "type": "string",
+                  "enum": [
+                    "WakingSandsMainArea",
+                    "RisingStonesSolar"
+                  ]
+                }
+              },
+              "additionalProperties": false
+            },
+            "AetheryteShortcutIf": {
+              "type": "object",
+              "properties": {
+                "Never": {
+                  "type": "boolean"
                 },
-                "RequiredQuestVariables": {
-                  "type": "array",
-                  "description": "Certain quests (primarily beast tribes/allied societies) have a RNG element to spawning targets, and the step should be skipped in its entirety if none of the sets below match",
-                  "minItems": 6,
-                  "maxItems": 6,
-                  "items": {
-                    "type": [
-                      "array",
-                      "null"
-                    ],
-                    "items": {
-                      "type": [
-                        "number",
-                        "object"
-                      ],
-                      "properties": {
-                        "High": {
-                          "type": [
-                            "number",
-                            "null"
-                          ],
-                          "minimum": 0,
-                          "maximum": 15
-                        },
-                        "Low": {
-                          "type": [
-                            "number",
-                            "null"
-                          ],
-                          "minimum": 0,
-                          "maximum": 15
-                        }
-                      },
-                      "minimum": 0,
-                      "maximum": 255
-                    }
-                  }
+                "InSameTerritory": {
+                  "type": "boolean"
                 },
-                "RequiredGatheredItems": {
+                "InTerritory": {
                   "type": "array",
                   "items": {
-                    "type": "object",
-                    "properties": {
-                      "ItemId": {
-                        "type": "number"
-                      },
-                      "AlternativeItemId": {
-                        "description": "For leves that allow you to gather two items with different chance percentage, this is the preferred item if the gathering chance is 100% (after buffs)",
-                        "type": "number"
-                      },
-                      "ItemCount": {
-                        "type": "number",
-                        "exclusiveMinimum": 0
-                      },
-                      "Collectability": {
-                        "type": "number",
-                        "minimum": 0,
-                        "maximum": 1000
-                      }
-                    },
-                    "required": [
-                      "ItemId",
-                      "ItemCount"
-                    ]
+                    "type": "integer"
                   }
                 },
-                "DelaySecondsAtStart": {
-                  "description": "Time to wait before starting",
+                "AetheryteLocked": {
+                  "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
+                },
+                "AetheryteUnlocked": {
+                  "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
+                }
+              },
+              "additionalProperties": false
+            },
+            "AethernetShortcutIf": {
+              "type": "object",
+              "properties": {
+                "Never": {
+                  "type": "boolean"
+                },
+                "InSameTerritory": {
+                  "type": "boolean"
+                },
+                "AetheryteLocked": {
+                  "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
+                },
+                "AetheryteUnlocked": {
+                  "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
+                }
+              },
+              "additionalProperties": false
+            }
+          },
+          "additionalProperties": false
+        },
+        "CompletionQuestVariablesFlags": {
+          "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/CompletionFlags"
+        },
+        "RequiredQuestVariables": {
+          "type": "array",
+          "description": "Certain quests (primarily beast tribes/allied societies) have a RNG element to spawning targets, and the step should be skipped in its entirety if none of the sets below match",
+          "minItems": 6,
+          "maxItems": 6,
+          "items": {
+            "type": [
+              "array",
+              "null"
+            ],
+            "items": {
+              "type": [
+                "number",
+                "object"
+              ],
+              "properties": {
+                "High": {
                   "type": [
                     "number",
                     "null"
-                  ]
+                  ],
+                  "minimum": 0,
+                  "maximum": 15
                 },
-                "Comment": {
-                  "type": "string"
+                "Low": {
+                  "type": [
+                    "number",
+                    "null"
+                  ],
+                  "minimum": 0,
+                  "maximum": 15
                 }
               },
-              "required": [
-                "TerritoryId",
-                "InteractionType"
-              ],
-              "allOf": [
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "Interact"
-                      }
+              "minimum": 0,
+              "maximum": 255
+            }
+          }
+        },
+        "RequiredGatheredItems": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "properties": {
+              "ItemId": {
+                "type": "number"
+              },
+              "AlternativeItemId": {
+                "description": "For leves that allow you to gather two items with different chance percentage, this is the preferred item if the gathering chance is 100% (after buffs)",
+                "type": "number"
+              },
+              "ItemCount": {
+                "type": "number",
+                "exclusiveMinimum": 0
+              },
+              "Collectability": {
+                "type": "number",
+                "minimum": 0,
+                "maximum": 1000
+              }
+            },
+            "required": [
+              "ItemId",
+              "ItemCount"
+            ]
+          }
+        },
+        "DelaySecondsAtStart": {
+          "description": "Time to wait before starting",
+          "type": [
+            "number",
+            "null"
+          ]
+        },
+        "Comment": {
+          "type": "string"
+        }
+      },
+      "required": [
+        "TerritoryId",
+        "InteractionType"
+      ],
+      "allOf": [
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "Interact"
+              }
+            }
+          },
+          "then": {
+            "required": [
+              "DataId"
+            ]
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "WalkTo"
+              }
+            }
+          },
+          "then": {
+            "required": [
+              "Position"
+            ]
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "AttuneAetheryte"
+              }
+            }
+          },
+          "then": {
+            "properties": {
+              "Aetheryte": {
+                "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
+              },
+              "DataId": {
+                "type": "null"
+              },
+              "Position": {
+                "type": "null"
+              }
+            },
+            "required": [
+              "Aetheryte"
+            ]
+          },
+          "else": {
+            "properties": {
+              "Aetheryte": {
+                "type": "null"
+              }
+            }
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "AttuneAethernetShard"
+              }
+            }
+          },
+          "then": {
+            "properties": {
+              "AethernetShard": {
+                "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/AethernetShard"
+              },
+              "DataId": {
+                "type": "null"
+              },
+              "Position": {
+                "type": "null"
+              }
+            },
+            "required": [
+              "AethernetShard"
+            ]
+          },
+          "else": {
+            "properties": {
+              "AethernetShard": {
+                "type": "null"
+              }
+            }
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "AttuneAetherCurrent"
+              }
+            }
+          },
+          "then": {
+            "properties": {
+              "AetherCurrentId": {
+                "type": "integer",
+                "description": "The aether current id, used to check if a given aetheryte is unlocked",
+                "exclusiveMinimum": 0
+              }
+            },
+            "required": [
+              "DataId",
+              "Position",
+              "AetherCurrentId"
+            ]
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "Combat"
+              }
+            }
+          },
+          "then": {
+            "properties": {
+              "EnemySpawnType": {
+                "type": "string",
+                "description": "Determines how enemy spawning is handled in combat locations",
+                "enum": [
+                  "AutoOnEnterArea",
+                  "AfterInteraction",
+                  "AfterItemUse",
+                  "OverworldEnemies"
+                ]
+              },
+              "KillEnemyDataIds": {
+                "description": "The enemy data ids which are supposed to be killed",
+                "type": "array",
+                "items": {
+                  "type": "integer"
+                }
+              },
+              "ComplexCombatData": {
+                "description": "If multiple different enemies are supposed to be killed in a single quest step, this typically is handled via items",
+                "type": "array",
+                "items": {
+                  "type": "object",
+                  "properties": {
+                    "DataId": {
+                      "description": "The enemy data id which is supposed to be killed",
+                      "type": "integer"
+                    },
+                    "MinimumKillCount": {
+                      "description": "Overworld mobs: If this number of mobs has been killed, will wait a bit before attempting to pull another mob to see if the quest progresses",
+                      "type": "integer"
+                    },
+                    "RewardItemId": {
+                      "type": "integer"
+                    },
+                    "RewardItemCount": {
+                      "type": "integer"
+                    },
+                    "CompletionQuestVariablesFlags": {
+                      "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/CompletionFlags"
+                    },
+                    "IgnoreQuestMarker": {
+                      "type": "boolean"
                     }
                   },
-                  "then": {
-                    "required": [
-                      "DataId"
-                    ]
+                  "required": [
+                    "DataId"
+                  ]
+                }
+              },
+              "CombatDelaySecondsAtStart": {
+                "type": "number"
+              }
+            },
+            "required": [
+              "Position",
+              "EnemySpawnType"
+            ],
+            "oneOf": [
+              {
+                "required": [
+                  "KillEnemyDataIds"
+                ]
+              },
+              {
+                "required": [
+                  "ComplexCombatData"
+                ]
+              }
+            ]
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "UseItem"
+              },
+              "ItemId": {
+                "not": {
+                  "const": 30362
+                }
+              }
+            }
+          },
+          "then": {
+            "required": [
+              "Position"
+            ]
+          }
+        },
+        {
+          "if": {
+            "anyOf": [
+              {
+                "properties": {
+                  "InteractionType": {
+                    "const": "UseItem"
                   }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "WalkTo"
-                      }
-                    }
+                }
+              },
+              {
+                "properties": {
+                  "InteractionType": {
+                    "const": "Combat"
                   },
-                  "then": {
-                    "required": [
-                      "Position"
-                    ]
+                  "EnemySpawnType": {
+                    "const": "AfterItemUse"
+                  }
+                }
+              }
+            ]
+          },
+          "then": {
+            "properties": {
+              "GroundTarget": {
+                "type": [
+                  "boolean",
+                  "null"
+                ],
+                "default": false
+              }
+            },
+            "required": [
+              "ItemId"
+            ]
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "EquipItem"
+              }
+            }
+          },
+          "then": {
+            "required": [
+              "ItemId"
+            ]
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "anyOf": [
+                  {
+                    "const": "Emote"
+                  },
+                  {
+                    "const": "AcceptQuest"
+                  },
+                  {
+                    "const": "CompleteQuest"
+                  },
+                  {
+                    "const": "SinglePlayerDuty"
+                  }
+                ]
+              }
+            }
+          },
+          "then": {
+            "properties": {
+              "Emote": {
+                "type": "string",
+                "description": "The emote to use",
+                "enum": [
+                  "stretch",
+                  "wave",
+                  "rally",
+                  "deny",
+                  "pray",
+                  "slap",
+                  "doubt",
+                  "psych",
+                  "cheer",
+                  "happy",
+                  "poke",
+                  "flex",
+                  "soothe",
+                  "me",
+                  "welcome",
+                  "imperialsalute",
+                  "pet",
+                  "dance",
+                  "respect",
+                  "lookout",
+                  "kneel",
+                  "bow",
+                  "uchiwasshoi",
+                  "clap",
+                  "victorypose"
+                ]
+              }
+            }
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "Emote"
+              }
+            }
+          },
+          "then": {
+            "required": [
+              "Position",
+              "Emote"
+            ]
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "anyOf": [
+                  {
+                    "const": "Say"
+                  },
+                  {
+                    "const": "CompleteQuest"
+                  }
+                ]
+              }
+            }
+          },
+          "then": {
+            "properties": {
+              "ChatMessage": {
+                "type": "object",
+                "description": "The text to use with /say",
+                "properties": {
+                  "ExcelSheet": {
+                    "type": "string"
+                  },
+                  "Key": {
+                    "type": "string"
                   }
                 },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "AttuneAetheryte"
-                      }
-                    }
+                "required": [
+                  "Key"
+                ]
+              }
+            }
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "Say"
+              }
+            }
+          },
+          "then": {
+            "required": [
+              "ChatMessage"
+            ]
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "Action"
+              }
+            }
+          },
+          "then": {
+            "properties": {
+              "Action": {
+                "type": "string",
+                "description": "The action to use",
+                "enum": [
+                  "Cure",
+                  "Esuna",
+                  "Physick",
+                  "Buffet",
+                  "Fumigate",
+                  "Siphon Snout",
+                  "Red Gulal",
+                  "Yellow Gulal",
+                  "Blue Gulal"
+                ]
+              }
+            },
+            "required": [
+              "Action"
+            ]
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "Jump"
+              }
+            }
+          },
+          "then": {
+            "properties": {
+              "JumpDestination": {
+                "type": "object",
+                "properties": {
+                  "Position": {
+                    "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Vector3"
                   },
-                  "then": {
-                    "properties": {
-                      "Aetheryte": {
-                        "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
-                      },
-                      "DataId": {
-                        "type": "null"
-                      },
-                      "Position": {
-                        "type": "null"
-                      }
-                    },
-                    "required": [
-                      "Aetheryte"
+                  "StopDistance": {
+                    "type": [
+                      "number",
+                      "null"
+                    ],
+                    "description": "Set if pathfinding should stop closer or further away from the default stop distance",
+                    "exclusiveMinimum": 0
+                  },
+                  "DelaySeconds": {
+                    "type": [
+                      "number",
+                      "null"
                     ]
                   },
-                  "else": {
-                    "properties": {
-                      "Aetheryte": {
-                        "type": "null"
-                      }
-                    }
+                  "Type": {
+                    "type": "string",
+                    "enum": [
+                      "SingleJump",
+                      "RepeatedJumps"
+                    ],
+                    "default": "SingleJump"
                   }
                 },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "AttuneAethernetShard"
-                      }
-                    }
+                "required": [
+                  "Position"
+                ]
+              }
+            },
+            "required": [
+              "Position",
+              "JumpDestination"
+            ]
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "anyOf": [
+                  {
+                    "const": "Interact"
                   },
-                  "then": {
-                    "properties": {
-                      "AethernetShard": {
-                        "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/AethernetShard"
-                      },
-                      "DataId": {
-                        "type": "null"
-                      },
-                      "Position": {
-                        "type": "null"
-                      }
-                    },
-                    "required": [
-                      "AethernetShard"
-                    ]
+                  {
+                    "const": "SinglePlayerDuty"
                   },
-                  "else": {
-                    "properties": {
-                      "AethernetShard": {
-                        "type": "null"
-                      }
-                    }
-                  }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "AttuneAetherCurrent"
-                      }
-                    }
+                  {
+                    "const": "WaitForManualProgress"
                   },
-                  "then": {
-                    "properties": {
-                      "AetherCurrentId": {
-                        "type": "integer",
-                        "description": "The aether current id, used to check if a given aetheryte is unlocked",
-                        "exclusiveMinimum": 0
-                      }
-                    },
-                    "required": [
-                      "DataId",
-                      "Position",
-                      "AetherCurrentId"
-                    ]
-                  }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "Combat"
-                      }
-                    }
+                  {
+                    "const": "AcceptQuest"
                   },
-                  "then": {
-                    "properties": {
-                      "EnemySpawnType": {
-                        "type": "string",
-                        "description": "Determines how enemy spawning is handled in combat locations",
-                        "enum": [
-                          "AutoOnEnterArea",
-                          "AfterInteraction",
-                          "AfterItemUse",
-                          "OverworldEnemies"
-                        ]
-                      },
-                      "KillEnemyDataIds": {
-                        "description": "The enemy data ids which are supposed to be killed",
-                        "type": "array",
-                        "items": {
-                          "type": "integer"
-                        }
-                      },
-                      "ComplexCombatData": {
-                        "description": "If multiple different enemies are supposed to be killed in a single quest step, this typically is handled via items",
-                        "type": "array",
-                        "items": {
-                          "type": "object",
-                          "properties": {
-                            "DataId": {
-                              "description": "The enemy data id which is supposed to be killed",
-                              "type": "integer"
-                            },
-                            "MinimumKillCount": {
-                              "description": "Overworld mobs: If this number of mobs has been killed, will wait a bit before attempting to pull another mob to see if the quest progresses",
-                              "type": "integer"
-                            },
-                            "RewardItemId": {
-                              "type": "integer"
-                            },
-                            "RewardItemCount": {
-                              "type": "integer"
-                            },
-                            "CompletionQuestVariablesFlags": {
-                              "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/CompletionFlags"
-                            },
-                            "IgnoreQuestMarker": {
-                              "type": "boolean"
-                            }
-                          },
-                          "required": [
-                            "DataId"
-                          ]
-                        }
-                      },
-                      "CombatDelaySecondsAtStart": {
-                        "type": "number"
-                      }
-                    },
-                    "required": [
-                      "Position",
-                      "EnemySpawnType"
-                    ],
-                    "oneOf": [
-                      {
-                        "required": [
-                          "KillEnemyDataIds"
-                        ]
-                      },
-                      {
-                        "required": [
-                          "ComplexCombatData"
-                        ]
-                      }
-                    ]
-                  }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "UseItem"
-                      },
-                      "ItemId": {
-                        "not": {
-                          "const": 30362
-                        }
-                      }
-                    }
+                  {
+                    "const": "CompleteQuest"
                   },
-                  "then": {
-                    "required": [
-                      "Position"
-                    ]
-                  }
-                },
-                {
-                  "if": {
-                    "anyOf": [
-                      {
-                        "properties": {
-                          "InteractionType": {
-                            "const": "UseItem"
-                          }
-                        }
-                      },
-                      {
-                        "properties": {
-                          "InteractionType": {
-                            "const": "Combat"
-                          },
-                          "EnemySpawnType": {
-                            "const": "AfterItemUse"
-                          }
-                        }
-                      }
-                    ]
+                  {
+                    "const": "Instruction"
                   },
-                  "then": {
-                    "properties": {
-                      "GroundTarget": {
-                        "type": [
-                          "boolean",
-                          "null"
-                        ],
-                        "default": false
-                      }
-                    },
-                    "required": [
-                      "ItemId"
-                    ]
-                  }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "EquipItem"
-                      }
-                    }
+                  {
+                    "const": "Say"
                   },
-                  "then": {
-                    "required": [
-                      "ItemId"
-                    ]
-                  }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "anyOf": [
-                          {
-                            "const": "Emote"
-                          },
-                          {
-                            "const": "AcceptQuest"
-                          },
-                          {
-                            "const": "CompleteQuest"
-                          },
-                          {
-                            "const": "SinglePlayerDuty"
-                          }
-                        ]
-                      }
-                    }
+                  {
+                    "const": "Emote"
                   },
-                  "then": {
-                    "properties": {
-                      "Emote": {
-                        "type": "string",
-                        "description": "The emote to use",
-                        "enum": [
-                          "stretch",
-                          "wave",
-                          "rally",
-                          "deny",
-                          "pray",
-                          "slap",
-                          "doubt",
-                          "psych",
-                          "cheer",
-                          "happy",
-                          "poke",
-                          "flex",
-                          "soothe",
-                          "me",
-                          "welcome",
-                          "imperialsalute",
-                          "pet",
-                          "dance",
-                          "respect",
-                          "lookout",
-                          "kneel",
-                          "bow",
-                          "uchiwasshoi",
-                          "clap",
-                          "victorypose"
-                        ]
-                      }
-                    }
+                  {
+                    "const": "UseItem"
                   }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "Emote"
-                      }
+                ]
+              }
+            }
+          },
+          "then": {
+            "properties": {
+              "DialogueChoices": {
+                "type": "array",
+                "items": {
+                  "type": "object",
+                  "properties": {
+                    "Type": {
+                      "type": "string",
+                      "enum": [
+                        "YesNo",
+                        "List"
+                      ]
+                    },
+                    "ExcelSheet": {
+                      "type": "string"
                     }
                   },
-                  "then": {
-                    "required": [
-                      "Position",
-                      "Emote"
-                    ]
-                  }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "anyOf": [
-                          {
-                            "const": "Say"
-                          },
-                          {
-                            "const": "CompleteQuest"
+                  "required": [
+                    "Type"
+                  ],
+                  "allOf": [
+                    {
+                      "if": {
+                        "properties": {
+                          "Type": {
+                            "const": "YesNo"
                           }
-                        ]
-                      }
-                    }
-                  },
-                  "then": {
-                    "properties": {
-                      "ChatMessage": {
-                        "type": "object",
-                        "description": "The text to use with /say",
+                        }
+                      },
+                      "then": {
                         "properties": {
-                          "ExcelSheet": {
-                            "type": "string"
+                          "Prompt": {
+                            "type": [
+                              "string",
+                              "integer"
+                            ]
                           },
-                          "Key": {
-                            "type": "string"
+                          "Yes": {
+                            "type": "boolean",
+                            "default": true
                           }
                         },
                         "required": [
-                          "Key"
-                        ]
-                      }
-                    }
-                  }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "Say"
-                      }
-                    }
-                  },
-                  "then": {
-                    "required": [
-                      "ChatMessage"
-                    ]
-                  }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "Action"
-                      }
-                    }
-                  },
-                  "then": {
-                    "properties": {
-                      "Action": {
-                        "type": "string",
-                        "description": "The action to use",
-                        "enum": [
-                          "Cure",
-                          "Esuna",
-                          "Physick",
-                          "Buffet",
-                          "Fumigate",
-                          "Siphon Snout",
-                          "Red Gulal",
-                          "Yellow Gulal",
-                          "Blue Gulal"
+                          "Prompt",
+                          "Yes"
                         ]
                       }
                     },
-                    "required": [
-                      "Action"
-                    ]
-                  }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "Jump"
-                      }
-                    }
-                  },
-                  "then": {
-                    "properties": {
-                      "JumpDestination": {
-                        "type": "object",
+                    {
+                      "if": {
                         "properties": {
-                          "Position": {
-                            "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Vector3"
-                          },
-                          "StopDistance": {
+                          "Type": {
+                            "const": "List"
+                          }
+                        }
+                      },
+                      "then": {
+                        "properties": {
+                          "Prompt": {
                             "type": [
-                              "number",
+                              "string",
+                              "integer",
                               "null"
-                            ],
-                            "description": "Set if pathfinding should stop closer or further away from the default stop distance",
-                            "exclusiveMinimum": 0
+                            ]
                           },
-                          "DelaySeconds": {
+                          "Answer": {
                             "type": [
-                              "number",
-                              "null"
+                              "string",
+                              "integer"
                             ]
-                          },
-                          "Type": {
-                            "type": "string",
-                            "enum": [
-                              "SingleJump",
-                              "RepeatedJumps"
-                            ],
-                            "default": "SingleJump"
                           }
                         },
                         "required": [
-                          "Position"
-                        ]
-                      }
-                    },
-                    "required": [
-                      "Position",
-                      "JumpDestination"
-                    ]
-                  }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "anyOf": [
-                          {
-                            "const": "Interact"
-                          },
-                          {
-                            "const": "SinglePlayerDuty"
-                          },
-                          {
-                            "const": "WaitForManualProgress"
-                          },
-                          {
-                            "const": "AcceptQuest"
-                          },
-                          {
-                            "const": "CompleteQuest"
-                          },
-                          {
-                            "const": "Instruction"
-                          },
-                          {
-                            "const": "Say"
-                          },
-                          {
-                            "const": "Emote"
-                          },
-                          {
-                            "const": "UseItem"
-                          }
+                          "Prompt",
+                          "Answer"
                         ]
                       }
                     }
-                  },
-                  "then": {
-                    "properties": {
-                      "DialogueChoices": {
-                        "type": "array",
-                        "items": {
-                          "type": "object",
-                          "properties": {
-                            "Type": {
-                              "type": "string",
-                              "enum": [
-                                "YesNo",
-                                "List"
-                              ]
-                            },
-                            "ExcelSheet": {
-                              "type": "string"
-                            }
-                          },
-                          "required": [
-                            "Type"
-                          ],
-                          "allOf": [
-                            {
-                              "if": {
-                                "properties": {
-                                  "Type": {
-                                    "const": "YesNo"
-                                  }
-                                }
-                              },
-                              "then": {
-                                "properties": {
-                                  "Prompt": {
-                                    "type": [
-                                      "string",
-                                      "integer"
-                                    ]
-                                  },
-                                  "Yes": {
-                                    "type": "boolean",
-                                    "default": true
-                                  }
-                                },
-                                "required": [
-                                  "Prompt",
-                                  "Yes"
-                                ]
-                              }
-                            },
-                            {
-                              "if": {
-                                "properties": {
-                                  "Type": {
-                                    "const": "List"
-                                  }
-                                }
-                              },
-                              "then": {
-                                "properties": {
-                                  "Prompt": {
-                                    "type": [
-                                      "string",
-                                      "integer",
-                                      "null"
-                                    ]
-                                  },
-                                  "Answer": {
-                                    "type": [
-                                      "string",
-                                      "integer"
-                                    ]
-                                  }
-                                },
-                                "required": [
-                                  "Prompt",
-                                  "Answer"
-                                ]
-                              }
-                            }
-                          ]
-                        }
-                      },
-                      "PointMenuChoices": {
-                        "type": "array",
-                        "items": {
-                          "type": "integer",
-                          "minimum": 0
-                        }
-                      }
-                    }
-                  }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "Duty"
-                      }
-                    }
-                  },
-                  "then": {
-                    "properties": {
-                      "ContentFinderConditionId": {
-                        "type": "integer",
-                        "exclusiveMinimum": 0,
-                        "exclusiveMaximum": 3000
-                      },
-                      "DataId": {
-                        "type": "null"
-                      },
-                      "Position": {
-                        "type": "null"
-                      }
-                    },
-                    "required": [
-                      "ContentFinderConditionId"
-                    ]
-                  }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "WaitForNpcAtPosition"
-                      }
-                    }
-                  },
-                  "then": {
-                    "properties": {
-                      "NpcWaitDistance": {
-                        "type": "number",
-                        "exclusiveMinimum": 0
-                      }
-                    }
-                  }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "AcceptQuest"
-                      }
-                    }
-                  },
-                  "then": {
-                    "properties": {
-                      "PickUpQuestId": {
-                        "type": [
-                          "null",
-                          "number",
-                          "string"
-                        ],
-                        "description": "Determines the quest which should be accepted. If empty/null, accepts the quest corresponding to the file name."
-                      }
-                    }
-                  }
-                },
-                {
-                  "if": {
-                    "properties": {
-                      "InteractionType": {
-                        "const": "CompleteQuest"
-                      }
-                    }
-                  },
-                  "then": {
-                    "properties": {
-                      "TurnInQuestId": {
-                        "type": [
-                          "null",
-                          "number",
-                          "string"
-                        ],
-                        "description": "Determines the quest which should be turned in. If empty/null, turns in the quest corresponding to the file name."
-                      },
-                      "NextQuestId": {
-                        "type": [
-                          "null",
-                          "number",
-                          "string"
-                        ],
-                        "description": "For quest chains (e.g. DT healer role quests) Which quest to do next, given that you meet the required level."
-                      }
-                    }
-                  }
+                  ]
                 }
-              ],
-              "not": {
-                "anyOf": [
-                  {
-                    "required": [
-                      "SkipIf"
-                    ]
-                  }
-                ]
+              },
+              "PointMenuChoices": {
+                "type": "array",
+                "items": {
+                  "type": "integer",
+                  "minimum": 0
+                }
+              }
+            }
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "Duty"
               }
             }
           },
-          "Comment": {
-            "type": "string"
+          "then": {
+            "properties": {
+              "ContentFinderConditionId": {
+                "type": "integer",
+                "exclusiveMinimum": 0,
+                "exclusiveMaximum": 3000
+              },
+              "DataId": {
+                "type": "null"
+              },
+              "Position": {
+                "type": "null"
+              }
+            },
+            "required": [
+              "ContentFinderConditionId"
+            ]
           }
         },
-        "required": [
-          "Sequence"
-        ],
-        "additionalProperties": false
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "WaitForNpcAtPosition"
+              }
+            }
+          },
+          "then": {
+            "properties": {
+              "NpcWaitDistance": {
+                "type": "number",
+                "exclusiveMinimum": 0
+              }
+            }
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "AcceptQuest"
+              }
+            }
+          },
+          "then": {
+            "properties": {
+              "PickUpQuestId": {
+                "type": [
+                  "null",
+                  "number",
+                  "string"
+                ],
+                "description": "Determines the quest which should be accepted. If empty/null, accepts the quest corresponding to the file name."
+              }
+            }
+          }
+        },
+        {
+          "if": {
+            "properties": {
+              "InteractionType": {
+                "const": "CompleteQuest"
+              }
+            }
+          },
+          "then": {
+            "properties": {
+              "TurnInQuestId": {
+                "type": [
+                  "null",
+                  "number",
+                  "string"
+                ],
+                "description": "Determines the quest which should be turned in. If empty/null, turns in the quest corresponding to the file name."
+              },
+              "NextQuestId": {
+                "type": [
+                  "null",
+                  "number",
+                  "string"
+                ],
+                "description": "For quest chains (e.g. DT healer role quests) Which quest to do next, given that you meet the required level."
+              }
+            }
+          }
+        }
+      ],
+      "not": {
+        "anyOf": [
+          {
+            "required": [
+              "SkipIf"
+            ]
+          }
+        ]
       }
     }
-  },
-  "required": [
-    "$schema",
-    "QuestSequence",
-    "Author"
-  ],
-  "additionalProperties": false
+  }
 }
index 3313d4df37eef4c0dd42084c8d2b00f604a5e914..875e1a5f425c45ad100c99cae0056011cfbd78bc 100644 (file)
@@ -87,6 +87,15 @@ public enum EAetheryteLocation
     IshgardGatesOfJudgement = 88,
     IshgardFirmament = 100001,
 
+    FirmamentMendicantsCourt = 2011373,
+    FirmamentMattock = 2011374,
+    FirmamentNewNest = 2011384,
+    FirmanentSaintRoellesDais = 2011385,
+    FirmamentFeatherfall = 2011386,
+    FirmamentHoarfrostHall = 2011387,
+    FirmamentWesternRisensongQuarter = 2011388,
+    FIrmamentEasternRisensongQuarter = 2011389,
+
     Idyllshire = 75,
     IdyllshireWest = 90,
     IdyllshirePrologueGate = 91,
@@ -251,3 +260,17 @@ public enum EAetheryteLocation
     LivingMemoryLeynodePyro = 214,
     LivingMemoryLeynodeAero = 215,
 }
+
+public static class EAetheryteLocationExtensions
+{
+    public static bool IsFirmamentAetheryte(this EAetheryteLocation aetheryteLocation) =>
+        aetheryteLocation is EAetheryteLocation.IshgardFirmament
+            or EAetheryteLocation.FirmamentMendicantsCourt
+            or EAetheryteLocation.FirmamentMattock
+            or EAetheryteLocation.FirmamentNewNest
+            or EAetheryteLocation.FirmanentSaintRoellesDais
+            or EAetheryteLocation.FirmamentFeatherfall
+            or EAetheryteLocation.FirmamentHoarfrostHall
+            or EAetheryteLocation.FirmamentWesternRisensongQuarter
+            or EAetheryteLocation.FIrmamentEasternRisensongQuarter;
+}
index c76f45c77c2784be4f8040d34bcaf4a1d14cc792..52da35eb24774eee7a754ea9f8ee292bf80dc02a 100644 (file)
@@ -2,6 +2,7 @@
 using System.Text.Json.Serialization;
 using Questionable.Model.Common;
 using Questionable.Model.Common.Converter;
+using Questionable.Model.Questing;
 using Questionable.Model.Questing.Converter;
 
 namespace Questionable.Model.Gathering;
@@ -10,12 +11,8 @@ public sealed class GatheringRoot
 {
     [JsonConverter(typeof(StringListOrValueConverter))]
     public List<string> Author { get; set; } = [];
-    public ushort TerritoryId { get; set; }
 
-    [JsonConverter(typeof(AetheryteConverter))]
-    public EAetheryteLocation? AetheryteShortcut { get; set; }
-
-    public AethernetShortcut? AethernetShortcut { get; set; }
+    public List<QuestStep> Steps { get; set; } = [];
     public bool? FlyBetweenNodes { get; set; }
     public List<GatheringNodeGroup> Groups { get; set; } = [];
 }
index b1560c7c551e7dd654df726444008e9c10bc158e..6b5e583492e12fa55c1a0673476202f8a81c1e91 100644 (file)
@@ -58,6 +58,15 @@ public sealed class AethernetShardConverter() : EnumConverter<EAetheryteLocation
         { EAetheryteLocation.IshgardGatesOfJudgement, "[Ishgard] The Gates of Judgement (Coerthas Central Highlands)" },
         { EAetheryteLocation.IshgardFirmament, "[Ishgard] Firmament" },
 
+        { EAetheryteLocation.FirmamentMendicantsCourt, "[Firmament] The Mendicant's Court" },
+        { EAetheryteLocation.FirmamentMattock, "[Firmament] The Mattock" },
+        { EAetheryteLocation.FirmamentNewNest, "[Firmament] The New Nest" },
+        { EAetheryteLocation.FirmanentSaintRoellesDais, "[Firmament] Saint Roelle's Dais" },
+        { EAetheryteLocation.FirmamentFeatherfall, "[Firmament] Featherfall" },
+        { EAetheryteLocation.FirmamentHoarfrostHall, "[Firmament] Hoarfrost Hall" },
+        { EAetheryteLocation.FirmamentWesternRisensongQuarter, "[Firmament] Western Risensong Quarter" },
+        { EAetheryteLocation.FIrmamentEasternRisensongQuarter, "[Firmament] Eastern Risensong Quarter" },
+
         { EAetheryteLocation.Idyllshire, "[Idyllshire] Aetheryte Plaza" },
         { EAetheryteLocation.IdyllshireWest, "[Idyllshire] West Idyllshire" },
         { EAetheryteLocation.IdyllshirePrologueGate, "[Idyllshire] Prologue Gate (Western Hinterlands)" },
index 825f4615cbe95c77f1e93347199498fe64387dea..112085beb941a70b79722f6e2e250308b0cfcf31 100644 (file)
         "[Ishgard] The Last Vigil",
         "[Ishgard] The Gates of Judgement (Coerthas Central Highlands)",
         "[Ishgard] Firmament",
+        "[Firmament] The Mendicant's Court",
+        "[Firmament] The Mattock",
+        "[Firmament] The New Nest",
+        "[Firmament] Saint Roelle's Dais",
+        "[Firmament] Featherfall",
+        "[Firmament] Hoarfrost Hall",
+        "[Firmament] Western Risensong Quarter",
+        "[Firmament] Eastern Risensong Quarter",
         "[Idyllshire] Aetheryte Plaza",
         "[Idyllshire] West Idyllshire",
         "[Idyllshire] Prologue Gate (Western Hinterlands)",
index 22f6506d9af61f442a6040fd2c780adeff4088d5..d9e6e2549bcee3033eaf3adfec7203c127822c93 100644 (file)
@@ -20,7 +20,9 @@ using Questionable.Controller.Steps.Interactions;
 using Questionable.Data;
 using Questionable.Functions;
 using Questionable.Model;
+using Questionable.Model.Common;
 using Questionable.Model.Questing;
+using AethernetShortcut = Questionable.Controller.Steps.Shared.AethernetShortcut;
 using Quest = Questionable.Model.Quest;
 using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
 
@@ -88,6 +90,7 @@ internal sealed class GameUiController : IDisposable
         _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "HousingSelectBlock", HousingSelectBlockPostSetup);
         _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "JournalResult", JournalResultPostSetup);
         _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "GuildLeve", GuildLevePostSetup);
+        _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "TelepotTown", TeleportTownPostSetup);
     }
 
     private bool ShouldHandleUiInteractions => _isInitialCheck || _questController.IsRunning;
@@ -916,6 +919,46 @@ internal sealed class GameUiController : IDisposable
         addon->Close(true);
     }
 
+    private void TeleportTownPostSetup(AddonEvent type, AddonArgs args)
+    {
+        if (ShouldHandleUiInteractions &&
+            _questController.HasCurrentTaskMatching(out AethernetShortcut.UseAethernetShortcut? aethernetShortcut) &&
+            aethernetShortcut.From.IsFirmamentAetheryte())
+        {
+            // this might be better via atkvalues; but this works for now
+            uint toIndex = aethernetShortcut.To switch
+            {
+                EAetheryteLocation.FirmamentMendicantsCourt => 0,
+                EAetheryteLocation.FirmamentMattock => 1,
+                EAetheryteLocation.FirmamentNewNest => 2,
+                EAetheryteLocation.FirmanentSaintRoellesDais => 3,
+                EAetheryteLocation.FirmamentFeatherfall => 4,
+                EAetheryteLocation.FirmamentHoarfrostHall => 5,
+                EAetheryteLocation.FirmamentWesternRisensongQuarter => 6,
+                EAetheryteLocation.FIrmamentEasternRisensongQuarter => 7,
+                _ => uint.MaxValue,
+            };
+
+            if (toIndex == uint.MaxValue)
+                return;
+
+            _logger.LogInformation("Teleporting to {ToName} with menu index {ToIndex}", aethernetShortcut.From,
+                toIndex);
+            unsafe
+            {
+                var teleportToDestination = stackalloc AtkValue[]
+                {
+                    new() { Type = ValueType.Int, Int = 11 },
+                    new() { Type = ValueType.UInt, UInt = toIndex }
+                };
+
+                var addon = (AtkUnitBase*)args.Addon;
+                addon->FireCallback(2, teleportToDestination);
+                addon->FireCallback(2, teleportToDestination, true);
+            }
+        }
+    }
+
     private StringOrRegex? ResolveReference(Quest? quest, string? excelSheet, ExcelRef? excelRef, bool isRegExp)
     {
         if (excelRef == null)
@@ -933,6 +976,7 @@ internal sealed class GameUiController : IDisposable
 
     public void Dispose()
     {
+        _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "TelepotTown", TeleportTownPostSetup);
         _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "GuildLeve", GuildLevePostSetup);
         _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "JournalResult", JournalResultPostSetup);
         _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "HousingSelectBlock", HousingSelectBlockPostSetup);
index f5a517fa72bdca4868cbbd886d1fc18290ff5863..aeb837d9662259cc5d469552d3738affd39fd4ee 100644 (file)
@@ -151,11 +151,12 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
         if (currentNode == null)
             return;
 
+        ushort territoryId = _currentRequest.Root.Steps.Last().TerritoryId;
         _taskQueue.Enqueue(_serviceProvider.GetRequiredService<MountTask>()
-            .With(_currentRequest.Root.TerritoryId, MountTask.EMountIf.Always));
+            .With(territoryId, MountTask.EMountIf.Always));
 
         bool fly = currentNode.Fly.GetValueOrDefault(_currentRequest.Root.FlyBetweenNodes.GetValueOrDefault(true)) &&
-                   _gameFunctions.IsFlyingUnlocked(_currentRequest.Root.TerritoryId);
+                   _gameFunctions.IsFlyingUnlocked(territoryId);
         if (currentNode.Locations.Count > 1)
         {
             Vector3 averagePosition = new Vector3
@@ -170,12 +171,12 @@ internal sealed unsafe class GatheringController : MiniTaskController<GatheringC
                 pointOnFloor = pointOnFloor.Value with { Y = pointOnFloor.Value.Y + (fly ? 3f : 0f) };
 
             _taskQueue.Enqueue(_serviceProvider.GetRequiredService<Move.MoveInternal>()
-                .With(_currentRequest.Root.TerritoryId, pointOnFloor ?? averagePosition, 50f, fly: fly,
+                .With(territoryId, pointOnFloor ?? averagePosition, 50f, fly: fly,
                     ignoreDistanceToObject: true));
         }
 
         _taskQueue.Enqueue(_serviceProvider.GetRequiredService<MoveToLandingLocation>()
-            .With(_currentRequest.Root.TerritoryId, fly, currentNode));
+            .With(territoryId, fly, currentNode));
         _taskQueue.Enqueue(_serviceProvider.GetRequiredService<Interact.DoInteract>()
             .With(currentNode.DataId, null, EInteractionType.InternalGather, true));
 
index ea397d841437d34a477435db71df154a65a7e843..a9cc655001f3da2b7398faebba725319a22b01f1 100644 (file)
@@ -35,7 +35,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
     private readonly IToastGui _toastGui;
     private readonly Configuration _configuration;
     private readonly YesAlreadyIpc _yesAlreadyIpc;
-    private readonly IReadOnlyList<ITaskFactory> _taskFactories;
+    private readonly TaskCreator _taskCreator;
 
     private readonly object _progressLock = new();
 
@@ -73,7 +73,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
         IToastGui toastGui,
         Configuration configuration,
         YesAlreadyIpc yesAlreadyIpc,
-        IEnumerable<ITaskFactory> taskFactories)
+        TaskCreator taskCreator)
         : base(chatGui, logger)
     {
         _clientState = clientState;
@@ -88,7 +88,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
         _toastGui = toastGui;
         _configuration = configuration;
         _yesAlreadyIpc = yesAlreadyIpc;
-        _taskFactories = taskFactories.ToList().AsReadOnly();
+        _taskCreator = taskCreator;
 
         _condition.ConditionChange += OnConditionChange;
         _toastGui.Toast += OnNormalToast;
@@ -607,34 +607,7 @@ internal sealed class QuestController : MiniTaskController<QuestController>, IDi
 
         try
         {
-            var newTasks = _taskFactories
-                .SelectMany(x =>
-                {
-                    IList<ITask> tasks = x.CreateAllTasks(CurrentQuest.Quest, seq, step).ToList();
-
-                    if (tasks.Count > 0 && _logger.IsEnabled(LogLevel.Trace))
-                    {
-                        string factoryName = x.GetType().FullName ?? x.GetType().Name;
-                        if (factoryName.Contains('.', StringComparison.Ordinal))
-                            factoryName = factoryName[(factoryName.LastIndexOf('.') + 1)..];
-
-                        _logger.LogTrace("Factory {FactoryName} created Task {TaskNames}",
-                            factoryName, string.Join(", ", tasks.Select(y => y.ToString())));
-                    }
-
-                    return tasks;
-                })
-                .ToList();
-            if (newTasks.Count == 0)
-            {
-                _logger.LogInformation("Nothing to execute for step?");
-                return;
-            }
-
-            _logger.LogInformation("Tasks for {QuestId}, {Sequence}, {Step}: {Tasks}",
-                CurrentQuest.Quest.Id, seq.Sequence, seq.Steps.IndexOf(step),
-                string.Join(", ", newTasks.Select(x => x.ToString())));
-            foreach (var task in newTasks)
+            foreach (var task in _taskCreator.CreateTasks(CurrentQuest.Quest, seq, step))
                 _taskQueue.Enqueue(task);
         }
         catch (Exception e)
index 6e7ad1649708e7465dec21197dbcc6917e399928..1c45596db0cc28b8b642fe272f54a1d594e5651f 100644 (file)
@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Numerics;
 using Dalamud.Game.ClientState.Conditions;
+using Dalamud.Game.ClientState.Objects.Enums;
 using Dalamud.Plugin.Services;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
@@ -102,12 +103,9 @@ internal static class AethernetShortcut
                 if (aetheryteData.CalculateDistance(playerPosition, territoryType, From) <
                     aetheryteData.CalculateDistance(playerPosition, territoryType, To))
                 {
-                    if (aetheryteData.CalculateDistance(playerPosition, territoryType, From) < 11)
+                    if (aetheryteData.CalculateDistance(playerPosition, territoryType, From) < (From.IsFirmamentAetheryte() ? 11f : 4f))
                     {
-                        logger.LogInformation("Using lifestream to teleport to {Destination}", To);
-                        lifestreamIpc.Teleport(To);
-
-                        _teleported = true;
+                        DoTeleport();
                         return true;
                     }
                     else if (From == EAetheryteLocation.SolutionNine)
@@ -141,7 +139,7 @@ internal static class AethernetShortcut
                             }
                         }
 
-                        MoveTo(From);
+                        MoveTo();
                         return true;
                     }
                 }
@@ -154,13 +152,32 @@ internal static class AethernetShortcut
             return false;
         }
 
-        private void MoveTo(EAetheryteLocation from)
+        private void MoveTo()
         {
             logger.LogInformation("Moving to aethernet shortcut");
             _moving = true;
             movementController.NavigateTo(EMovementType.Quest, (uint)From, aetheryteData.Locations[From],
                 false, true,
-                AetheryteConverter.IsLargeAetheryte(From) ? 10.9f : 6.9f);
+                From.IsFirmamentAetheryte()
+                    ? 4.4f
+                    : AetheryteConverter.IsLargeAetheryte(From)
+                        ? 10.9f
+                        : 6.9f);
+        }
+
+        private void DoTeleport()
+        {
+            if (From.IsFirmamentAetheryte())
+            {
+                logger.LogInformation("Using manual teleport interaction");
+                _teleported = gameFunctions.InteractWith((uint)From, ObjectKind.EventObj);
+            }
+            else
+            {
+                logger.LogInformation("Using lifestream to teleport to {Destination}", To);
+                lifestreamIpc.Teleport(To);
+                _teleported = true;
+            }
         }
 
         public ETaskResult Update()
@@ -173,7 +190,7 @@ internal static class AethernetShortcut
                 if (condition[ConditionFlag.Mounted])
                 {
                     _triedMounting = false;
-                    MoveTo(From);
+                    MoveTo();
                     return ETaskResult.StillRunning;
                 }
                 else
@@ -194,10 +211,7 @@ internal static class AethernetShortcut
 
             if (!_teleported)
             {
-                logger.LogInformation("Using lifestream to teleport to {Destination}", To);
-                lifestreamIpc.Teleport(To);
-
-                _teleported = true;
+                DoTeleport();
                 return ETaskResult.StillRunning;
             }
 
index 7817f49ca8b478b2ca3771a72e3a804c02824f0a..f9af944ddc417b5631f66d30ca2c64810f484d24 100644 (file)
@@ -1,13 +1,14 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using Dalamud.Game.Text;
 using Dalamud.Plugin.Services;
 using FFXIVClientStructs.FFXIV.Client.Game;
 using LLib.GameData;
 using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
 using Questionable.Controller.Steps.Common;
 using Questionable.Data;
-using Questionable.GatheringPaths;
 using Questionable.Model;
 using Questionable.Model.Gathering;
 using Questionable.Model.Questing;
@@ -23,7 +24,7 @@ internal static class GatheringRequiredItems
         IClientState clientState,
         GatheringData gatheringData,
         TerritoryData territoryData,
-        AetheryteData aetheryteData) : ITaskFactory
+        ILogger<Factory> logger) : ITaskFactory
     {
         public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
         {
@@ -50,24 +51,25 @@ internal static class GatheringRequiredItems
                 if (HasRequiredItems(requiredGatheredItems))
                     continue;
 
-                if (gatheringRoot.AetheryteShortcut != null && clientState.TerritoryType != gatheringRoot.TerritoryId)
+                using (var _ = logger.BeginScope("Gathering(inner)"))
                 {
-                    ushort expectedTerritoryId = gatheringRoot.TerritoryId;
-                    if (gatheringRoot.AethernetShortcut != null)
-                        expectedTerritoryId = aetheryteData.TerritoryIds[gatheringRoot.AethernetShortcut.From];
-
-                    yield return serviceProvider.GetRequiredService<AetheryteShortcut.UseAetheryteShortcut>()
-                        .With(null, gatheringRoot.AetheryteShortcut.Value, expectedTerritoryId);
-                }
-
-                if (gatheringRoot.AethernetShortcut != null)
-                {
-                    yield return serviceProvider.GetRequiredService<AethernetShortcut.UseAethernetShortcut>()
-                        .With(gatheringRoot.AethernetShortcut.From, gatheringRoot.AethernetShortcut.To);
+                    QuestSequence gatheringSequence = new QuestSequence
+                    {
+                        Sequence = 0,
+                        Steps = gatheringRoot.Steps
+                    };
+                    foreach (var gatheringStep in gatheringSequence.Steps)
+                    {
+                        foreach (var task in serviceProvider.GetRequiredService<TaskCreator>()
+                                     .CreateTasks(quest, gatheringSequence, gatheringStep))
+                            if (task is not WaitAtEnd.NextStep)
+                                yield return task;
+                    }
                 }
 
-                yield return new WaitConditionTask(() => clientState.TerritoryType == gatheringRoot.TerritoryId,
-                    $"Wait(territory: {territoryData.GetNameAndId(gatheringRoot.TerritoryId)})");
+                ushort territoryId = gatheringRoot.Steps.Last().TerritoryId;
+                yield return new WaitConditionTask(() => clientState.TerritoryType == territoryId,
+                    $"Wait(territory: {territoryData.GetNameAndId(territoryId)})");
 
                 yield return new WaitConditionTask(() => movementController.IsNavmeshReady,
                     "Wait(navmesh ready)");
diff --git a/Questionable/Controller/Steps/TaskCreator.cs b/Questionable/Controller/Steps/TaskCreator.cs
new file mode 100644 (file)
index 0000000..c5e8255
--- /dev/null
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Extensions.Logging;
+using Questionable.Model;
+using Questionable.Model.Questing;
+
+namespace Questionable.Controller.Steps;
+
+internal sealed class TaskCreator
+{
+    private readonly IReadOnlyList<ITaskFactory> _taskFactories;
+    private readonly ILogger<TaskCreator> _logger;
+
+    public TaskCreator(IEnumerable<ITaskFactory> taskFactories, ILogger<TaskCreator> logger)
+    {
+        _taskFactories = taskFactories.ToList().AsReadOnly();
+        _logger = logger;
+    }
+
+    public IReadOnlyList<ITask> CreateTasks(Quest quest, QuestSequence sequence, QuestStep step)
+    {
+        var newTasks = _taskFactories
+            .SelectMany(x =>
+            {
+                IList<ITask> tasks = x.CreateAllTasks(quest, sequence, step).ToList();
+
+                if (tasks.Count > 0 && _logger.IsEnabled(LogLevel.Trace))
+                {
+                    string factoryName = x.GetType().FullName ?? x.GetType().Name;
+                    if (factoryName.Contains('.', StringComparison.Ordinal))
+                        factoryName = factoryName[(factoryName.LastIndexOf('.') + 1)..];
+
+                    _logger.LogTrace("Factory {FactoryName} created Task {TaskNames}",
+                        factoryName, string.Join(", ", tasks.Select(y => y.ToString())));
+                }
+
+                return tasks;
+            })
+            .ToList();
+        if (newTasks.Count == 0)
+            _logger.LogInformation("Nothing to execute for step?");
+        else
+        {
+            _logger.LogInformation("Tasks for {QuestId}, {Sequence}, {Step}: {Tasks}",
+                quest.Id, sequence.Sequence, sequence.Steps.IndexOf(step),
+                string.Join(", ", newTasks.Select(x => x.ToString())));
+        }
+
+        return newTasks;
+    }
+}
index 74d183130346df9a5388d5e2649c2e8a9497639c..b843c70da8fc27e0aeec268fba2f3fbf67124000 100644 (file)
@@ -3,6 +3,7 @@ using System.Collections.ObjectModel;
 using System.Linq;
 using System.Numerics;
 using Dalamud.Plugin.Services;
+using Dalamud.Utility;
 using Lumina.Excel.GeneratedSheets;
 using Questionable.Model.Common;
 
@@ -14,7 +15,25 @@ internal sealed class AetheryteData
     {
         Dictionary<EAetheryteLocation, string> aethernetNames = new();
         Dictionary<EAetheryteLocation, ushort> territoryIds = new();
-        Dictionary<EAetheryteLocation, byte> aethernetGroups = new();
+        Dictionary<EAetheryteLocation, ushort> aethernetGroups = new();
+
+
+        void ConfigureAetheryte(EAetheryteLocation aetheryteLocation, string name, ushort territoryId,
+            ushort aethernetGroup)
+        {
+            aethernetNames[aetheryteLocation] = name;
+            territoryIds[aetheryteLocation] = territoryId;
+            aethernetGroups[aetheryteLocation] = aethernetGroup;
+        }
+
+        void ConfigureAetheryteWithPlaceName(EAetheryteLocation aetheryteLocation, uint placeNameId, ushort territoryId)
+        {
+            ConfigureAetheryte(aetheryteLocation,
+                dataManager.GetExcelSheet<PlaceName>()!.GetRow(placeNameId)!.Name.ToDalamudString().TextValue,
+                territoryId,
+                (ushort)((int)aetheryteLocation / 100));
+        }
+
         foreach (var aetheryte in dataManager.GetExcelSheet<Aetheryte>()!.Where(x => x.RowId > 0))
         {
             string? aethernetName = aetheryte.AethernetName?.Value?.Name.ToString();
@@ -28,9 +47,16 @@ internal sealed class AetheryteData
                 aethernetGroups[(EAetheryteLocation)aetheryte.RowId] = aetheryte.AethernetGroup;
         }
 
-        aethernetNames[EAetheryteLocation.IshgardFirmament] = "Firmament";
-        territoryIds[EAetheryteLocation.IshgardFirmament] = 886;
-        aethernetGroups[EAetheryteLocation.IshgardFirmament] = aethernetGroups[EAetheryteLocation.Ishgard];
+        ConfigureAetheryte(EAetheryteLocation.IshgardFirmament, "Firmament", 886,
+            aethernetGroups[EAetheryteLocation.Ishgard]);
+        ConfigureAetheryteWithPlaceName(EAetheryteLocation.FirmamentMendicantsCourt, 3436, 886);
+        ConfigureAetheryteWithPlaceName(EAetheryteLocation.FirmamentMattock, 3473, 886);
+        ConfigureAetheryteWithPlaceName(EAetheryteLocation.FirmamentNewNest, 3475, 886);
+        ConfigureAetheryteWithPlaceName(EAetheryteLocation.FirmanentSaintRoellesDais, 3474, 886);
+        ConfigureAetheryteWithPlaceName(EAetheryteLocation.FirmamentFeatherfall, 3525, 886);
+        ConfigureAetheryteWithPlaceName(EAetheryteLocation.FirmamentHoarfrostHall, 3528, 886);
+        ConfigureAetheryteWithPlaceName(EAetheryteLocation.FirmamentWesternRisensongQuarter, 3646, 886);
+        ConfigureAetheryteWithPlaceName(EAetheryteLocation.FIrmamentEasternRisensongQuarter, 3645, 886);
 
         AethernetNames = aethernetNames.AsReadOnly();
         TerritoryIds = territoryIds.AsReadOnly();
@@ -207,6 +233,15 @@ internal sealed class AetheryteData
                 { EAetheryteLocation.RadzAtHanKama, new(129.59485f, 26.993164f, 13.473633f) },
                 { EAetheryteLocation.RadzAtHanHighCrucible, new(57.90796f, -24.704407f, -210.6203f) },
 
+                { EAetheryteLocation.FirmamentMendicantsCourt, new(23.941406f, -16.006714f, 169.35986f) },
+                { EAetheryteLocation.FirmamentMattock, new(76.035645f, -18.509216f, 10.299805f) },
+                { EAetheryteLocation.FirmamentNewNest, new(149.49255f, -50.003845f, 98.55798f) },
+                { EAetheryteLocation.FirmanentSaintRoellesDais, new(207.75159f, -40.024475f, -25.589417f) },
+                { EAetheryteLocation.FirmamentFeatherfall, new(-78.78235f, -0.015319824f, 75.97461f) },
+                { EAetheryteLocation.FirmamentHoarfrostHall, new(-132.55518f, 9.964111f, -14.66394f) },
+                { EAetheryteLocation.FirmamentWesternRisensongQuarter, new(-91.722046f, -0.015319824f, -115.19043f) },
+                { EAetheryteLocation.FIrmamentEasternRisensongQuarter, new(114.3053f, -20.004639f, -107.43884f) },
+
                 { EAetheryteLocation.LabyrinthosArcheion, new(443.5338f, 170.6416f, -476.18835f) },
                 { EAetheryteLocation.LabyrinthosSharlayanHamlet, new(8.377136f, -27.542603f, -46.67737f) },
                 { EAetheryteLocation.LabyrinthosAporia, new(-729.18286f, -27.634155f, 302.1438f) },
@@ -276,7 +311,7 @@ internal sealed class AetheryteData
 
     public ReadOnlyDictionary<EAetheryteLocation, string> AethernetNames { get; }
     public ReadOnlyDictionary<EAetheryteLocation, ushort> TerritoryIds { get; }
-    public ReadOnlyDictionary<EAetheryteLocation, byte> AethernetGroups { get; }
+    public ReadOnlyDictionary<EAetheryteLocation, ushort> AethernetGroups { get; }
     public IReadOnlyList<ushort> TownTerritoryIds { get; set; }
 
     public float CalculateDistance(Vector3 fromPosition, ushort fromTerritoryType, EAetheryteLocation to)
index 0388b024672248587f2cb7164410994392c2b8b1..afdedf4d8382a490c3fa29ed3288606dae465a72 100644 (file)
@@ -41,7 +41,7 @@ internal sealed unsafe class AetheryteFunctions
 
     public bool IsAetheryteUnlocked(EAetheryteLocation aetheryteLocation)
     {
-        if (aetheryteLocation == EAetheryteLocation.IshgardFirmament)
+        if (aetheryteLocation.IsFirmamentAetheryte())
             return _serviceProvider.GetRequiredService<QuestFunctions>().IsQuestComplete(new QuestId(3672));
         return IsAetheryteUnlocked((uint)aetheryteLocation, out _);
     }
index 9be89b8b4db0e9c2654badc9d6036f30a79cdccb..e51c7b3ff453d56725ad78ae1b1acae9105f4e2f 100644 (file)
@@ -171,6 +171,8 @@ public sealed class QuestionablePlugin : IDalamudPlugin
                 WaitAtEnd.WaitObjectAtPosition>();
         serviceCollection.AddTransient<WaitAtEnd.WaitQuestAccepted>();
         serviceCollection.AddTransient<WaitAtEnd.WaitQuestCompleted>();
+
+        serviceCollection.AddSingleton<TaskCreator>();
     }
 
     private static void AddControllers(ServiceCollection serviceCollection)
index 13a00aa870c9d32d093397bac499741816cf3d3b..2dd107f7210ef6c0bfd73fb635cd2e788cef589b 100644 (file)
@@ -29,8 +29,8 @@ internal sealed class AethernetShortcutValidator : IQuestValidator
         if (aethernetShortcut == null)
             return null;
 
-        byte fromGroup = _aetheryteData.AethernetGroups.GetValueOrDefault(aethernetShortcut.From);
-        byte toGroup = _aetheryteData.AethernetGroups.GetValueOrDefault(aethernetShortcut.To);
+        ushort fromGroup = _aetheryteData.AethernetGroups.GetValueOrDefault(aethernetShortcut.From);
+        ushort toGroup = _aetheryteData.AethernetGroups.GetValueOrDefault(aethernetShortcut.To);
         if (fromGroup != toGroup)
         {
             return new ValidationIssue