"ecommons": {
         "type": "Project"
       },
-      "gatheringpaths": {
-        "type": "Project",
-        "dependencies": {
-          "Questionable.Model": "[1.0.0, )"
-        }
-      },
       "questionable.model": {
         "type": "Project",
         "dependencies": {
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
+  "Author": "liza",
+  "TerritoryId": 614,
+  "AetheryteShortcut": "Yanxia - Namai",
+  "Groups": [
+    {
+      "Nodes": [
+        {
+          "DataId": 33334,
+          "Locations": [
+            {
+              "Position": {
+                "X": -222.386,
+                "Y": 23.28162,
+                "Z": 425.76
+              }
+            },
+            {
+              "Position": {
+                "X": -209.1725,
+                "Y": 22.35068,
+                "Z": 425.5524
+              }
+            }
+          ]
+        },
+        {
+          "DataId": 33333,
+          "Locations": [
+            {
+              "Position": {
+                "X": -219.9592,
+                "Y": 22.78741,
+                "Z": 431.5036
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "Nodes": [
+        {
+          "DataId": 33335,
+          "Locations": [
+            {
+              "Position": {
+                "X": -349.8553,
+                "Y": 33.90925,
+                "Z": 452.5893
+              },
+              "MinimumAngle": -90,
+              "MaximumAngle": 90
+            }
+          ]
+        },
+        {
+          "DataId": 33336,
+          "Locations": [
+            {
+              "Position": {
+                "X": -361.5062,
+                "Y": 33.49068,
+                "Z": 453.4639
+              }
+            },
+            {
+              "Position": {
+                "X": -359.826,
+                "Y": 35.47207,
+                "Z": 442.164
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "Nodes": [
+        {
+          "DataId": 33331,
+          "Locations": [
+            {
+              "Position": {
+                "X": -231.3864,
+                "Y": 17.74118,
+                "Z": 511.0694
+              }
+            }
+          ]
+        },
+        {
+          "DataId": 33332,
+          "Locations": [
+            {
+              "Position": {
+                "X": -219.0789,
+                "Y": 18.05494,
+                "Z": 525.418
+              }
+            },
+            {
+              "Position": {
+                "X": -220.9139,
+                "Y": 17.97838,
+                "Z": 514.0063
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1012299,
+          "Position": {
+            "X": -16.586609,
+            "Y": 206.49942,
+            "Z": 42.98462
+          },
+          "TerritoryId": 478,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1019615,
+          "Position": {
+            "X": -71.763245,
+            "Y": 206.50021,
+            "Z": 32.638916
+          },
+          "StopDistance": 5,
+          "TerritoryId": 478,
+          "InteractionType": "CompleteQuest"
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "Position": {
+            "X": -71.31451,
+            "Y": 206.56206,
+            "Z": 29.3684
+          },
+          "TerritoryId": 478,
+          "InteractionType": "WalkTo",
+          "RequiredGatheredItems": [],
+          "AetheryteShortcut": "Idyllshire"
+        },
+        {
+          "DataId": 1019615,
+          "Position": {
+            "X": -71.763245,
+            "Y": 206.50021,
+            "Z": 32.638916
+          },
+          "StopDistance": 5,
+          "TerritoryId": 478,
+          "InteractionType": "Interact"
+        }
+      ]
+    }
+  ]
+}
 
+++ /dev/null
-{
-  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
-  "Author": "liza",
-  "QuestSequence": [
-    {
-      "Sequence": 0,
-      "Steps": [
-        {
-          "DataId": 1012299,
-          "Position": {
-            "X": -16.586609,
-            "Y": 206.49942,
-            "Z": 42.98462
-          },
-          "TerritoryId": 478,
-          "InteractionType": "AcceptQuest"
-        }
-      ]
-    },
-    {
-      "Sequence": 255,
-      "Steps": [
-        {
-          "DataId": 1019615,
-          "Position": {
-            "X": -71.763245,
-            "Y": 206.50021,
-            "Z": 32.638916
-          },
-          "StopDistance": 5,
-          "TerritoryId": 478,
-          "InteractionType": "CompleteQuest"
-        }
-      ]
-    }
-  ]
-}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1018393,
+          "Position": {
+            "X": -60.380005,
+            "Y": 206.50021,
+            "Z": 26.16919
+          },
+          "TerritoryId": 478,
+          "InteractionType": "Interact",
+          "RequiredGatheredItems": [],
+          "AetheryteShortcut": "Idyllshire"
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1025878,
+          "Position": {
+            "X": 343.984,
+            "Y": -120.32947,
+            "Z": -306.0197
+          },
+          "TerritoryId": 613,
+          "InteractionType": "Interact",
+          "RequiredGatheredItems": [],
+          "AetheryteShortcut": "Ruby Sea - Tamamizu"
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1020337,
+          "Position": {
+            "X": 171.31299,
+            "Y": 13.02367,
+            "Z": -89.951965
+          },
+          "TerritoryId": 635,
+          "InteractionType": "Interact",
+          "RequiredGatheredItems": [],
+          "AetheryteShortcut": "Rhalgr's Reach"
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1035211,
+          "Position": {
+            "X": -116.96039,
+            "Y": 0,
+            "Z": -133.95898
+          },
+          "TerritoryId": 886,
+          "InteractionType": "Interact",
+          "AetheryteShortcut": "Ishgard",
+          "AethernetShortcut": [
+            "[Ishgard] Aetheryte Plaza",
+            "[Ishgard] Firmament"
+          ]
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1033543,
+          "Position": {
+            "X": 113.38977,
+            "Y": -20,
+            "Z": -0.96136475
+          },
+          "TerritoryId": 886,
+          "InteractionType": "Interact",
+          "AetheryteShortcut": "Ishgard",
+          "AethernetShortcut": [
+            "[Ishgard] Aetheryte Plaza",
+            "[Ishgard] Firmament"
+          ]
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1031801,
+          "Position": {
+            "X": 52.8114,
+            "Y": 83.001076,
+            "Z": -65.38495
+          },
+          "TerritoryId": 820,
+          "InteractionType": "Interact",
+          "RequiredGatheredItems": [],
+          "AetheryteShortcut": "Eulmore"
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1042241,
+          "Position": {
+            "X": 222.85791,
+            "Y": 24.942732,
+            "Z": -197.77222
+          },
+          "TerritoryId": 962,
+          "InteractionType": "Interact",
+          "RequiredGatheredItems": [],
+          "AetheryteShortcut": "Old Sharlayan",
+          "AethernetShortcut": [
+            "[Old Sharlayan] Aetheryte Plaza",
+            "[Old Sharlayan] The Leveilleur Estate"
+          ]
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1044547,
+          "Position": {
+            "X": -241.68768,
+            "Y": 51.058994,
+            "Z": 620.8744
+          },
+          "TerritoryId": 816,
+          "InteractionType": "Interact",
+          "RequiredGatheredItems": [],
+          "AetheryteShortcut": "Il Mheg - Lydha Lran",
+          "Fly": true
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "Position": {
+            "X": -44.066154,
+            "Y": -29.530005,
+            "Z": -55.85129
+          },
+          "TerritoryId": 956,
+          "InteractionType": "WalkTo",
+          "AetheryteShortcut": "Labyrinthos - Sharlayan Hamlet",
+          "RequiredGatheredItems": [],
+          "Fly": true
+        },
+        {
+          "DataId": 1046073,
+          "Position": {
+            "X": -53.635498,
+            "Y": -29.497286,
+            "Z": -65.14081
+          },
+          "TerritoryId": 956,
+          "InteractionType": "Interact"
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1038500,
+          "Position": {
+            "X": -357.83936,
+            "Y": 21.84602,
+            "Z": -91.32526
+          },
+          "TerritoryId": 962,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1038500,
+          "Position": {
+            "X": -357.83936,
+            "Y": 21.84602,
+            "Z": -91.32526
+          },
+          "TerritoryId": 962,
+          "InteractionType": "CompleteQuest"
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1038504,
+          "Position": {
+            "X": -357.62573,
+            "Y": 21.64856,
+            "Z": -95.99457
+          },
+          "TerritoryId": 962,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 1038505,
+          "Position": {
+            "X": -376.45538,
+            "Y": 18.999998,
+            "Z": 37.00305
+          },
+          "TerritoryId": 962,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 2,
+      "Steps": [
+        {
+          "DataId": 1038503,
+          "Position": {
+            "X": -367.0863,
+            "Y": 21.84602,
+            "Z": -101.701416
+          },
+          "TerritoryId": 962,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1038501,
+          "Position": {
+            "X": -367.3305,
+            "Y": 21.846018,
+            "Z": -102.983154
+          },
+          "StopDistance": 7,
+          "TerritoryId": 962,
+          "InteractionType": "CompleteQuest",
+          "NextQuestId": 4154
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1038501,
+          "Position": {
+            "X": -367.3305,
+            "Y": 21.846018,
+            "Z": -102.983154
+          },
+          "TerritoryId": 962,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1038501,
+          "Position": {
+            "X": -367.3305,
+            "Y": 21.846018,
+            "Z": -102.983154
+          },
+          "TerritoryId": 962,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Old Sharlayan",
+          "AethernetShortcut": [
+            "[Old Sharlayan] Aetheryte Plaza",
+            "[Old Sharlayan] The Studium"
+          ],
+          "RequiredGatheredItems": [
+            {
+              "ItemId": 35600,
+              "ItemCount": 6,
+              "Collectability": 600
+            }
+          ],
+          "NextQuestId": 4155
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1038501,
+          "Position": {
+            "X": -367.3305,
+            "Y": 21.846018,
+            "Z": -102.983154
+          },
+          "TerritoryId": 962,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1038501,
+          "Position": {
+            "X": -367.3305,
+            "Y": 21.846018,
+            "Z": -102.983154
+          },
+          "TerritoryId": 962,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Old Sharlayan",
+          "AethernetShortcut": [
+            "[Old Sharlayan] Aetheryte Plaza",
+            "[Old Sharlayan] The Studium"
+          ],
+          "RequiredGatheredItems": [
+            {
+              "ItemId": 35601,
+              "ItemCount": 6,
+              "Collectability": 600
+            }
+          ],
+          "NextQuestId": 4156
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1038501,
+          "Position": {
+            "X": -367.3305,
+            "Y": 21.846018,
+            "Z": -102.983154
+          },
+          "TerritoryId": 962,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1038501,
+          "Position": {
+            "X": -367.3305,
+            "Y": 21.846018,
+            "Z": -102.983154
+          },
+          "TerritoryId": 962,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Old Sharlayan",
+          "AethernetShortcut": [
+            "[Old Sharlayan] Aetheryte Plaza",
+            "[Old Sharlayan] The Studium"
+          ],
+          "RequiredGatheredItems": [
+            {
+              "ItemId": 35602,
+              "ItemCount": 6,
+              "Collectability": 600
+            }
+          ],
+          "NextQuestId": 4157
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1038501,
+          "Position": {
+            "X": -367.3305,
+            "Y": 21.846018,
+            "Z": -102.983154
+          },
+          "TerritoryId": 962,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 2011719,
+          "Position": {
+            "X": -102.1897,
+            "Y": -7.0039062,
+            "Z": -59.92218
+          },
+          "TerritoryId": 628,
+          "InteractionType": "Interact",
+          "AetheryteShortcut": "Kugane",
+          "AethernetShortcut": [
+            "[Kugane] Aetheryte Plaza",
+            "[Kugane] Shiokaze Hostelry"
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 2,
+      "Steps": [
+        {
+          "DataId": 1038506,
+          "Position": {
+            "X": -142.2904,
+            "Y": -4.7500057,
+            "Z": 199.6643
+          },
+          "TerritoryId": 628,
+          "InteractionType": "Interact",
+          "AethernetShortcut": [
+            "[Kugane] Kogane Dori Markets",
+            "[Kugane] Pier #1"
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 3,
+      "Steps": [
+        {
+          "DataId": 1038507,
+          "Position": {
+            "X": 52.750366,
+            "Y": 8.02,
+            "Z": 152.81909
+          },
+          "TerritoryId": 628,
+          "InteractionType": "Interact",
+          "AethernetShortcut": [
+            "[Kugane] Pier #1",
+            "[Kugane] Thavnairian Consulate"
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 4,
+      "Steps": [
+        {
+          "DataId": 2011720,
+          "Position": {
+            "X": 129.5033,
+            "Y": 24.979004,
+            "Z": 15.701477
+          },
+          "TerritoryId": 628,
+          "InteractionType": "Interact",
+          "AethernetShortcut": [
+            "[Kugane] Thavnairian Consulate",
+            "[Kugane] The Ruby Bazaar"
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 5,
+      "Steps": [
+        {
+          "DataId": 1038508,
+          "Position": {
+            "X": 114.70203,
+            "Y": 12,
+            "Z": 35.965454
+          },
+          "TerritoryId": 628,
+          "InteractionType": "Interact",
+          "AetheryteShortcut": "Kugane",
+          "AethernetShortcut": [
+            "[Kugane] Aetheryte Plaza",
+            "[Kugane] The Ruby Bazaar"
+          ],
+          "RequiredGatheredItems": [
+            {
+              "ItemId": 35847,
+              "ItemCount": 1
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 6,
+      "Steps": [
+        {
+          "DataId": 1038510,
+          "Position": {
+            "X": -92.24078,
+            "Y": 11.799999,
+            "Z": -156.05408
+          },
+          "TerritoryId": 628,
+          "InteractionType": "Interact",
+          "AethernetShortcut": [
+            "[Kugane] The Ruby Bazaar",
+            "[Kugane] Bokairo Inn"
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1038501,
+          "Position": {
+            "X": -367.3305,
+            "Y": 21.846018,
+            "Z": -102.983154
+          },
+          "TerritoryId": 962,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Old Sharlayan",
+          "AethernetShortcut": [
+            "[Old Sharlayan] Aetheryte Plaza",
+            "[Old Sharlayan] The Studium"
+          ],
+          "NextQuestId": 4158
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1038501,
+          "Position": {
+            "X": -367.3305,
+            "Y": 21.846018,
+            "Z": -102.983154
+          },
+          "TerritoryId": 962,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1038501,
+          "Position": {
+            "X": -367.3305,
+            "Y": 21.846018,
+            "Z": -102.983154
+          },
+          "TerritoryId": 962,
+          "InteractionType": "CompleteQuest",
+          "AetheryteShortcut": "Old Sharlayan",
+          "AethernetShortcut": [
+            "[Old Sharlayan] Aetheryte Plaza",
+            "[Old Sharlayan] The Studium"
+          ],
+          "RequiredGatheredItems": [
+            {
+              "ItemId": 35603,
+              "ItemCount": 6,
+              "Collectability": 600
+            }
+          ],
+          "NextQuestId": 4159
+        }
+      ]
+    }
+  ]
+}
 
--- /dev/null
+{
+  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1038501,
+          "Position": {
+            "X": -367.3305,
+            "Y": 21.846018,
+            "Z": -102.983154
+          },
+          "TerritoryId": 962,
+          "InteractionType": "AcceptQuest"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 1038503,
+          "Position": {
+            "X": -367.0863,
+            "Y": 21.84602,
+            "Z": -101.701416
+          },
+          "TerritoryId": 962,
+          "InteractionType": "Interact",
+          "AetheryteShortcut": "Old Sharlayan",
+          "AethernetShortcut": [
+            "[Old Sharlayan] Aetheryte Plaza",
+            "[Old Sharlayan] The Studium"
+          ],
+          "RequiredGatheredItems": [
+            {
+              "ItemId": 35848,
+              "ItemCount": 1
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 2,
+      "Steps": [
+        {
+          "DataId": 1038512,
+          "Position": {
+            "X": -73.47223,
+            "Y": -16.147001,
+            "Z": 191.27173
+          },
+          "TerritoryId": 962,
+          "InteractionType": "Interact",
+          "AethernetShortcut": [
+            "[Old Sharlayan] The Studium",
+            "[Old Sharlayan] Scholar's Harbor"
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 3,
+      "Steps": [
+        {
+          "DataId": 1038503,
+          "Position": {
+            "X": -367.0863,
+            "Y": 21.84602,
+            "Z": -101.701416
+          },
+          "TerritoryId": 962,
+          "InteractionType": "Interact",
+          "AethernetShortcut": [
+            "[Old Sharlayan] Scholar's Harbor",
+            "[Old Sharlayan] The Studium"
+          ]
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1038501,
+          "Position": {
+            "X": -367.3305,
+            "Y": 21.846018,
+            "Z": -102.983154
+          },
+          "StopDistance": 7,
+          "TerritoryId": 962,
+          "InteractionType": "CompleteQuest"
+        }
+      ]
+    }
+  ]
+}
 
+++ /dev/null
-{
-  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
-  "Author": "liza",
-  "QuestSequence": [
-    {
-      "Sequence": 0,
-      "Steps": [
-        {
-          "DataId": 1038500,
-          "Position": {
-            "X": -357.83936,
-            "Y": 21.84602,
-            "Z": -91.32526
-          },
-          "TerritoryId": 962,
-          "InteractionType": "AcceptQuest"
-        }
-      ]
-    },
-    {
-      "Sequence": 255,
-      "Steps": [
-        {
-          "DataId": 1038500,
-          "Position": {
-            "X": -357.83936,
-            "Y": 21.84602,
-            "Z": -91.32526
-          },
-          "TerritoryId": 962,
-          "InteractionType": "CompleteQuest"
-        }
-      ]
-    }
-  ]
-}
 
+++ /dev/null
-{
-  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
-  "Author": "liza",
-  "QuestSequence": [
-    {
-      "Sequence": 0,
-      "Steps": [
-        {
-          "DataId": 1038504,
-          "Position": {
-            "X": -357.62573,
-            "Y": 21.64856,
-            "Z": -95.99457
-          },
-          "TerritoryId": 962,
-          "InteractionType": "AcceptQuest"
-        }
-      ]
-    },
-    {
-      "Sequence": 1,
-      "Steps": [
-        {
-          "DataId": 1038505,
-          "Position": {
-            "X": -376.45538,
-            "Y": 18.999998,
-            "Z": 37.00305
-          },
-          "TerritoryId": 962,
-          "InteractionType": "Interact"
-        }
-      ]
-    },
-    {
-      "Sequence": 2,
-      "Steps": [
-        {
-          "DataId": 1038503,
-          "Position": {
-            "X": -367.0863,
-            "Y": 21.84602,
-            "Z": -101.701416
-          },
-          "TerritoryId": 962,
-          "InteractionType": "Interact"
-        }
-      ]
-    },
-    {
-      "Sequence": 255,
-      "Steps": [
-        {
-          "DataId": 1038501,
-          "Position": {
-            "X": -367.3305,
-            "Y": 21.846018,
-            "Z": -102.983154
-          },
-          "StopDistance": 7,
-          "TerritoryId": 962,
-          "InteractionType": "CompleteQuest",
-          "NextQuestId": 4154
-        }
-      ]
-    }
-  ]
-}
 
+++ /dev/null
-{
-  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
-  "Author": "liza",
-  "QuestSequence": [
-    {
-      "Sequence": 0,
-      "Steps": [
-        {
-          "DataId": 1038501,
-          "Position": {
-            "X": -367.3305,
-            "Y": 21.846018,
-            "Z": -102.983154
-          },
-          "TerritoryId": 962,
-          "InteractionType": "AcceptQuest"
-        }
-      ]
-    },
-    {
-      "Sequence": 255,
-      "Steps": [
-        {
-          "DataId": 1038501,
-          "Position": {
-            "X": -367.3305,
-            "Y": 21.846018,
-            "Z": -102.983154
-          },
-          "TerritoryId": 962,
-          "InteractionType": "CompleteQuest",
-          "AetheryteShortcut": "Old Sharlayan",
-          "AethernetShortcut": [
-            "[Old Sharlayan] Aetheryte Plaza",
-            "[Old Sharlayan] The Studium"
-          ],
-          "RequiredGatheredItems": [
-            {
-              "ItemId": 35600,
-              "ItemCount": 6,
-              "Collectability": 600
-            }
-          ],
-          "NextQuestId": 4155
-        }
-      ]
-    }
-  ]
-}
 
+++ /dev/null
-{
-  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
-  "Author": "liza",
-  "QuestSequence": [
-    {
-      "Sequence": 0,
-      "Steps": [
-        {
-          "DataId": 1038501,
-          "Position": {
-            "X": -367.3305,
-            "Y": 21.846018,
-            "Z": -102.983154
-          },
-          "TerritoryId": 962,
-          "InteractionType": "AcceptQuest"
-        }
-      ]
-    },
-    {
-      "Sequence": 255,
-      "Steps": [
-        {
-          "DataId": 1038501,
-          "Position": {
-            "X": -367.3305,
-            "Y": 21.846018,
-            "Z": -102.983154
-          },
-          "TerritoryId": 962,
-          "InteractionType": "CompleteQuest",
-          "AetheryteShortcut": "Old Sharlayan",
-          "AethernetShortcut": [
-            "[Old Sharlayan] Aetheryte Plaza",
-            "[Old Sharlayan] The Studium"
-          ],
-          "RequiredGatheredItems": [
-            {
-              "ItemId": 35601,
-              "ItemCount": 6,
-              "Collectability": 600
-            }
-          ],
-          "NextQuestId": 4156
-        }
-      ]
-    }
-  ]
-}
 
+++ /dev/null
-{
-  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
-  "Author": "liza",
-  "QuestSequence": [
-    {
-      "Sequence": 0,
-      "Steps": [
-        {
-          "DataId": 1038501,
-          "Position": {
-            "X": -367.3305,
-            "Y": 21.846018,
-            "Z": -102.983154
-          },
-          "TerritoryId": 962,
-          "InteractionType": "AcceptQuest"
-        }
-      ]
-    },
-    {
-      "Sequence": 255,
-      "Steps": [
-        {
-          "DataId": 1038501,
-          "Position": {
-            "X": -367.3305,
-            "Y": 21.846018,
-            "Z": -102.983154
-          },
-          "TerritoryId": 962,
-          "InteractionType": "CompleteQuest",
-          "AetheryteShortcut": "Old Sharlayan",
-          "AethernetShortcut": [
-            "[Old Sharlayan] Aetheryte Plaza",
-            "[Old Sharlayan] The Studium"
-          ],
-          "RequiredGatheredItems": [
-            {
-              "ItemId": 35602,
-              "ItemCount": 6,
-              "Collectability": 600
-            }
-          ],
-          "NextQuestId": 4157
-        }
-      ]
-    }
-  ]
-}
 
+++ /dev/null
-{
-  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
-  "Author": "liza",
-  "QuestSequence": [
-    {
-      "Sequence": 0,
-      "Steps": [
-        {
-          "DataId": 1038501,
-          "Position": {
-            "X": -367.3305,
-            "Y": 21.846018,
-            "Z": -102.983154
-          },
-          "TerritoryId": 962,
-          "InteractionType": "AcceptQuest"
-        }
-      ]
-    },
-    {
-      "Sequence": 1,
-      "Steps": [
-        {
-          "DataId": 2011719,
-          "Position": {
-            "X": -102.1897,
-            "Y": -7.0039062,
-            "Z": -59.92218
-          },
-          "TerritoryId": 628,
-          "InteractionType": "Interact",
-          "AetheryteShortcut": "Kugane",
-          "AethernetShortcut": [
-            "[Kugane] Aetheryte Plaza",
-            "[Kugane] Shiokaze Hostelry"
-          ]
-        }
-      ]
-    },
-    {
-      "Sequence": 2,
-      "Steps": [
-        {
-          "DataId": 1038506,
-          "Position": {
-            "X": -142.2904,
-            "Y": -4.7500057,
-            "Z": 199.6643
-          },
-          "TerritoryId": 628,
-          "InteractionType": "Interact",
-          "AethernetShortcut": [
-            "[Kugane] Kogane Dori Markets",
-            "[Kugane] Pier #1"
-          ]
-        }
-      ]
-    },
-    {
-      "Sequence": 3,
-      "Steps": [
-        {
-          "DataId": 1038507,
-          "Position": {
-            "X": 52.750366,
-            "Y": 8.02,
-            "Z": 152.81909
-          },
-          "TerritoryId": 628,
-          "InteractionType": "Interact",
-          "AethernetShortcut": [
-            "[Kugane] Pier #1",
-            "[Kugane] Thavnairian Consulate"
-          ]
-        }
-      ]
-    },
-    {
-      "Sequence": 4,
-      "Steps": [
-        {
-          "DataId": 2011720,
-          "Position": {
-            "X": 129.5033,
-            "Y": 24.979004,
-            "Z": 15.701477
-          },
-          "TerritoryId": 628,
-          "InteractionType": "Interact",
-          "AethernetShortcut": [
-            "[Kugane] Thavnairian Consulate",
-            "[Kugane] The Ruby Bazaar"
-          ]
-        }
-      ]
-    },
-    {
-      "Sequence": 5,
-      "Steps": [
-        {
-          "DataId": 1038508,
-          "Position": {
-            "X": 114.70203,
-            "Y": 12,
-            "Z": 35.965454
-          },
-          "TerritoryId": 628,
-          "InteractionType": "Interact",
-          "AetheryteShortcut": "Kugane",
-          "AethernetShortcut": [
-            "[Kugane] Aetheryte Plaza",
-            "[Kugane] The Ruby Bazaar"
-          ],
-          "RequiredGatheredItems": [
-            {
-              "ItemId": 35847,
-              "ItemCount": 1
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "Sequence": 6,
-      "Steps": [
-        {
-          "DataId": 1038510,
-          "Position": {
-            "X": -92.24078,
-            "Y": 11.799999,
-            "Z": -156.05408
-          },
-          "TerritoryId": 628,
-          "InteractionType": "Interact",
-          "AethernetShortcut": [
-            "[Kugane] The Ruby Bazaar",
-            "[Kugane] Bokairo Inn"
-          ]
-        }
-      ]
-    },
-    {
-      "Sequence": 255,
-      "Steps": [
-        {
-          "DataId": 1038501,
-          "Position": {
-            "X": -367.3305,
-            "Y": 21.846018,
-            "Z": -102.983154
-          },
-          "TerritoryId": 962,
-          "InteractionType": "CompleteQuest",
-          "AetheryteShortcut": "Old Sharlayan",
-          "AethernetShortcut": [
-            "[Old Sharlayan] Aetheryte Plaza",
-            "[Old Sharlayan] The Studium"
-          ],
-          "NextQuestId": 4158
-        }
-      ]
-    }
-  ]
-}
 
+++ /dev/null
-{
-  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
-  "Author": "liza",
-  "QuestSequence": [
-    {
-      "Sequence": 0,
-      "Steps": [
-        {
-          "DataId": 1038501,
-          "Position": {
-            "X": -367.3305,
-            "Y": 21.846018,
-            "Z": -102.983154
-          },
-          "TerritoryId": 962,
-          "InteractionType": "AcceptQuest"
-        }
-      ]
-    },
-    {
-      "Sequence": 255,
-      "Steps": [
-        {
-          "DataId": 1038501,
-          "Position": {
-            "X": -367.3305,
-            "Y": 21.846018,
-            "Z": -102.983154
-          },
-          "TerritoryId": 962,
-          "InteractionType": "CompleteQuest",
-          "AetheryteShortcut": "Old Sharlayan",
-          "AethernetShortcut": [
-            "[Old Sharlayan] Aetheryte Plaza",
-            "[Old Sharlayan] The Studium"
-          ],
-          "RequiredGatheredItems": [
-            {
-              "ItemId": 35603,
-              "ItemCount": 6,
-              "Collectability": 600
-            }
-          ],
-          "NextQuestId": 4159
-        }
-      ]
-    }
-  ]
-}
 
+++ /dev/null
-{
-  "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/QuestPaths/quest-v1.json",
-  "Author": "liza",
-  "QuestSequence": [
-    {
-      "Sequence": 0,
-      "Steps": [
-        {
-          "DataId": 1038501,
-          "Position": {
-            "X": -367.3305,
-            "Y": 21.846018,
-            "Z": -102.983154
-          },
-          "TerritoryId": 962,
-          "InteractionType": "AcceptQuest"
-        }
-      ]
-    },
-    {
-      "Sequence": 1,
-      "Steps": [
-        {
-          "DataId": 1038503,
-          "Position": {
-            "X": -367.0863,
-            "Y": 21.84602,
-            "Z": -101.701416
-          },
-          "TerritoryId": 962,
-          "InteractionType": "Interact",
-          "AetheryteShortcut": "Old Sharlayan",
-          "AethernetShortcut": [
-            "[Old Sharlayan] Aetheryte Plaza",
-            "[Old Sharlayan] The Studium"
-          ],
-          "RequiredGatheredItems": [
-            {
-              "ItemId": 35848,
-              "ItemCount": 1
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "Sequence": 2,
-      "Steps": [
-        {
-          "DataId": 1038512,
-          "Position": {
-            "X": -73.47223,
-            "Y": -16.147001,
-            "Z": 191.27173
-          },
-          "TerritoryId": 962,
-          "InteractionType": "Interact",
-          "AethernetShortcut": [
-            "[Old Sharlayan] The Studium",
-            "[Old Sharlayan] Scholar's Harbor"
-          ]
-        }
-      ]
-    },
-    {
-      "Sequence": 3,
-      "Steps": [
-        {
-          "DataId": 1038503,
-          "Position": {
-            "X": -367.0863,
-            "Y": 21.84602,
-            "Z": -101.701416
-          },
-          "TerritoryId": 962,
-          "InteractionType": "Interact",
-          "AethernetShortcut": [
-            "[Old Sharlayan] Scholar's Harbor",
-            "[Old Sharlayan] The Studium"
-          ]
-        }
-      ]
-    },
-    {
-      "Sequence": 255,
-      "Steps": [
-        {
-          "DataId": 1038501,
-          "Position": {
-            "X": -367.3305,
-            "Y": 21.846018,
-            "Z": -102.983154
-          },
-          "StopDistance": 7,
-          "TerritoryId": 962,
-          "InteractionType": "CompleteQuest"
-        }
-      ]
-    }
-  ]
-}
 
         <AdditionalFiles Include="6.x - Endwalker\**\*.json" />
         <AdditionalFiles Include="7.x - Dawntrail\**\*.json" />
     </ItemGroup>
-
-    <ItemGroup>
-      <Folder Include="7.x - Dawntrail\Custom Deliveries\" />
-    </ItemGroup>
 </Project>
 
                       "PickUpQuestId": {
                         "type": [
                           "null",
-                          "number"
+                          "number",
+                          "string"
                         ],
                         "description": "Determines the quest which should be accepted. If empty/null, accepts the quest corresponding to the file name."
                       }
                       "TurnInQuestId": {
                         "type": [
                           "null",
-                          "number"
+                          "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"
+                          "number",
+                          "string"
                         ],
                         "description": "For quest chains (e.g. DT healer role quests) Which quest to do next, given that you meet the required level."
                       }
 
     IshgardTribunal = 86,
     IshgardLastVigil = 87,
     IshgardGatesOfJudgement = 88,
+    IshgardFirmament = 100001,
 
     Idyllshire = 75,
     IdyllshireWest = 90,
 
         { EAetheryteLocation.IshgardTribunal, "[Ishgard] The Tribunal" },
         { EAetheryteLocation.IshgardLastVigil, "[Ishgard] The Last Vigil" },
         { EAetheryteLocation.IshgardGatesOfJudgement, "[Ishgard] The Gates of Judgement (Coerthas Central Highlands)" },
+        { EAetheryteLocation.IshgardFirmament, "[Ishgard] Firmament" },
 
         { EAetheryteLocation.Idyllshire, "[Idyllshire] Aetheryte Plaza" },
         { EAetheryteLocation.IdyllshireWest, "[Idyllshire] West Idyllshire" },
 
 
 namespace Questionable.Model.Questing.Converter;
 
-public class ElementIdConverter : JsonConverter<ElementId>
+public sealed class ElementIdConverter : JsonConverter<ElementId>
 {
     public override ElementId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
     {
-        uint value = reader.GetUInt32();
-        return ElementId.From(value);
+        if (reader.TokenType == JsonTokenType.Number)
+            return new QuestId(reader.GetUInt16());
+        else
+            return ElementId.FromString(reader.GetString() ?? throw new JsonException());
     }
 
     public override void Write(Utf8JsonWriter writer, ElementId value, JsonSerializerOptions options)
 
         return !Equals(left, right);
     }
 
-    public static ElementId From(uint value)
+    public static ElementId FromString(string value)
     {
-        if (value >= 100_000 && value < 200_000)
-            return new LeveId((ushort)(value - 100_000));
+        if (value.StartsWith("L"))
+            return new LeveId(ushort.Parse(value.Substring(1), CultureInfo.InvariantCulture));
+        else if (value.StartsWith("S"))
+            return new SatisfactionSupplyNpcId(ushort.Parse(value.Substring(1), CultureInfo.InvariantCulture));
         else
-            return new QuestId((ushort)value);
+            return new QuestId(ushort.Parse(value, CultureInfo.InvariantCulture));
     }
-}
 
-public sealed class QuestId : ElementId
-{
-    public QuestId(ushort value)
-        : base(value)
+    public static bool TryFromString(string value, out ElementId? elementId)
     {
+        try
+        {
+            elementId = FromString(value);
+            return true;
+        }
+        catch (Exception)
+        {
+            elementId = null;
+            return false;
+        }
     }
+}
 
+public sealed class QuestId(ushort value) : ElementId(value)
+{
     public override string ToString()
     {
         return Value.ToString(CultureInfo.InvariantCulture);
     }
 }
 
-public sealed class LeveId : ElementId
+public sealed class LeveId(ushort value) : ElementId(value)
 {
-    public LeveId(ushort value)
-        : base(value)
+    public override string ToString()
     {
+        return "L" + Value.ToString(CultureInfo.InvariantCulture);
     }
+}
 
+public sealed class SatisfactionSupplyNpcId(ushort value) : ElementId(value)
+{
     public override string ToString()
     {
-        return "L" + Value.ToString(CultureInfo.InvariantCulture);
+        return "S" + Value.ToString(CultureInfo.InvariantCulture);
     }
 }
 
         "[Ishgard] The Tribunal",
         "[Ishgard] The Last Vigil",
         "[Ishgard] The Gates of Judgement (Coerthas Central Highlands)",
+        "[Ishgard] Firmament",
         "[Idyllshire] Aetheryte Plaza",
         "[Idyllshire] West Idyllshire",
         "[Idyllshire] Prologue Gate (Western Hinterlands)",
 
 
             case "start":
                 _questWindow.IsOpen = true;
-                _questController.ExecuteNextStep(true);
+                _questController.ExecuteNextStep(QuestController.EAutomationType.Automatic);
                 break;
 
             case "stop":
             return;
         }
 
-        if (arguments.Length >= 1 && uint.TryParse(arguments[0], out uint questId))
+        if (arguments.Length >= 1 && ElementId.TryFromString(arguments[0], out ElementId? questId) && questId != null)
         {
-            if (_questRegistry.TryGetQuest(ElementId.From(questId), out Quest? quest))
+            if (_questRegistry.TryGetQuest(questId, out Quest? quest))
             {
-                _debugOverlay.HighlightedQuest = quest.QuestElementId;
+                _debugOverlay.HighlightedQuest = quest.Id;
                 _chatGui.Print($"[Questionable] Set highlighted quest to {questId} ({quest.Info.Name}).");
             }
             else
 
     private void SetNextQuest(string[] arguments)
     {
-        if (arguments.Length >= 1 && uint.TryParse(arguments[0], out uint questId))
+        if (arguments.Length >= 1 && ElementId.TryFromString(arguments[0], out ElementId? questId) && questId != null)
         {
-            if (_gameFunctions.IsQuestLocked(ElementId.From(questId)))
+            if (_gameFunctions.IsQuestLocked(questId))
                 _chatGui.PrintError($"[Questionable] Quest {questId} is locked.");
-            else if (_questRegistry.TryGetQuest(ElementId.From(questId), out Quest? quest))
+            else if (_questRegistry.TryGetQuest(questId, out Quest? quest))
             {
                 _questController.SetNextQuest(quest);
                 _chatGui.Print($"[Questionable] Set next quest to {questId} ({quest.Info.Name}).");
 
     private void SetSimulatedQuest(string[] arguments)
     {
-        if (arguments.Length >= 1 && ushort.TryParse(arguments[0], out ushort questId))
+        if (arguments.Length >= 1 && ElementId.TryFromString(arguments[0], out ElementId? questId) && questId != null)
         {
-            if (_questRegistry.TryGetQuest(ElementId.From(questId), out Quest? quest))
+            if (_questRegistry.TryGetQuest(questId, out Quest? quest))
             {
                 _questController.SimulateQuest(quest);
                 _chatGui.Print($"[Questionable] Simulating quest {questId} ({quest.Info.Name}).");
 
--- /dev/null
+using System;
+using System.Linq;
+using Dalamud.Game.Gui.ContextMenu;
+using Dalamud.Game.Text;
+using Dalamud.Plugin.Services;
+using FFXIVClientStructs.FFXIV.Client.Game;
+using Microsoft.Extensions.Logging;
+using Questionable.Data;
+using Questionable.Model;
+using Questionable.Model.Questing;
+
+namespace Questionable.Controller;
+
+internal sealed class ContextMenuController : IDisposable
+{
+    private readonly IContextMenu _contextMenu;
+    private readonly QuestController _questController;
+    private readonly GatheringData _gatheringData;
+    private readonly QuestRegistry _questRegistry;
+    private readonly QuestData _questData;
+    private readonly IGameGui _gameGui;
+    private readonly IChatGui _chatGui;
+    private readonly IClientState _clientState;
+    private readonly ILogger<ContextMenuController> _logger;
+
+    public ContextMenuController(
+        IContextMenu contextMenu,
+        QuestController questController,
+        GatheringData gatheringData,
+        QuestRegistry questRegistry,
+        QuestData questData,
+        IGameGui gameGui,
+        IChatGui chatGui,
+        IClientState clientState,
+        ILogger<ContextMenuController> logger)
+    {
+        _contextMenu = contextMenu;
+        _questController = questController;
+        _gatheringData = gatheringData;
+        _questRegistry = questRegistry;
+        _questData = questData;
+        _gameGui = gameGui;
+        _chatGui = chatGui;
+        _clientState = clientState;
+        _logger = logger;
+
+        _contextMenu.OnMenuOpened += MenuOpened;
+    }
+
+    private void MenuOpened(IMenuOpenedArgs args)
+    {
+        uint itemId = (uint) _gameGui.HoveredItem;
+        if (itemId == 0)
+            return;
+
+        if (itemId > 1_000_000)
+            itemId -= 1_000_000;
+
+        if (itemId >= 500_000)
+            itemId -= 500_000;
+
+        if (!_gatheringData.TryGetGatheringPointId(itemId, _clientState.LocalPlayer!.ClassJob.Id, out _))
+        {
+            _logger.LogInformation("No gathering point found for current job.");
+            return;
+        }
+
+        if (_gatheringData.TryGetCustomDeliveryNpc(itemId, out uint npcId))
+        {
+            ushort collectability = _gatheringData.GetRecommendedCollectability(itemId);
+            int quantityToGather = collectability > 0 ? 6 : int.MaxValue;
+            if (collectability == 0)
+                return;
+
+            args.AddMenuItem(new MenuItem
+            {
+                Prefix = SeIconChar.Hyadelyn,
+                PrefixColor = 52,
+                Name = "Gather with Questionable",
+                OnClicked = _ => StartGathering(npcId, itemId, quantityToGather, collectability),
+            });
+        }
+    }
+
+    private void StartGathering(uint npcId, uint itemId, int quantity, ushort collectability)
+    {
+        var info = (SatisfactionSupplyInfo)_questData.GetAllByIssuerDataId(npcId).Single(x => x is SatisfactionSupplyInfo);
+        if (_questRegistry.TryGetQuest(info.QuestId, out Quest? quest))
+        {
+            var step = quest.FindSequence(0)!.FindStep(0)!;
+            step.RequiredGatheredItems =
+            [
+                new GatheredItem
+                {
+                    ItemId = itemId,
+                    ItemCount = quantity,
+                    Collectability = collectability
+                }
+            ];
+            _questController.SetNextQuest(quest);
+            _questController.ExecuteNextStep(QuestController.EAutomationType.CurrentQuestOnly);
+        }
+        else
+            _chatGui.PrintError($"No associated quest ({info.QuestId}).", "Questionable");
+    }
+
+    public void Dispose()
+    {
+        _contextMenu.OnMenuOpened -= MenuOpened;
+    }
+}
 
 
     private unsafe void UnendingCodexPostSetup(AddonEvent type, AddonArgs args)
     {
-        if (_questController.StartedQuest?.Quest.QuestElementId.Value == 4526)
+        if (_questController.StartedQuest?.Quest.Id.Value == 4526)
         {
             _logger.LogInformation("Closing Unending Codex");
             AtkUnitBase* addon = (AtkUnitBase*)args.Addon;
 
     private unsafe void ContentsTutorialPostSetup(AddonEvent type, AddonArgs args)
     {
-        if (_questController.StartedQuest?.Quest.QuestElementId.Value == 245)
+        if (_questController.StartedQuest?.Quest.Id.Value == 245)
         {
             _logger.LogInformation("Closing ContentsTutorial");
             AtkUnitBase* addon = (AtkUnitBase*)args.Addon;
     /// </summary>
     private unsafe void MultipleHelpWindowPostSetup(AddonEvent type, AddonArgs args)
     {
-        if (_questController.StartedQuest?.Quest.QuestElementId.Value == 245)
+        if (_questController.StartedQuest?.Quest.Id.Value == 245)
         {
             _logger.LogInformation("Closing MultipleHelpWindow");
             AtkUnitBase* addon = (AtkUnitBase*)args.Addon;
 
     private QuestProgress? _startedQuest;
     private QuestProgress? _nextQuest;
     private QuestProgress? _simulatedQuest;
-    private bool _automatic;
+    private EAutomationType _automationType;
 
     /// <summary>
     /// Some combat encounters finish relatively early (i.e. they're done as part of progressing the quest, but not
         _taskFactories = taskFactories.ToList().AsReadOnly();
     }
 
-    public (QuestProgress Progress, CurrentQuestType Type)? CurrentQuestDetails
+    public (QuestProgress Progress, ECurrentQuestType Type)? CurrentQuestDetails
     {
         get
         {
             if (_simulatedQuest != null)
-                return (_simulatedQuest, CurrentQuestType.Simulated);
-            else if (_nextQuest != null && _gameFunctions.IsReadyToAcceptQuest(_nextQuest.Quest.QuestElementId))
-                return (_nextQuest, CurrentQuestType.Next);
+                return (_simulatedQuest, ECurrentQuestType.Simulated);
+            else if (_nextQuest != null && _gameFunctions.IsReadyToAcceptQuest(_nextQuest.Quest.Id))
+                return (_nextQuest, ECurrentQuestType.Next);
             else if (_startedQuest != null)
-                return (_startedQuest, CurrentQuestType.Normal);
+                return (_startedQuest, ECurrentQuestType.Normal);
             else
                 return null;
         }
         if (CurrentQuest != null && CurrentQuest.Quest.Root.TerritoryBlacklist.Contains(_clientState.TerritoryType))
             return;
 
-        if (_automatic && ((_currentTask == null && _taskQueue.Count == 0) ||
-                           _currentTask is WaitAtEnd.WaitQuestAccepted)
-                       && CurrentQuest is { Sequence: 0, Step: 0 } or { Sequence: 0, Step: 255 }
-                       && DateTime.Now >= CurrentQuest.StepProgress.StartedAt.AddSeconds(15))
+        if (_automationType == EAutomationType.Automatic &&
+            ((_currentTask == null && _taskQueue.Count == 0) ||
+             _currentTask is WaitAtEnd.WaitQuestAccepted)
+            && CurrentQuest is { Sequence: 0, Step: 0 } or { Sequence: 0, Step: 255 }
+            && DateTime.Now >= CurrentQuest.StepProgress.StartedAt.AddSeconds(15))
         {
             lock (_progressLock)
             {
                 CurrentQuest.SetStep(0);
             }
 
-            ExecuteNextStep(true);
+            ExecuteNextStep(_automationType);
             return;
         }
 
                 // if the quest is accepted, we no longer track it
                 bool canUseNextQuest;
                 if (_nextQuest.Quest.Info.IsRepeatable)
-                    canUseNextQuest = !_gameFunctions.IsQuestAccepted(_nextQuest.Quest.QuestElementId);
+                    canUseNextQuest = !_gameFunctions.IsQuestAccepted(_nextQuest.Quest.Id);
                 else
-                    canUseNextQuest = !_gameFunctions.IsQuestAcceptedOrComplete(_nextQuest.Quest.QuestElementId);
+                    canUseNextQuest = !_gameFunctions.IsQuestAcceptedOrComplete(_nextQuest.Quest.Id);
 
                 if (!canUseNextQuest)
                 {
-                    _logger.LogInformation("Next quest {QuestId} accepted or completed", _nextQuest.Quest.QuestElementId);
+                    _logger.LogInformation("Next quest {QuestId} accepted or completed",
+                        _nextQuest.Quest.Id);
                     _nextQuest = null;
                 }
             }
                 currentSequence = _simulatedQuest.Sequence;
                 questToRun = _simulatedQuest;
             }
-            else if (_nextQuest != null && _gameFunctions.IsReadyToAcceptQuest(_nextQuest.Quest.QuestElementId))
+            else if (_nextQuest != null && _gameFunctions.IsReadyToAcceptQuest(_nextQuest.Quest.Id))
             {
                 questToRun = _nextQuest;
                 currentSequence = _nextQuest.Sequence; // by definition, this should always be 0
-                if (_nextQuest.Step == 0 && _currentTask == null && _taskQueue.Count == 0 && _automatic)
-                    ExecuteNextStep(true);
+                if (_nextQuest.Step == 0 &&
+                    _currentTask == null &&
+                    _taskQueue.Count == 0 &&
+                    _automationType == EAutomationType.Automatic)
+                    ExecuteNextStep(_automationType);
             }
             else
             {
 
                     questToRun = null;
                 }
-                else if (_startedQuest == null || _startedQuest.Quest.QuestElementId != currentQuestId)
+                else if (_startedQuest == null || _startedQuest.Quest.Id != currentQuestId)
                 {
                     if (_questRegistry.TryGetQuest(currentQuestId, out var quest))
                     {
                 return;
             }
 
-            if (questId != null && CurrentQuest.Quest.QuestElementId != questId)
+            if (questId != null && CurrentQuest.Quest.Id != questId)
             {
                 _logger.LogWarning(
                     "Ignoring 'increase step count' for different quest (expected {ExpectedQuestId}, but we are at {CurrentQuestId}",
-                    questId, CurrentQuest.Quest.QuestElementId);
+                    questId, CurrentQuest.Quest.Id);
                 return;
             }
 
                 CurrentQuest.SetStep(255);
         }
 
-        if (shouldContinue && _automatic)
-            ExecuteNextStep(true);
+        if (shouldContinue && _automationType != EAutomationType.Manual)
+            ExecuteNextStep(_automationType);
     }
 
     private void ClearTasksInternal()
         ClearTasksInternal();
 
         // reset task queue
-        if (continueIfAutomatic && _automatic)
+        if (continueIfAutomatic && _automationType == EAutomationType.Automatic)
         {
             if (CurrentQuest?.Step is >= 0 and < 255)
-                ExecuteNextStep(true);
+                ExecuteNextStep(_automationType);
             else
                 _logger.LogInformation("Couldn't execute next step during Stop() call");
         }
-        else if (_automatic)
+        else if (_automationType != EAutomationType.Manual)
         {
             _logger.LogInformation("Stopping automatic questing");
-            _automatic = false;
+            _automationType = EAutomationType.Manual;
             _nextQuest = null;
         }
     }
 
     public void SimulateQuest(Quest? quest)
     {
-        _logger.LogInformation("SimulateQuest: {QuestId}", quest?.QuestElementId);
+        _logger.LogInformation("SimulateQuest: {QuestId}", quest?.Id);
         if (quest != null)
             _simulatedQuest = new QuestProgress(quest);
         else
 
     public void SetNextQuest(Quest? quest)
     {
-        _logger.LogInformation("NextQuest: {QuestId}", quest?.QuestElementId);
+        _logger.LogInformation("NextQuest: {QuestId}", quest?.Id);
         if (quest != null)
             _nextQuest = new QuestProgress(quest);
         else
         IncreaseStepCount(task.QuestElementId, task.Sequence, true);
     }
 
-    public void ExecuteNextStep(bool automatic)
+    public void ExecuteNextStep(EAutomationType automatic)
     {
         ClearTasksInternal();
-        _automatic = automatic;
+        _automationType = automatic;
 
         if (TryPickPriorityQuest())
             _logger.LogInformation("Using priority quest over current quest");
         (QuestSequence? seq, QuestStep? step) = GetNextStep();
         if (CurrentQuest == null || seq == null || step == null)
         {
-            _logger.LogWarning("Could not retrieve next quest step, not doing anything [{QuestId}, {Sequence}, {Step}]",
-                CurrentQuest?.Quest.QuestElementId, CurrentQuest?.Sequence, CurrentQuest?.Step);
+            if (CurrentQuestDetails?.Progress.Quest.Id is SatisfactionSupplyNpcId &&
+                CurrentQuestDetails?.Progress.Sequence == 0 &&
+                CurrentQuestDetails?.Progress.Step == 255 &&
+                CurrentQuestDetails?.Type == ECurrentQuestType.Next)
+            {
+                _logger.LogInformation("Completed delivery quest");
+                SetNextQuest(null);
+            }
+            else
+            {
+                _logger.LogWarning(
+                    "Could not retrieve next quest step, not doing anything [{QuestId}, {Sequence}, {Step}]",
+                    CurrentQuest?.Quest.Id, CurrentQuest?.Sequence, CurrentQuest?.Step);
+            }
+
             return;
         }
 
             }
 
             _logger.LogInformation("Tasks for {QuestId}, {Sequence}, {Step}: {Tasks}",
-                CurrentQuest.Quest.QuestElementId, seq.Sequence, seq.Steps.IndexOf(step),
+                CurrentQuest.Quest.Id, seq.Sequence, seq.Steps.IndexOf(step),
                 string.Join(", ", newTasks.Select(x => x.ToString())));
             foreach (var task in newTasks)
                 _taskQueue.Enqueue(task);
             return false;
 
         var (currentQuest, type) = details.Value;
-        if (type != CurrentQuestType.Normal)
+        if (type != ECurrentQuestType.Normal)
             return false;
 
         QuestSequence? currentSequence = currentQuest.Quest.FindSequence(currentQuest.Sequence);
         DateTime StartedAt,
         int PointMenuCounter = 0);
 
-    public enum CurrentQuestType
+    public enum ECurrentQuestType
     {
         Normal,
         Next,
         Simulated,
     }
+
+    public enum EAutomationType
+    {
+        Manual,
+        Automatic,
+        CurrentQuestOnly,
+    }
 }
 
         {
             Quest quest = new()
             {
-                QuestElementId = new QuestId(questId),
+                Id = new QuestId(questId),
                 Root = questRoot,
                 Info = _questData.GetQuestInfo(new QuestId(questId)),
                 ReadOnly = true,
             };
-            _quests[quest.QuestElementId] = quest;
+            _quests[quest.Id] = quest;
         }
 
         _logger.LogInformation("Loaded {Count} quests from assembly", _quests.Count);
 
         Quest quest = new Quest
         {
-            QuestElementId = questId,
+            Id = questId,
             Root = questNode.Deserialize<QuestRoot>()!,
             Info = _questData.GetQuestInfo(questId),
             ReadOnly = false,
         };
-        _quests[quest.QuestElementId] = quest;
+        _quests[quest.Id] = quest;
     }
 
     private void LoadFromDirectory(DirectoryInfo directory, LogLevel logLevel = LogLevel.Information)
             return null;
 
         string[] parts = name.Split('_', 2);
-        return ElementId.From(uint.Parse(parts[0], CultureInfo.InvariantCulture));
+        return ElementId.FromString(parts[0]);
     }
 
-    public bool IsKnownQuest(ElementId elementId)
-    {
-        if (elementId is QuestId questId)
-            return IsKnownQuest(questId);
-        else
-            return false;
-    }
-
-    public bool IsKnownQuest(QuestId questId) => _quests.ContainsKey(questId);
-
-    public bool TryGetQuest(ElementId elementId, [NotNullWhen(true)] out Quest? quest)
-    {
-        if (elementId is QuestId questId)
-            return TryGetQuest(questId, out quest);
-        else
-        {
-            quest = null;
-            return false;
-        }
-    }
+    public bool IsKnownQuest(ElementId questId) => _quests.ContainsKey(questId);
 
-    public bool TryGetQuest(QuestId questId, [NotNullWhen(true)] out Quest? quest)
+    public bool TryGetQuest(ElementId questId, [NotNullWhen(true)] out Quest? quest)
         => _quests.TryGetValue(questId, out quest);
 }
 
             if (step.NextQuestId == null)
                 return null;
 
-            if (step.NextQuestId == quest.QuestElementId)
+            if (step.NextQuestId == quest.Id)
                 return null;
 
             return serviceProvider.GetRequiredService<SetQuest>()
-                .With(step.NextQuestId, quest.QuestElementId);
+                .With(step.NextQuestId, quest.Id);
         }
     }
 
 
                     ArgumentNullException.ThrowIfNull(step.ItemId);
 
                     yield return serviceProvider.GetRequiredService<UseItem.UseOnObject>()
-                        .With(quest.QuestElementId, step.DataId.Value, step.ItemId.Value, step.CompletionQuestVariablesFlags,
+                        .With(quest.Id, step.DataId.Value, step.ItemId.Value, step.CompletionQuestVariablesFlags,
                             true);
                     yield return CreateTask(quest, sequence, step);
                     break;
 
             bool isLastStep = sequence.Steps.Last() == step;
             return serviceProvider.GetRequiredService<HandleCombat>()
-                .With(quest.QuestElementId, isLastStep, step.EnemySpawnType.Value, step.KillEnemyDataIds,
+                .With(quest.Id, isLastStep, step.EnemySpawnType.Value, step.KillEnemyDataIds,
                     step.CompletionQuestVariablesFlags, step.ComplexCombatData);
         }
     }
 
                 yield return serviceProvider.GetRequiredService<WaitAtEnd.WaitDelay>();
 
             yield return serviceProvider.GetRequiredService<DoInteract>()
-                .With(step.DataId.Value, step.TargetTerritoryId != null);
+                .With(step.DataId.Value,
+                    step.TargetTerritoryId != null || quest.Id is SatisfactionSupplyNpcId);
         }
 
         public ITask CreateTask(Quest quest, QuestSequence sequence, QuestStep step)
 
                 }
 
                 var task = serviceProvider.GetRequiredService<Use>()
-                    .With(quest.QuestElementId, step.ItemId.Value, step.CompletionQuestVariablesFlags);
+                    .With(quest.Id, step.ItemId.Value, step.CompletionQuestVariablesFlags);
                 return
                 [
                     unmount, task,
                 ITask task;
                 if (step.DataId != null)
                     task = serviceProvider.GetRequiredService<UseOnGround>()
-                        .With(quest.QuestElementId, step.DataId.Value, step.ItemId.Value, step.CompletionQuestVariablesFlags);
+                        .With(quest.Id, step.DataId.Value, step.ItemId.Value, step.CompletionQuestVariablesFlags);
                 else
                 {
                     ArgumentNullException.ThrowIfNull(step.Position);
                     task = serviceProvider.GetRequiredService<UseOnPosition>()
-                        .With(quest.QuestElementId, step.Position.Value, step.ItemId.Value,
+                        .With(quest.Id, step.Position.Value, step.ItemId.Value,
                             step.CompletionQuestVariablesFlags);
                 }
 
             else if (step.DataId != null)
             {
                 var task = serviceProvider.GetRequiredService<UseOnObject>()
-                    .With(quest.QuestElementId, step.DataId.Value, step.ItemId.Value, step.CompletionQuestVariablesFlags);
+                    .With(quest.Id, step.DataId.Value, step.ItemId.Value, step.CompletionQuestVariablesFlags);
                 return [unmount, task];
             }
             else
             {
                 var task = serviceProvider.GetRequiredService<Use>()
-                    .With(quest.QuestElementId, step.ItemId.Value, step.CompletionQuestVariablesFlags);
+                    .With(quest.Id, step.ItemId.Value, step.CompletionQuestVariablesFlags);
                 return [unmount, task];
             }
         }
 
 
                 if (!AssemblyGatheringLocationLoader.GetLocations()
                         .TryGetValue(gatheringPointId, out GatheringRoot? gatheringRoot))
-                    throw new TaskException("No path found for gathering point");
+                    throw new TaskException($"No path found for gathering point {gatheringPointId}");
 
                 if (HasRequiredItems(requiredGatheredItems))
                     continue;
 
                 return null;
 
             return serviceProvider.GetRequiredService<CheckSkip>()
-                .With(step, skipConditions ?? new(), quest.QuestElementId);
+                .With(step, skipConditions ?? new(), quest.Id);
         }
     }
 
 
             if (step.CompletionQuestVariablesFlags.Count == 6 && QuestWorkUtils.HasCompletionFlags(step.CompletionQuestVariablesFlags))
             {
                 var task = serviceProvider.GetRequiredService<WaitForCompletionFlags>()
-                    .With((QuestId)quest.QuestElementId, step);
+                    .With((QuestId)quest.Id, step);
                 var delay = serviceProvider.GetRequiredService<WaitDelay>();
                 return [task, delay, Next(quest, sequence)];
             }
                 case EInteractionType.AcceptQuest:
                 {
                     var accept = serviceProvider.GetRequiredService<WaitQuestAccepted>()
-                        .With(step.PickUpQuestId ?? quest.QuestElementId);
+                        .With(step.PickUpQuestId ?? quest.Id);
                     var delay = serviceProvider.GetRequiredService<WaitDelay>();
                     if (step.PickUpQuestId != null)
                         return [accept, delay, Next(quest, sequence)];
                 case EInteractionType.CompleteQuest:
                 {
                     var complete = serviceProvider.GetRequiredService<WaitQuestCompleted>()
-                        .With(step.TurnInQuestId ?? quest.QuestElementId);
+                        .With(step.TurnInQuestId ?? quest.Id);
                     var delay = serviceProvider.GetRequiredService<WaitDelay>();
                     if (step.TurnInQuestId != null)
                         return [complete, delay, Next(quest, sequence)];
 
         private static NextStep Next(Quest quest, QuestSequence sequence)
         {
-            return new NextStep(quest.QuestElementId, sequence.Sequence);
+            return new NextStep(quest.Id, sequence.Sequence);
         }
     }
 
 
                 aethernetGroups[(EAetheryteLocation)aetheryte.RowId] = aetheryte.AethernetGroup;
         }
 
+        aethernetNames[EAetheryteLocation.IshgardFirmament] = "Firmament";
+        territoryIds[EAetheryteLocation.IshgardFirmament] = 886;
+        aethernetGroups[EAetheryteLocation.IshgardFirmament] = aethernetGroups[EAetheryteLocation.Ishgard];
+
         AethernetNames = aethernetNames.AsReadOnly();
         TerritoryIds = territoryIds.AsReadOnly();
         AethernetGroups = aethernetGroups.AsReadOnly();
             { EAetheryteLocation.GridaniaAirship, new(24.86354f, -19.000002f, 96f) },
             { EAetheryteLocation.UldahAirship, new(-16.954851f, 82.999985f, -9.421141f) },
             { EAetheryteLocation.KuganeAirship, new(-55.72525f, 79.10602f, 46.23109f) },
+            { EAetheryteLocation.IshgardFirmament, new(9.92315f, -15.2f, 173.5059f) },
         }.AsReadOnly();
 
     public ReadOnlyDictionary<EAetheryteLocation, string> AethernetNames { get; }
 
     public bool IsCityAetheryte(EAetheryteLocation aetheryte)
     {
+        if (aetheryte == EAetheryteLocation.IshgardFirmament)
+            return true;
+
         var territoryId = TerritoryIds[aetheryte];
         return TownTerritoryIds.Contains(territoryId);
     }
 
 ï»¿using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using Dalamud.Plugin.Services;
 using Lumina.Excel.GeneratedSheets;
+using Microsoft.Extensions.Logging;
 
 namespace Questionable.Data;
 
 internal sealed class GatheringData
 {
-    private readonly Dictionary<uint, uint> _gatheringItemToItem;
     private readonly Dictionary<uint, ushort> _minerGatheringPoints = [];
     private readonly Dictionary<uint, ushort> _botanistGatheringPoints = [];
+    private readonly Dictionary<uint, ushort> _itemIdToCollectability;
+    private readonly Dictionary<uint, uint> _npcForCustomDeliveries;
 
     public GatheringData(IDataManager dataManager)
     {
-        _gatheringItemToItem = dataManager.GetExcelSheet<GatheringItem>()!
+        Dictionary<uint, uint> gatheringItemToItem = dataManager.GetExcelSheet<GatheringItem>()!
             .Where(x => x.RowId != 0 && x.Item != 0)
             .ToDictionary(x => x.RowId, x => (uint)x.Item);
 
         {
             foreach (var gatheringItemId in gatheringPointBase.Item.Where(x => x != 0))
             {
-                if (_gatheringItemToItem.TryGetValue((uint)gatheringItemId, out uint itemId))
+                if (gatheringItemToItem.TryGetValue((uint)gatheringItemId, out uint itemId))
                 {
                     if (gatheringPointBase.GatheringType.Row is 0 or 1)
                         _minerGatheringPoints[itemId] = (ushort)gatheringPointBase.RowId;
                 }
             }
         }
-    }
 
+        _itemIdToCollectability = dataManager.GetExcelSheet<SatisfactionSupply>()!
+            .Where(x => x.RowId > 0)
+            .Where(x => x.Slot is 2)
+            .Select(x => new
+            {
+                ItemId = x.Item.Row,
+                Collectability = x.CollectabilityHigh,
+            })
+            .Distinct()
+            .ToDictionary(x => x.ItemId, x => x.Collectability);
+
+        _npcForCustomDeliveries = dataManager.GetExcelSheet<SatisfactionNpc>()!
+            .Where(x => x.RowId > 0)
+            .SelectMany(x => dataManager.GetExcelSheet<SatisfactionSupply>()!
+                .Where(y => y.RowId == x.SupplyIndex.Last())
+                .Select(y => new
+                {
+                    ItemId = y.Item.Row,
+                    NpcId = x.Npc.Row
+                }))
+            .Where(x => x.ItemId > 0)
+            .Distinct()
+            .ToDictionary(x => x.ItemId, x => x.NpcId);
+    }
 
     public bool TryGetGatheringPointId(uint itemId, uint classJobId, out ushort gatheringPointId)
     {
             return false;
         }
     }
+
+    public ushort GetRecommendedCollectability(uint itemId)
+        => _itemIdToCollectability.GetValueOrDefault(itemId);
+
+    public bool TryGetCustomDeliveryNpc(uint itemId, out uint npcId)
+        => _npcForCustomDeliveries.TryGetValue(itemId, out npcId);
 }
 
         var genreLimsa = new Genre(uint.MaxValue - 3, "Starting in Limsa Lominsa", 1,
             new uint[] { 108, 109 }.Concat(limsaStart.Quest.Select(x => x.Row))
                 .Where(x => x != 0)
-                .Select(x => questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF))))
+                .Select(x => (QuestInfo)questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF))))
                 .ToList());
         var genreGridania = new Genre(uint.MaxValue - 2, "Starting in Gridania", 1,
             new uint[] { 85, 123, 124 }.Concat(gridaniaStart.Quest.Select(x => x.Row))
                 .Where(x => x != 0)
-                .Select(x => questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF))))
+                .Select(x => (QuestInfo)questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF))))
                 .ToList());
         var genreUldah = new Genre(uint.MaxValue - 1, "Starting in Ul'dah", 1,
             new uint[] { 568, 569, 570 }.Concat(uldahStart.Quest.Select(x => x.Row))
                 .Where(x => x != 0)
-                .Select(x => questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF))))
+                .Select(x => (QuestInfo)questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF))))
                 .ToList());
         genres.InsertRange(0, [genreLimsa, genreGridania, genreUldah]);
         genres.Single(x => x.Id == 1)
 
 using System.Collections.Immutable;
 using System.Linq;
 using Dalamud.Plugin.Services;
+using Lumina.Excel.GeneratedSheets;
 using Questionable.Model;
 using Questionable.Model.Questing;
 using Quest = Lumina.Excel.GeneratedSheets.Quest;
 
 internal sealed class QuestData
 {
-    private readonly ImmutableDictionary<QuestId, QuestInfo> _quests;
+    private readonly Dictionary<ElementId, IQuestInfo> _quests;
 
     public QuestData(IDataManager dataManager)
     {
-        _quests = dataManager.GetExcelSheet<Quest>()!
-            .Where(x => x.RowId > 0)
-            .Where(x => x.IssuerLocation.Row > 0)
-            .Where(x => x.Festival.Row == 0)
-            .Select(x => new QuestInfo(x))
-            .ToImmutableDictionary(x => x.QuestId, x => x);
+        List<IQuestInfo> quests =
+        [
+            ..dataManager.GetExcelSheet<Quest>()!
+                .Where(x => x.RowId > 0)
+                .Where(x => x.IssuerLocation.Row > 0)
+                .Where(x => x.Festival.Row == 0)
+                .Select(x => new QuestInfo(x)),
+            ..dataManager.GetExcelSheet<SatisfactionNpc>()!
+                .Where(x => x.RowId > 0)
+                .Select(x => new SatisfactionSupplyInfo(x))
+        ];
+        _quests = quests.ToDictionary(x => x.QuestId, x => x);
     }
 
-    public QuestInfo GetQuestInfo(ElementId elementId)
+    public IQuestInfo GetQuestInfo(ElementId elementId)
     {
-        if (elementId is QuestId questId)
-            return GetQuestInfo(questId);
-
-        throw new ArgumentException("Invalid id", nameof(elementId));
-    }
-
-    public QuestInfo GetQuestInfo(QuestId questId)
-    {
-        return _quests[questId] ?? throw new ArgumentOutOfRangeException(nameof(questId));
+        return _quests[elementId] ?? throw new ArgumentOutOfRangeException(nameof(elementId));
     }
 
-    public List<QuestInfo> GetAllByIssuerDataId(uint targetId)
+    public List<IQuestInfo> GetAllByIssuerDataId(uint targetId)
     {
         return _quests.Values
             .Where(x => x.IssuerDataId == targetId)
     public List<QuestInfo> GetAllByJournalGenre(uint journalGenre)
     {
         return _quests.Values
+            .Where(x => x is QuestInfo)
+            .Cast<QuestInfo>()
             .Where(x => x.JournalGenre == journalGenre)
             .OrderBy(x => x.SortKey)
             .ThenBy(x => x.QuestId)
 
 
     public bool Teleport(EAetheryteLocation aetheryteLocation)
     {
+        if (aetheryteLocation == EAetheryteLocation.IshgardFirmament)
+        {
+            // TODO does this even work on non-EN clients?
+            return _aethernetTeleport.InvokeFunc("Firmament");
+        }
+
         if (!_aetheryteData.AethernetNames.TryGetValue(aetheryteLocation, out string? name))
             return false;
 
 
     {
         if (elementId is QuestId questId)
             return IsReadyToAcceptQuest(questId);
-        return false;
+        else if (elementId is SatisfactionSupplyNpcId)
+            return true;
+        else
+            throw new ArgumentOutOfRangeException(nameof(elementId));
     }
 
     public bool IsReadyToAcceptQuest(QuestId questId)
     {
         if (elementId is QuestId questId)
             return IsQuestAccepted(questId);
-        return false;
+        else if (elementId is SatisfactionSupplyNpcId)
+            return false;
+        else
+            throw new ArgumentOutOfRangeException(nameof(elementId));
     }
 
     public bool IsQuestAccepted(QuestId questId)
     {
         if (elementId is QuestId questId)
             return IsQuestComplete(questId);
-        return false;
+        else if (elementId is SatisfactionSupplyNpcId)
+            return false;
+        else
+            throw new ArgumentOutOfRangeException(nameof(elementId));
     }
 
     [SuppressMessage("Performance", "CA1822")]
     {
         if (elementId is QuestId questId)
             return IsQuestLocked(questId, extraCompletedQuest);
-        return false;
+        else if (elementId is SatisfactionSupplyNpcId)
+            return false;
+        else
+            throw new ArgumentOutOfRangeException(nameof(elementId));
     }
 
     public bool IsQuestLocked(QuestId questId, ElementId? extraCompletedQuest = null)
     {
-        var questInfo = _questData.GetQuestInfo(questId);
+        var questInfo = (QuestInfo) _questData.GetQuestInfo(questId);
         if (questInfo.QuestLocks.Count > 0)
         {
             var completedQuests = questInfo.QuestLocks.Count(x => IsQuestComplete(x) || x.Equals(extraCompletedQuest));
     }
 
     public bool IsAetheryteUnlocked(EAetheryteLocation aetheryteLocation)
-        => IsAetheryteUnlocked((uint)aetheryteLocation, out _);
+    {
+        if (aetheryteLocation == EAetheryteLocation.IshgardFirmament)
+            return IsQuestComplete(new QuestId(3672));
+        return IsAetheryteUnlocked((uint)aetheryteLocation, out _);
+    }
 
     public bool CanTeleport(EAetheryteLocation aetheryteLocation)
     {
         if (excelSheetName == null)
         {
             var questRow =
-                _dataManager.GetExcelSheet<Lumina.Excel.GeneratedSheets2.Quest>()!.GetRow((uint)currentQuest.QuestElementId.Value +
+                _dataManager.GetExcelSheet<Lumina.Excel.GeneratedSheets2.Quest>()!.GetRow((uint)currentQuest.Id.Value +
                     0x10000);
             if (questRow == null)
             {
-                _logger.LogError("Could not find quest row for {QuestId}", currentQuest.QuestElementId);
+                _logger.LogError("Could not find quest row for {QuestId}", currentQuest.Id);
                 return null;
             }
 
-            excelSheetName = $"quest/{(currentQuest.QuestElementId.Value / 100):000}/{questRow.Id}";
+            excelSheetName = $"quest/{(currentQuest.Id.Value / 100):000}/{questRow.Id}";
         }
 
         var excelSheet = _dataManager.Excel.GetSheet<QuestDialogueText>(excelSheetName);
 
--- /dev/null
+using System;
+using Dalamud.Game.Text;
+using Questionable.Model.Questing;
+
+namespace Questionable.Model;
+
+public interface IQuestInfo
+{
+    public ElementId QuestId { get; }
+    public string Name { get; }
+    public uint IssuerDataId { get; }
+    public bool IsRepeatable { get; }
+    public ushort Level { get; }
+    public EBeastTribe BeastTribe { get; }
+    public bool IsMainScenarioQuest { get; }
+
+    public string SimplifiedName => Name
+        .Replace(".", "", StringComparison.Ordinal)
+        .TrimStart(SeIconChar.QuestSync.ToIconChar(), SeIconChar.QuestRepeatable.ToIconChar(), ' ');
+}
 
 
 internal sealed class Quest
 {
-    public required ElementId QuestElementId { get; init; }
+    public required ElementId Id { get; init; }
     public required QuestRoot Root { get; init; }
-    public required QuestInfo Info { get; init; }
+    public required IQuestInfo Info { get; init; }
     public required bool ReadOnly { get; init; }
 
     public QuestSequence? FindSequence(byte currentSequence)
 
 
 namespace Questionable.Model;
 
-internal sealed class QuestInfo
+internal sealed class QuestInfo : IQuestInfo
 {
     public QuestInfo(ExcelQuest quest)
     {
     }
 
 
-    public QuestId QuestId { get; }
+    public ElementId QuestId { get; }
     public string Name { get; }
     public ushort Level { get; }
     public uint IssuerDataId { get; }
     public GrandCompany GrandCompany { get; }
     public EBeastTribe BeastTribe { get; }
 
-    public string SimplifiedName => Name
-        .Replace(".", "", StringComparison.Ordinal)
-        .TrimStart(SeIconChar.QuestSync.ToIconChar(), SeIconChar.QuestRepeatable.ToIconChar(), ' ');
-
     [UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.Members)]
     public enum QuestJoin : byte
     {
 
--- /dev/null
+using Lumina.Excel.GeneratedSheets;
+using Questionable.Model.Questing;
+
+namespace Questionable.Model;
+
+internal sealed class SatisfactionSupplyInfo : IQuestInfo
+{
+    public SatisfactionSupplyInfo(SatisfactionNpc npc)
+    {
+        QuestId = new SatisfactionSupplyNpcId((ushort)npc.RowId);
+        Name = npc.Npc.Value!.Singular;
+        IssuerDataId = npc.Npc.Row;
+        Level = npc.LevelUnlock;
+    }
+
+    public ElementId QuestId { get; }
+    public string Name { get; }
+    public uint IssuerDataId { get; }
+    public bool IsRepeatable => true;
+    public ushort Level { get; }
+    public EBeastTribe BeastTribe => EBeastTribe.None;
+    public bool IsMainScenarioQuest => false;
+}
 
         IChatGui chatGui,
         ICommandManager commandManager,
         IAddonLifecycle addonLifecycle,
-        IKeyState keyState)
+        IKeyState keyState,
+        IContextMenu contextMenu)
     {
         ArgumentNullException.ThrowIfNull(pluginInterface);
 
         serviceCollection.AddSingleton(commandManager);
         serviceCollection.AddSingleton(addonLifecycle);
         serviceCollection.AddSingleton(keyState);
+        serviceCollection.AddSingleton(contextMenu);
         serviceCollection.AddSingleton(new WindowSystem(nameof(Questionable)));
         serviceCollection.AddSingleton((Configuration?)pluginInterface.GetPluginConfig() ?? new Configuration());
 
         _serviceProvider = serviceCollection.BuildServiceProvider();
         _serviceProvider.GetRequiredService<QuestRegistry>().Reload();
         _serviceProvider.GetRequiredService<CommandHandler>();
+        _serviceProvider.GetRequiredService<ContextMenuController>();
         _serviceProvider.GetRequiredService<DalamudInitializer>();
     }
 
         serviceCollection.AddSingleton<NavigationShortcutController>();
         serviceCollection.AddSingleton<CombatController>();
         serviceCollection.AddSingleton<GatheringController>();
+        serviceCollection.AddSingleton<ContextMenuController>();
 
         serviceCollection.AddSingleton<ICombatModule, RotationSolverRebornModule>();
     }
 
     public IEnumerable<ValidationIssue> Validate(Quest quest)
     {
         return quest.AllSteps()
-            .Select(x => Validate(quest.QuestElementId, x.Sequence.Sequence, x.StepId, x.Step.AethernetShortcut))
+            .Select(x => Validate(quest.Id, x.Sequence.Sequence, x.StepId, x.Step.AethernetShortcut))
             .Where(x => x != null)
             .Cast<ValidationIssue>();
     }
 
         {
             yield return new ValidationIssue
             {
-                QuestId = quest.QuestElementId,
+                QuestId = quest.Id,
                 Sequence = 0,
                 Step = null,
                 Type = EIssueType.MissingSequence0,
             yield break;
         }
 
-        if (quest.Info.CompletesInstantly)
+        if (quest.Info is QuestInfo { CompletesInstantly: true })
         {
             foreach (var sequence in sequences)
             {
 
                 yield return new ValidationIssue
                 {
-                    QuestId = quest.QuestElementId,
+                    QuestId = quest.Id,
                     Sequence = (byte)sequence.Sequence,
                     Step = null,
                     Type = EIssueType.InstantQuestWithMultipleSteps,
                 };
             }
         }
-        else
+        else if (quest.Info is QuestInfo)
         {
             int maxSequence = sequences.Select(x => x.Sequence)
                 .Where(x => x != 255)
         {
             return new ValidationIssue
             {
-                QuestId = quest.QuestElementId,
+                QuestId = quest.Id,
                 Sequence = (byte)sequenceNo,
                 Step = null,
                 Type = EIssueType.MissingSequence,
         {
             return new ValidationIssue
             {
-                QuestId = quest.QuestElementId,
+                QuestId = quest.Id,
                 Sequence = (byte)sequenceNo,
                 Step = null,
                 Type = EIssueType.DuplicateSequence,
 
                 {
                     yield return new ValidationIssue
                     {
-                        QuestId = quest.QuestElementId,
+                        QuestId = quest.Id,
                         Sequence = (byte)sequence.Sequence,
                         Step = i,
                         Type = EIssueType.DuplicateCompletionFlags,
 
     {
         _questSchema ??= JsonSchema.FromStream(AssemblyQuestLoader.QuestSchema).AsTask().Result;
 
-        if (_questNodes.TryGetValue(quest.QuestElementId, out JsonNode? questNode))
+        if (_questNodes.TryGetValue(quest.Id, out JsonNode? questNode))
         {
             var evaluationResult = _questSchema.Evaluate(questNode, new EvaluationOptions
             {
             {
                 yield return new ValidationIssue
                 {
-                    QuestId = quest.QuestElementId,
+                    QuestId = quest.Id,
                     Sequence = null,
                     Step = null,
                     Type = EIssueType.InvalidJsonSchema,
 
 {
     public IEnumerable<ValidationIssue> Validate(Quest quest)
     {
-        foreach (var invalidNextQuest in quest.AllSteps().Where(x => x.Step.NextQuestId == quest.QuestElementId))
+        foreach (var invalidNextQuest in quest.AllSteps().Where(x => x.Step.NextQuestId == quest.Id))
         {
             yield return new ValidationIssue
             {
-                QuestId = quest.QuestElementId,
+                QuestId = quest.Id,
                 Sequence = (byte)invalidNextQuest.Sequence.Sequence,
                 Step = invalidNextQuest.StepId,
                 Type = EIssueType.InvalidNextQuestId,
 
         {
             yield return new ValidationIssue
             {
-                QuestId = quest.QuestElementId,
+                QuestId = quest.Id,
                 Sequence = null,
                 Step = null,
                 Type = EIssueType.QuestDisabled,
 
 {
     public IEnumerable<ValidationIssue> Validate(Quest quest)
     {
+        if (quest.Id is SatisfactionSupplyNpcId)
+            yield break;
+
         var questAccepts = FindQuestStepsWithInteractionType(quest, EInteractionType.AcceptQuest)
             .Where(x => x.Step.PickUpQuestId == null)
             .ToList();
             {
                 yield return new ValidationIssue
                 {
-                    QuestId = quest.QuestElementId,
+                    QuestId = quest.Id,
                     Sequence = (byte)accept.Sequence.Sequence,
                     Step = accept.StepId,
                     Type = EIssueType.UnexpectedAcceptQuestStep,
         {
             yield return new ValidationIssue
             {
-                QuestId = quest.QuestElementId,
+                QuestId = quest.Id,
                 Sequence = 0,
                 Step = null,
                 Type = EIssueType.MissingQuestAccept,
             {
                 yield return new ValidationIssue
                 {
-                    QuestId = quest.QuestElementId,
+                    QuestId = quest.Id,
                     Sequence = (byte)complete.Sequence.Sequence,
                     Step = complete.StepId,
                     Type = EIssueType.UnexpectedCompleteQuestStep,
         {
             yield return new ValidationIssue
             {
-                QuestId = quest.QuestElementId,
+                QuestId = quest.Id,
                 Sequence = 255,
                 Step = null,
                 Type = EIssueType.MissingQuestComplete,
 
                 QuestStep? step = sequence.FindStep(i);
                 if (step != null && TryGetPosition(step, out Vector3? position))
                 {
-                    DrawStep($"{quest.QuestElementId} / {sequence.Sequence} / {i}", step, position.Value, 0xFFFFFFFF);
+                    DrawStep($"{quest.Id} / {sequence.Sequence} / {i}", step, position.Value, 0xFFFFFFFF);
                 }
             }
         }
 
 
         if (ImGui.IsItemClicked() && _commandManager.Commands.TryGetValue("/questinfo", out var commandInfo))
         {
-            _commandManager.DispatchCommand("/questinfo", questInfo.QuestId.ToString(), commandInfo);
+            _commandManager.DispatchCommand("/questinfo", questInfo.QuestId.ToString() ?? string.Empty, commandInfo);
         }
 
         if (ImGui.IsItemHovered())
 
     {
         var currentQuestDetails = _questController.CurrentQuestDetails;
         QuestController.QuestProgress? currentQuest = currentQuestDetails?.Progress;
-        QuestController.CurrentQuestType? currentQuestType = currentQuestDetails?.Type;
+        QuestController.ECurrentQuestType? currentQuestType = currentQuestDetails?.Type;
         if (currentQuest != null)
         {
             DrawQuestNames(currentQuest, currentQuestType);
     }
 
     private void DrawQuestNames(QuestController.QuestProgress currentQuest,
-        QuestController.CurrentQuestType? currentQuestType)
+        QuestController.ECurrentQuestType? currentQuestType)
     {
-        if (currentQuestType == QuestController.CurrentQuestType.Simulated)
+        if (currentQuestType == QuestController.ECurrentQuestType.Simulated)
         {
             using var _ = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
             ImGui.TextUnformatted(
 
     private QuestWork? DrawQuestWork(QuestController.QuestProgress currentQuest)
     {
-        if (currentQuest.Quest.QuestElementId is not QuestId questId)
+        if (currentQuest.Quest.Id is not QuestId questId)
             return null;
 
         var questWork = _gameFunctions.GetQuestEx(questId);
         {
             using var disabled = ImRaii.Disabled();
 
-            if (currentQuest.Quest.QuestElementId == _questController.NextQuest?.Quest.QuestElementId)
+            if (currentQuest.Quest.Id == _questController.NextQuest?.Quest.Id)
                 ImGui.TextUnformatted("(Next quest in story line not accepted)");
             else
                 ImGui.TextUnformatted("(Not accepted)");
             if (questWork == null)
                 _questController.SetNextQuest(currentQuest.Quest);
 
-            _questController.ExecuteNextStep(true);
+            _questController.ExecuteNextStep(QuestController.EAutomationType.Automatic);
         }
 
         ImGui.SameLine();
 
         if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.StepForward, "Step"))
         {
-            _questController.ExecuteNextStep(false);
+            _questController.ExecuteNextStep(QuestController.EAutomationType.Manual);
         }
 
         ImGui.EndDisabled();
         if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.ArrowCircleRight, "Skip"))
         {
             _movementController.Stop();
-            _questController.Skip(currentQuest.Quest.QuestElementId, currentQuest.Sequence);
+            _questController.Skip(currentQuest.Quest.Id, currentQuest.Sequence);
         }
 
         if (colored)
             ImGui.SameLine();
             if (ImGuiComponents.IconButton(FontAwesomeIcon.Atlas))
                 _commandManager.DispatchCommand("/questinfo",
-                    currentQuest.Quest.QuestElementId.ToString() ?? string.Empty, commandInfo);
+                    currentQuest.Quest.Id.ToString() ?? string.Empty, commandInfo);
         }
 
         bool autoAcceptNextQuest = _configuration.General.AutoAcceptNextQuest;
 
 using Questionable.Controller;
 using Questionable.Data;
 using Questionable.Model;
+using Questionable.Model.Questing;
 
 namespace Questionable.Windows.QuestComponents;
 
         _uiUtils = uiUtils;
     }
 
+    public void Draw(IQuestInfo quest)
+    {
+        if (quest is QuestInfo questInfo)
+            Draw(questInfo);
+    }
+
     public void Draw(QuestInfo quest)
     {
         using var tooltip = ImRaii.Tooltip();
 
                 _uiUtils.ChecklistItem(FormatQuestUnlockName(qInfo), iconColor, icon);
 
-                if (counter <= 2 || icon != FontAwesomeIcon.Check)
-                    DrawQuestUnlocks(qInfo, counter + 1);
+                if (qInfo is QuestInfo qstInfo && (counter <= 2 || icon != FontAwesomeIcon.Check))
+                    DrawQuestUnlocks(qstInfo, counter + 1);
             }
         }
 
             ImGui.Unindent();
     }
 
-    private static string FormatQuestUnlockName(QuestInfo questInfo)
+    private static string FormatQuestUnlockName(IQuestInfo questInfo)
     {
         if (questInfo.IsMainScenarioQuest)
             return $"{questInfo.Name} ({questInfo.QuestId}, MSQ)";
 
     private readonly UiUtils _uiUtils;
     private readonly QuestTooltipComponent _questTooltipComponent;
 
-    private List<QuestInfo> _quests = [];
-    private List<QuestInfo> _offeredQuests = [];
+    private List<IQuestInfo> _quests = [];
+    private List<IQuestInfo> _offeredQuests = [];
     private bool _onlyAvailableQuests = true;
 
     public QuestSelectionWindow(QuestData questData, IGameGui gameGui, IChatGui chatGui, GameFunctions gameFunctions,
 
         _quests = _questRegistry.AllQuests
             .Where(x => x.FindSequence(0)?.FindStep(0)?.TerritoryId == territoryId)
-            .Select(x => _questData.GetQuestInfo(x.QuestElementId))
+            .Select(x => _questData.GetQuestInfo(x.Id))
             .ToList();
 
         foreach (var unacceptedQuest in Map.Instance()->UnacceptedQuestMarkers)
         ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, actionIconSize);
         ImGui.TableHeadersRow();
 
-        foreach (QuestInfo quest in (_offeredQuests.Count != 0 && _onlyAvailableQuests) ? _offeredQuests : _quests)
+        foreach (IQuestInfo quest in (_offeredQuests.Count != 0 && _onlyAvailableQuests) ? _offeredQuests : _quests)
         {
             ImGui.TableNextRow();
 
-            string questId = quest.QuestId.ToString();
+            string questId = quest.QuestId.ToString() ?? string.Empty;
             bool isKnownQuest = _questRegistry.TryGetQuest(quest.QuestId, out var knownQuest);
 
             if (ImGui.TableNextColumn())
                     if (startNextQuest)
                     {
                         _questController.SetNextQuest(knownQuest);
-                        _questController.ExecuteNextStep(true);
+                        _questController.ExecuteNextStep(QuestController.EAutomationType.Automatic);
                     }
 
                     ImGui.SameLine();
         }
     }
 
-    private void CopyToClipboard(QuestInfo quest, bool suffix)
+    private void CopyToClipboard(IQuestInfo quest, bool suffix)
     {
         string fileName = $"{quest.QuestId}_{quest.SimplifiedName}{(suffix ? ".json" : "")}";
         ImGui.SetClipboardText(fileName);
 
     public (Vector4 color, FontAwesomeIcon icon, string status) GetQuestStyle(ElementId questElementId)
     {
         if (_gameFunctions.IsQuestAccepted(questElementId))
-            return (ImGuiColors.DalamudYellow, FontAwesomeIcon.Running, "Active");
+            return (ImGuiColors.DalamudYellow, FontAwesomeIcon.PersonWalkingArrowRight, "Active");
         else if (_gameFunctions.IsQuestAcceptedOrComplete(questElementId))
             return (ImGuiColors.ParsedGreen, FontAwesomeIcon.Check, "Complete");
         else if (_gameFunctions.IsQuestLocked(questElementId))
             return (ImGuiColors.DalamudRed, FontAwesomeIcon.Times, "Locked");
         else
-            return (ImGuiColors.DalamudYellow, FontAwesomeIcon.PersonWalkingArrowRight, "Available");
+            return (ImGuiColors.DalamudYellow, FontAwesomeIcon.Running, "Available");
     }
 
     public static (Vector4 color, FontAwesomeIcon icon) GetInstanceStyle(ushort instanceId)
         if (UIState.IsInstanceContentCompleted(instanceId))
             return (ImGuiColors.ParsedGreen, FontAwesomeIcon.Check);
         else if (UIState.IsInstanceContentUnlocked(instanceId))
-            return (ImGuiColors.DalamudYellow, FontAwesomeIcon.PersonWalkingArrowRight);
+            return (ImGuiColors.DalamudYellow, FontAwesomeIcon.Running);
         else
             return (ImGuiColors.DalamudRed, FontAwesomeIcon.Times);
     }