internal sealed class MovementController : IDisposable
 {
+    public const float DefaultStopDistance = 3f;
     private readonly NavmeshIpc _navmeshIpc;
     private readonly IClientState _clientState;
     private readonly GameFunctions _gameFunctions;
     public bool IsNavmeshReady => _navmeshIpc.IsReady;
     public bool IsPathRunning => _navmeshIpc.IsPathRunning;
     public bool IsPathfinding => _pathfindTask is { IsCompleted: false };
+    public Vector3? Destination { get; private set; }
+    public float StopDistance { get; private set; }
 
     public void Update()
     {
                 ResetPathfinding();
             }
         }
+
+        if (IsPathRunning && Destination != null)
+        {
+            Vector3 localPlayerPosition = _clientState.LocalPlayer?.Position ?? Vector3.Zero;
+            if ((localPlayerPosition - Destination.Value).Length() < StopDistance)
+                Stop();
+        }
     }
 
-    public void NavigateTo(EMovementType type, Vector3 to, bool fly)
+    public void NavigateTo(EMovementType type, Vector3 to, bool fly, float? stopDistance = null)
     {
         ResetPathfinding();
 
+
         _gameFunctions.ExecuteCommand("/automove off");
 
+        Destination = to;
+        StopDistance = stopDistance ?? (DefaultStopDistance - 0.2f);
         _cancellationTokenSource = new();
         _cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(10));
         _pathfindTask =
 
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
 using System.IO;
+using System.Numerics;
 using System.Text.Json;
+using Dalamud.Game.ClientState.Conditions;
 using Dalamud.Plugin;
+using Dalamud.Plugin.Services;
+using FFXIVClientStructs.FFXIV.Client.Game;
+using FFXIVClientStructs.FFXIV.Client.Game.Object;
+using Questionable.Data;
 using Questionable.Model.V1;
 
 namespace Questionable.Controller;
 
 internal sealed class QuestController
 {
+    private readonly IClientState _clientState;
+    private readonly GameFunctions _gameFunctions;
+    private readonly MovementController _movementController;
+    private readonly IPluginLog _pluginLog;
+    private readonly ICondition _condition;
+    private readonly IChatGui _chatGui;
+    private readonly ICommandManager _commandManager;
+    private readonly AetheryteData _aetheryteData;
+    private readonly TerritoryData _territoryData;
     private readonly Dictionary<ushort, Quest> _quests = new();
 
-    public QuestController(DalamudPluginInterface pluginInterface)
+    public QuestController(DalamudPluginInterface pluginInterface, IDataManager dataManager, IClientState clientState,
+        GameFunctions gameFunctions, MovementController movementController, IPluginLog pluginLog, ICondition condition,
+        IChatGui chatGui, ICommandManager commandManager)
     {
+        _clientState = clientState;
+        _gameFunctions = gameFunctions;
+        _movementController = movementController;
+        _pluginLog = pluginLog;
+        _condition = condition;
+        _chatGui = chatGui;
+        _commandManager = commandManager;
+        _aetheryteData = new AetheryteData(dataManager);
+        _territoryData = new TerritoryData(dataManager);
 #if false
         LoadFromEmbeddedResources();
 #endif
         LoadFromDirectory(new DirectoryInfo(@"E:\ffxiv\Questionable\Questionable\QuestPaths"));
         LoadFromDirectory(pluginInterface.ConfigDirectory);
+
+        foreach (var (questId, quest) in _quests)
+        {
+            var questData =
+                dataManager.GetExcelSheet<Lumina.Excel.GeneratedSheets.Quest>()!.GetRow((uint)questId + 0x10000);
+            if (questData == null)
+                continue;
+
+            quest.Name = questData.Name.ToString();
+        }
     }
 
 #if false
     }
 #endif
 
+    public QuestProgress? CurrentQuest { get; set; }
+    public string? DebugState { get; set; }
+
     private void LoadFromDirectory(DirectoryInfo configDirectory)
     {
         foreach (FileInfo fileInfo in configDirectory.GetFiles("*.json"))
         {
-            using FileStream stream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read);
-            var (questId, name) = ExtractQuestDataFromName(fileInfo.Name);
-            Quest quest = new Quest
+            try
             {
-                FilePath = fileInfo.FullName,
-                QuestId = questId,
-                Name = name,
-                Data = JsonSerializer.Deserialize<QuestData>(stream)!,
-            };
-            _quests[questId] = quest;
+                using FileStream stream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read);
+                var (questId, name) = ExtractQuestDataFromName(fileInfo.Name);
+                Quest quest = new Quest
+                {
+                    FilePath = fileInfo.FullName,
+                    QuestId = questId,
+                    Name = name,
+                    Data = JsonSerializer.Deserialize<QuestData>(stream)!,
+                };
+                _quests[questId] = quest;
+            }
+            catch (Exception e)
+            {
+                throw new InvalidDataException($"Unable to load file {fileInfo.FullName}", e);
+            }
         }
 
         foreach (DirectoryInfo childDirectory in configDirectory.GetDirectories())
         string name = resourceName.Substring(0, resourceName.Length - ".json".Length);
         name = name.Substring(name.LastIndexOf('.') + 1);
 
-        ushort questId = ushort.Parse(name.Substring(0, name.IndexOf('_')));
-        return (questId, name);
+        string[] parts = name.Split('_', 2);
+        return (ushort.Parse(parts[0], CultureInfo.InvariantCulture), parts[1]);
+    }
+
+    public void Update()
+    {
+        (ushort currentQuestId, byte currentSequence) = _gameFunctions.GetCurrentQuest();
+        if (currentQuestId == 0)
+        {
+            if (CurrentQuest != null)
+                CurrentQuest = null;
+        }
+        else if (CurrentQuest == null || CurrentQuest.Quest.QuestId != currentQuestId)
+        {
+            if (_quests.TryGetValue(currentQuestId, out var quest))
+                CurrentQuest = new QuestProgress(quest, currentSequence, 0);
+            else if (CurrentQuest != null)
+                CurrentQuest = null;
+        }
+
+        if (CurrentQuest == null)
+        {
+            DebugState = "No quest active";
+            return;
+        }
+
+        if (_condition[ConditionFlag.Occupied] || _condition[ConditionFlag.Occupied30] ||
+            _condition[ConditionFlag.Occupied33] || _condition[ConditionFlag.Occupied38] ||
+            _condition[ConditionFlag.Occupied39] || _condition[ConditionFlag.OccupiedInEvent] ||
+            _condition[ConditionFlag.OccupiedInQuestEvent] || _condition[ConditionFlag.OccupiedInCutSceneEvent] ||
+            _condition[ConditionFlag.Casting] || _condition[ConditionFlag.Unknown57])
+        {
+            DebugState = "Occupied";
+            return;
+        }
+
+        if (!_movementController.IsNavmeshReady)
+        {
+            DebugState = "Navmesh not ready";
+            return;
+        }
+        else if (_movementController.IsPathfinding || _movementController.IsPathRunning)
+        {
+            DebugState = "Path is running";
+            return;
+        }
+
+        if (CurrentQuest.Sequence != currentSequence)
+            CurrentQuest = CurrentQuest with { Sequence = currentSequence, Step = 0 };
+
+        var q = CurrentQuest.Quest;
+        var sequence = q.FindSequence(CurrentQuest.Sequence);
+        if (sequence == null)
+        {
+            DebugState = "Sequence not found";
+            return;
+        }
+
+        if (CurrentQuest.Step == 255)
+        {
+            DebugState = "Step completed";
+            return;
+        }
+
+        if (CurrentQuest.Step >= sequence.Steps.Count)
+        {
+            DebugState = "Step not found";
+            return;
+        }
+
+        var step = sequence.Steps[CurrentQuest.Step];
+        DebugState = step.Comment ?? sequence.Comment ?? q.Data.Comment;
+    }
+
+    public (QuestSequence? Sequence, QuestStep? Step) GetNextStep()
+    {
+        if (CurrentQuest == null)
+            return (null, null);
+
+        var q = CurrentQuest.Quest;
+        var seq = q.FindSequence(CurrentQuest.Sequence);
+        if (seq == null)
+            return (null, null);
+
+        if (CurrentQuest.Step >= seq.Steps.Count)
+            return (null, null);
+
+        return (seq, seq.Steps[CurrentQuest.Step]);
+    }
+
+    public void IncreaseStepCount()
+    {
+        (QuestSequence? seq, QuestStep? step) = GetNextStep();
+        if (seq == null || step == null)
+            return;
+
+        Debug.Assert(CurrentQuest != null, nameof(CurrentQuest) + " != null");
+        if (CurrentQuest.Step + 1 < seq.Steps.Count)
+        {
+            CurrentQuest = CurrentQuest with
+            {
+                Step = CurrentQuest.Step + 1,
+                AetheryteShortcutUsed = false,
+                AethernetShortcutUsed = false
+            };
+        }
+        else
+        {
+            CurrentQuest = CurrentQuest with
+            {
+                Step = 255,
+                AetheryteShortcutUsed = false,
+                AethernetShortcutUsed = false
+            };
+        }
+    }
+
+    public void ExecuteNextStep()
+    {
+        (QuestSequence? seq, QuestStep? step) = GetNextStep();
+        if (seq == null || step == null)
+            return;
+
+        Debug.Assert(CurrentQuest != null, nameof(CurrentQuest) + " != null");
+        if (!CurrentQuest.AetheryteShortcutUsed && step.AetheryteShortcut != null)
+        {
+            bool skipTeleport = false;
+            ushort territoryType = _clientState.TerritoryType;
+            if (step.TerritoryId == territoryType)
+            {
+                Vector3 playerPosition = _clientState.LocalPlayer!.Position;
+                if (_aetheryteData.CalculateDistance(playerPosition, territoryType, step.AetheryteShortcut.Value) < 11 ||
+                    (step.AethernetShortcut != null &&
+                     (_aetheryteData.CalculateDistance(playerPosition, territoryType, step.AethernetShortcut.From) < 11 ||
+                      _aetheryteData.CalculateDistance(playerPosition, territoryType, step.AethernetShortcut.To) < 11)))
+                {
+                    skipTeleport = true;
+                }
+            }
+
+            if (skipTeleport)
+            {
+                CurrentQuest = CurrentQuest with { AetheryteShortcutUsed = true };
+            }
+            else
+            {
+                if (step.AetheryteShortcut != null)
+                {
+                    if (!_gameFunctions.IsAetheryteUnlocked(step.AetheryteShortcut.Value))
+                        _chatGui.Print($"[Questionable] Aetheryte {step.AetheryteShortcut.Value} is not unlocked.");
+                    else if (_gameFunctions.TeleportAetheryte(step.AetheryteShortcut.Value))
+                        CurrentQuest = CurrentQuest with { AetheryteShortcutUsed = true };
+                    else
+                        _chatGui.Print("[Questionable] Unable to teleport to aetheryte.");
+                }
+                else
+                    _chatGui.Print("[Questionable] No aetheryte for teleport set.");
+
+                return;
+            }
+        }
+
+        if (!CurrentQuest.AethernetShortcutUsed)
+        {
+            if (step.AethernetShortcut != null)
+            {
+                EAetheryteLocation from = step.AethernetShortcut.From;
+                EAetheryteLocation to = step.AethernetShortcut.To;
+                ushort territoryType = _clientState.TerritoryType;
+                Vector3 playerPosition = _clientState.LocalPlayer!.Position;
+
+                // closer to the source
+                if (_aetheryteData.CalculateDistance(playerPosition, territoryType, from) <
+                    _aetheryteData.CalculateDistance(playerPosition, territoryType, to))
+                {
+                    if (_aetheryteData.CalculateDistance(playerPosition, territoryType, from) < 11)
+                    {
+                        // unsure if this works across languages
+                        _commandManager.ProcessCommand(
+                            $"/li {_aetheryteData.AethernetNames[step.AethernetShortcut.To].Replace("The ", "", StringComparison.Ordinal)}");
+                        CurrentQuest = CurrentQuest with { AethernetShortcutUsed = true };
+                    }
+                    else
+                        _movementController.NavigateTo(EMovementType.Quest, _aetheryteData.Locations[from], false,
+                            6.9f);
+
+                    return;
+                }
+            }
+        }
+
+        if (step.Position != null)
+        {
+            float distance;
+            if (step.InteractionType == EInteractionType.WalkTo)
+                distance = step.StopDistance ?? 0.25f;
+            else
+                distance = step.StopDistance ?? MovementController.DefaultStopDistance;
+
+            var position = _clientState.LocalPlayer?.Position ?? new Vector3();
+            float actualDistance = (position - step.Position.Value).Length();
+            if (actualDistance > 30f && !_condition[ConditionFlag.Mounted] &&
+                _territoryData.CanUseMount(_clientState.TerritoryType))
+            {
+                unsafe
+                {
+                    ActionManager.Instance()->UseAction(ActionType.Mount, 71);
+                }
+
+                return;
+            }
+            else if (actualDistance > distance)
+            {
+                _movementController.NavigateTo(EMovementType.Quest, step.Position.Value,
+                    _gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType), distance);
+                return;
+            }
+        }
+
+        switch (step.InteractionType)
+        {
+            case EInteractionType.Interact:
+            case EInteractionType.AttuneAetheryte:
+            case EInteractionType.AttuneAethernetShard:
+            case EInteractionType.AttuneAetherCurrent:
+                if (step.DataId != null)
+                {
+                    _gameFunctions.InteractWith(step.DataId.Value);
+                    IncreaseStepCount();
+                }
+
+                break;
+
+            case EInteractionType.WalkTo:
+                IncreaseStepCount();
+                break;
+
+            default:
+                _pluginLog.Warning($"Action '{step.InteractionType}' is not implemented");
+                break;
+        }
     }
+
+    public sealed record QuestProgress(
+        Quest Quest,
+        byte Sequence,
+        int Step,
+        bool AetheryteShortcutUsed = false,
+        bool AethernetShortcutUsed = false);
 }
 
--- /dev/null
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Numerics;
+using Dalamud.Plugin.Services;
+using Lumina.Excel.GeneratedSheets2;
+using Questionable.Model.V1;
+
+namespace Questionable.Data;
+
+internal sealed class AetheryteData
+{
+    public ReadOnlyDictionary<EAetheryteLocation, Vector3> Locations { get; } =
+        new Dictionary<EAetheryteLocation, Vector3>
+            {
+                { EAetheryteLocation.Gridania, new(32.913696f, 2.670288f, 30.014404f) },
+                { EAetheryteLocation.GridaniaArcher, new(166.58276f, -1.7243042f, 86.13721f) },
+                { EAetheryteLocation.GridaniaLeatherworker, new(101.27405f, 9.018005f, -111.31464f) },
+                { EAetheryteLocation.GridaniaLancer, new(121.23291f, 12.649658f, -229.63306f) },
+                { EAetheryteLocation.GridaniaConjurer, new(-145.15906f, 4.9591064f, -11.7647705f) },
+                { EAetheryteLocation.GridaniaBotanist, new(-311.0857f, 7.94989f, -177.05048f) },
+                { EAetheryteLocation.GridaniaAmphitheatre, new(-73.92999f, 7.9804688f, -140.15417f) },
+
+                { EAetheryteLocation.Uldah, new(-144.51825f, -1.3580933f, -169.6651f) },
+                { EAetheryteLocation.UldahAdventurers, new(64.22522f, 4.5318604f, -115.31244f) },
+                { EAetheryteLocation.UldahThaumaturge, new(-154.83331f, 14.633362f, 73.07532f) },
+                { EAetheryteLocation.UldahGladiator, new(-53.849182f, 10.696533f, 12.222412f) },
+                { EAetheryteLocation.UldahMiner, new(33.49353f, 13.229492f, 113.206665f) },
+                { EAetheryteLocation.UldahAlchemist, new(-98.25293f, 42.34375f, 88.45642f) },
+                { EAetheryteLocation.UldahWeaver, new(89.64673f, 12.924377f, 58.27417f) },
+                { EAetheryteLocation.UldahGoldsmith, new(-19.333252f, 14.602844f, 72.03784f) },
+                { EAetheryteLocation.UldahSapphireAvenue, new(131.9447f, 4.714966f, -29.800903f) },
+                { EAetheryteLocation.UldahChamberOfRule, new(6.6376343f, 30.655273f, -24.826477f) },
+
+                { EAetheryteLocation.Limsa, new(-84.031494f, 20.767456f, 0.015197754f) },
+                { EAetheryteLocation.LimsaAftcastle, new(16.067688f, 40.787354f, 68.80286f) },
+                { EAetheryteLocation.LimsaCulinarian, new(-56.50421f, 44.47998f, -131.45648f) },
+                { EAetheryteLocation.LimsaArcanist, new(-335.1645f, 12.619202f, 56.381958f) },
+                { EAetheryteLocation.LimsaFisher, new(-179.40033f, 4.8065186f, 182.97095f) },
+                { EAetheryteLocation.LimsaMarauder, new(-5.1728516f, 44.63257f, -218.06671f) },
+                { EAetheryteLocation.LimsaHawkersAlley, new(-213.61108f, 16.739136f, 51.80432f) },
+
+                // ... missing a few
+
+                { EAetheryteLocation.Crystarium, new(-65.0188f, 4.5318604f, 0.015197754f) },
+                { EAetheryteLocation.CrystariumMarkets, new(-6.149414f, -7.736328f, 148.72961f) },
+                { EAetheryteLocation.CrystariumThemenosRookery, new(-107.37775f, -0.015319824f, -58.762512f) },
+                { EAetheryteLocation.CrystariumDossalGate, new(64.86609f, -0.015319824f, -18.173523f) },
+                { EAetheryteLocation.CrystariumPendants, new(35.477173f, -0.015319824f, 222.58337f) },
+                { EAetheryteLocation.CrystariumAmaroLaunch, new(66.60559f, 35.99597f, -131.09033f) },
+                { EAetheryteLocation.CrystariumCrystallineMean, new(-52.506348f, 19.97406f, -173.35773f) },
+                { EAetheryteLocation.CrystariumCabinetOfCuriosity, new(-54.398438f, -37.70508f, -241.07733f) },
+
+                { EAetheryteLocation.Eulmore, new(0.015197754f, 81.986694f, 0.93078613f) },
+                { EAetheryteLocation.EulmoreMainstay, new(10.940674f, 36.087524f, -4.196289f) },
+                { EAetheryteLocation.EulmoreNightsoilPots, new(-54.093323f, -0.83929443f, 52.140015f) },
+                { EAetheryteLocation.EulmoreGloryGate, new(6.9122925f, 6.240906f, -56.351562f) },
+                { EAetheryteLocation.EulmoreSoutheastDerelict, new(71.82422f, -10.391418f, 65.32385f) },
+
+                // ... missing a few
+
+                { EAetheryteLocation.OldSharlayan, new(0.07623291f, 4.8065186f, -0.10687256f) },
+                { EAetheryteLocation.OldSharlayanStudium, new(-291.1574f, 20.004517f, -74.143616f) },
+                { EAetheryteLocation.OldSharlayanBaldesionAnnex, new(-92.21033f, 2.304016f, 29.709229f) },
+                { EAetheryteLocation.OldSharlayanRostra, new(-36.94214f, 41.367188f, -156.6034f) },
+                { EAetheryteLocation.OldSharlayanLeveilleurEstate, new(204.79126f, 21.774597f, -118.73047f) },
+                { EAetheryteLocation.OldSharlayanJourneysEnd, new(206.22559f, 1.8463135f, 13.77887f) },
+                { EAetheryteLocation.OldSharlayanScholarsHarbor, new(16.494995f, -16.250854f, 127.73328f) },
+
+                { EAetheryteLocation.RadzAtHan, new(25.986084f, 3.250122f, -27.023743f) },
+                { EAetheryteLocation.RadzAtHanMeghaduta, new(-365.95715f, 44.99878f, -31.815125f) },
+                { EAetheryteLocation.RadzAtHanRuveydahFibers, new(-156.14563f, 35.99597f, 27.725586f) },
+                { EAetheryteLocation.RadzAtHanAirship, new(-144.33508f, 27.969727f, 202.2583f) },
+                { EAetheryteLocation.RadzAtHanAlzadaalsPeace, new(6.6071167f, -2.02948f, 110.55151f) },
+                { EAetheryteLocation.RadzAtHanHallOfTheRadiantHost, new(-141.37488f, 3.982544f, -98.435974f) },
+                { EAetheryteLocation.RadzAtHanMehrydesMeyhane, new(-42.61847f, -0.015319824f, -197.61963f) },
+                { EAetheryteLocation.RadzAtHanKama, new(129.59485f, 26.993164f, 13.473633f) },
+                { EAetheryteLocation.RadzAtHanHighCrucible, new(57.90796f, -24.704407f, -210.6203f) },
+
+                { EAetheryteLocation.LabyrinthosArcheion, new(443.5338f, 170.6416f, -476.18835f) },
+                { EAetheryteLocation.LabyrinthosSharlayanHamlet, new(8.377136f, -27.542603f, -46.67737f) },
+                { EAetheryteLocation.LabyrinthosAporia, new(-729.18286f, -27.634155f, 302.1438f) },
+                { EAetheryteLocation.ThavnairYedlihmad, new(193.49963f, 6.9733276f, 629.2362f) },
+                { EAetheryteLocation.ThavnairGreatWork, new(-527.48914f, 4.776001f, 36.75891f) },
+                { EAetheryteLocation.ThavnairPalakasStand, new(405.1422f, 5.2643433f, -244.4953f) },
+                { EAetheryteLocation.GarlemaldCampBrokenGlass, new(-408.10254f, 24.15503f, 479.9724f) },
+                { EAetheryteLocation.GarlemaldTertium, new(518.9136f, -35.324707f, -178.36273f) },
+                { EAetheryteLocation.MareLamentorumSinusLacrimarum, new(-566.2471f, 134.66089f, 650.6294f) },
+                { EAetheryteLocation.MareLamentorumBestwaysBurrow, new(-0.015319824f, -128.83197f, -512.0165f) },
+                { EAetheryteLocation.ElpisAnagnorisis, new(159.96033f, 11.703674f, 126.878784f) },
+                { EAetheryteLocation.ElpisTwelveWonders, new(-633.7225f, -19.821533f, 542.56494f) },
+                { EAetheryteLocation.ElpisPoietenOikos, new(-529.9001f, 161.24207f, -222.2782f) },
+                { EAetheryteLocation.UltimaThuleReahTahra, new(-544.152f, 74.32666f, 269.6421f) },
+                { EAetheryteLocation.UltimaThuleAbodeOfTheEa, new(64.286255f, 272.48022f, -657.49603f) },
+                { EAetheryteLocation.UltimaThuleBaseOmicron, new(489.2804f, 437.5829f, 333.63843f) },
+            }
+            .AsReadOnly();
+
+    public ReadOnlyDictionary<EAetheryteLocation, string> AethernetNames { get; }
+    public ReadOnlyDictionary<EAetheryteLocation, ushort> TerritoryIds { get; }
+
+    public AetheryteData(IDataManager dataManager)
+    {
+        Dictionary<EAetheryteLocation, string> aethernetNames = new();
+        Dictionary<EAetheryteLocation, ushort> territoryIds = new();
+        foreach (var aetheryte in dataManager.GetExcelSheet<Aetheryte>()!.Where(x => x.RowId > 0))
+        {
+            string? aethernetName = aetheryte.AethernetName?.Value?.Name.ToString();
+            if (!string.IsNullOrEmpty(aethernetName))
+                aethernetNames[(EAetheryteLocation)aetheryte.RowId] = aethernetName;
+
+            if (aetheryte.Territory != null && aetheryte.Territory.Row > 0)
+                territoryIds[(EAetheryteLocation)aetheryte.RowId] = (ushort)aetheryte.Territory.Row;
+        }
+
+        AethernetNames = aethernetNames.AsReadOnly();
+        TerritoryIds = territoryIds.AsReadOnly();
+    }
+
+    public float CalculateDistance(Vector3 fromPosition, ushort fromTerritoryType, EAetheryteLocation to)
+    {
+        if (!TerritoryIds.TryGetValue(to, out ushort toTerritoryType) || fromTerritoryType != toTerritoryType)
+            return float.MaxValue;
+
+        if (!Locations.TryGetValue(to, out Vector3 toPosition))
+            return float.MaxValue;
+
+        return (fromPosition - toPosition).Length();
+    }
+}
 
--- /dev/null
+using System.Collections.Immutable;
+using System.Linq;
+using Dalamud.Plugin.Services;
+using Lumina.Excel.GeneratedSheets;
+
+namespace Questionable.Data;
+
+internal sealed class TerritoryData
+{
+    private readonly ImmutableHashSet<uint> _territoriesWithMount;
+
+    public TerritoryData(IDataManager dataManager)
+    {
+        _territoriesWithMount = dataManager.GetExcelSheet<TerritoryType>()!
+            .Where(x => x.RowId > 0 && x.Mount)
+            .Select(x => x.RowId)
+            .ToImmutableHashSet();
+    }
+
+    public bool CanUseMount(ushort territoryId) => _territoriesWithMount.Contains(territoryId);
+}
 
     public Task<List<Vector3>> Pathfind(Vector3 localPlayerPosition, Vector3 targetPosition, bool fly,
         CancellationToken cancellationToken)
     {
+        _pathSetTolerance.InvokeAction(0.25f);
         return _navPathfind.InvokeFunc(localPlayerPosition, targetPosition, fly, cancellationToken);
     }
 
 
 using System.Collections.ObjectModel;
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
+using System.Numerics;
 using System.Runtime.InteropServices;
 using System.Text;
 using Dalamud.Game;
+using Dalamud.Game.ClientState.Objects;
 using Dalamud.Plugin.Services;
 using FFXIVClientStructs.FFXIV.Client.Game;
+using FFXIVClientStructs.FFXIV.Client.Game.Control;
 using FFXIVClientStructs.FFXIV.Client.Game.UI;
 using FFXIVClientStructs.FFXIV.Client.System.Framework;
 using FFXIVClientStructs.FFXIV.Client.System.Memory;
 using FFXIVClientStructs.FFXIV.Client.System.String;
 using FFXIVClientStructs.FFXIV.Client.UI.Agent;
 using Lumina.Excel.GeneratedSheets;
+using Questionable.Model.V1;
 
 namespace Questionable;
 
     private readonly delegate* unmanaged<Utf8String*, int, IntPtr, void> _sanitiseString;
     private readonly ReadOnlyDictionary<ushort, byte> _territoryToAetherCurrentCompFlgSet;
 
-    public GameFunctions(IDataManager dataManager, ISigScanner sigScanner)
+    private readonly IObjectTable _objectTable;
+    private readonly ITargetManager _targetManager;
+    private readonly IPluginLog _pluginLog;
+
+    public GameFunctions(IDataManager dataManager, IObjectTable objectTable, ISigScanner sigScanner, ITargetManager targetManager, IPluginLog pluginLog)
     {
+        _objectTable = objectTable;
+        _targetManager = targetManager;
+        _pluginLog = pluginLog;
         _processChatBox =
             Marshal.GetDelegateForFunctionPointer<ProcessChatBoxDelegate>(sigScanner.ScanText(Signatures.SendChat));
         _sanitiseString =
             .AsReadOnly();
     }
 
-    public (uint CurrentQuest, byte Sequence) GetCurrentQuest()
+    public (ushort CurrentQuest, byte Sequence) GetCurrentQuest()
     {
         var scenarioTree = AgentScenarioTree.Instance();
         if (scenarioTree == null)
 
         //ImGui.Text($"Current Quest: {currentQuest}");
         //ImGui.Text($"Progress: {QuestManager.GetQuestSequence(currentQuest)}");
-        return (currentQuest, QuestManager.GetQuestSequence(currentQuest));
+        return ((ushort)currentQuest, QuestManager.GetQuestSequence(currentQuest));
+    }
+
+    public bool IsAetheryteUnlocked(uint aetheryteId, out byte subIndex)
+    {
+        var telepo = Telepo.Instance();
+        if (telepo == null || telepo->UpdateAetheryteList() == null)
+        {
+            subIndex = 0;
+            return false;
+        }
+
+        for (ulong i = 0; i < telepo->TeleportList.Size(); ++ i)
+        {
+            var data = telepo->TeleportList.Get(i);
+            if (data.AetheryteId == aetheryteId)
+            {
+                subIndex = data.SubIndex;
+                return true;
+            }
+        }
+
+        subIndex = 0;
+        return false;
+    }
+
+    public bool IsAetheryteUnlocked(EAetheryteLocation aetheryteLocation)
+        => IsAetheryteUnlocked((uint)aetheryteLocation, out _);
+
+    public bool TeleportAetheryte(uint aetheryteId)
+    {
+        var status = ActionManager.Instance()->GetActionStatus(ActionType.Action, 5);
+        if (status != 0)
+            return false;
+
+        if (IsAetheryteUnlocked(aetheryteId, out var subIndex))
+        {
+            return Telepo.Instance()->Teleport(aetheryteId, subIndex);
+        }
+
+        return false;
     }
 
+    public bool TeleportAetheryte(EAetheryteLocation aetheryteLocation)
+        => TeleportAetheryte((uint)aetheryteLocation);
+
     public bool IsFlyingUnlocked(ushort territoryId)
     {
         var playerState = PlayerState.Instance();
 
     public void ExecuteCommand(string command)
     {
-        if (!command.StartsWith("/", StringComparison.Ordinal))
+        if (!command.StartsWith('/'))
             return;
 
         SendMessage(command);
 
         internal ChatPayload(byte[] stringBytes)
         {
-            this.textPtr = Marshal.AllocHGlobal(stringBytes.Length + 30);
-            Marshal.Copy(stringBytes, 0, this.textPtr, stringBytes.Length);
-            Marshal.WriteByte(this.textPtr + stringBytes.Length, 0);
+            textPtr = Marshal.AllocHGlobal(stringBytes.Length + 30);
+            Marshal.Copy(stringBytes, 0, textPtr, stringBytes.Length);
+            Marshal.WriteByte(textPtr + stringBytes.Length, 0);
 
-            this.textLen = (ulong)(stringBytes.Length + 1);
+            textLen = (ulong)(stringBytes.Length + 1);
 
-            this.unk1 = 64;
-            this.unk2 = 0;
+            unk1 = 64;
+            unk2 = 0;
         }
 
         public void Dispose()
         {
-            Marshal.FreeHGlobal(this.textPtr);
+            Marshal.FreeHGlobal(textPtr);
         }
     }
 
     #endregion
+
+    public void InteractWith(uint dataId)
+    {
+        foreach (var gameObject in _objectTable)
+        {
+            if (gameObject.DataId == dataId)
+            {
+                _targetManager.Target = null;
+                _targetManager.Target = gameObject;
+
+                TargetSystem.Instance()->InteractWithObject(
+                    (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)gameObject.Address, false);
+                return;
+            }
+        }
+    }
 }
 
-using Questionable.Model.V1;
+using System.Linq;
+using Questionable.Model.V1;
 
 namespace Questionable;
 
     public required string FilePath { get; init; }
 
     public required ushort QuestId { get; init; }
-    public required string Name { get; init; }
+    public required string Name { get; set; }
     public required QuestData Data { get; init; }
+
+    public QuestSequence? FindSequence(byte currentSequence)
+        => Data.QuestSequence.SingleOrDefault(seq => seq.Sequence == currentSequence);
 }
 
         { EAetheryteLocation.KuganeSekiseigumiBarracks, "[Kugane] Sekiseigumi Barracks" },
         { EAetheryteLocation.KuganeRakuzaDistrict, "[Kugane] Rakuza District" },
         { EAetheryteLocation.KuganeAirship, "[Kugane] Airship Landing" },
-        { EAetheryteLocation.Crystarium, "[The Crystarium] Aetheryte Plaza" },
-        { EAetheryteLocation.CrystariumMarkets, "[The Crystarium] Musica Universalis Markets" },
-        { EAetheryteLocation.CrystariumThemenosRookery, "[The Crystarium] Themenos Rookery" },
-        { EAetheryteLocation.CrystariumDossalGate, "[The Crystarium] The Dossal Gate" },
-        { EAetheryteLocation.CrystariumPendants, "[The Crystarium] The Pendants" },
-        { EAetheryteLocation.CrystariumAmaroLaunch, "[The Crystarium] The Amaro Launch" },
-        { EAetheryteLocation.CrystariumCrystallineMean, "[The Crystarium] The Crystalline Mean" },
-        { EAetheryteLocation.CrystariumCabinetOfCuriosity, "[The Crystarium] The Cabinet of Curiosity" },
+        { EAetheryteLocation.Crystarium, "[Crystarium] Aetheryte Plaza" },
+        { EAetheryteLocation.CrystariumMarkets, "[Crystarium] Musica Universalis Markets" },
+        { EAetheryteLocation.CrystariumThemenosRookery, "[Crystarium] Themenos Rookery" },
+        { EAetheryteLocation.CrystariumDossalGate, "[Crystarium] The Dossal Gate" },
+        { EAetheryteLocation.CrystariumPendants, "[Crystarium] The Pendants" },
+        { EAetheryteLocation.CrystariumAmaroLaunch, "[Crystarium] The Amaro Launch" },
+        { EAetheryteLocation.CrystariumCrystallineMean, "[Crystarium] The Crystalline Mean" },
+        { EAetheryteLocation.CrystariumCabinetOfCuriosity, "[Crystarium] The Cabinet of Curiosity" },
         { EAetheryteLocation.Eulmore, "[Eulmore] Aetheryte Plaza" },
         { EAetheryteLocation.EulmoreSoutheastDerelict, "[Eulmore] Southeast Derelicts" },
         { EAetheryteLocation.EulmoreNightsoilPots, "[Eulmore] Nightsoil Pots" },
     private static readonly Dictionary<string, EAetheryteLocation> StringToEnum =
         EnumToString.ToDictionary(x => x.Value, x => x.Key);
 
-    public override AethernetShortcut? Read(ref Utf8JsonReader reader, Type typeToConvert,
+    public override AethernetShortcut Read(ref Utf8JsonReader reader, Type typeToConvert,
         JsonSerializerOptions options)
     {
         if (reader.TokenType != JsonTokenType.StartArray)
 
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Questionable.Model.V1.Converter;
+
+public class AetheryteConverter : JsonConverter<EAetheryteLocation>
+{
+    private static readonly Dictionary<EAetheryteLocation, string> EnumToString = new()
+    {
+        { EAetheryteLocation.Limsa, "Limsa Lominsa" },
+        { EAetheryteLocation.Gridania, "Gridania" },
+        { EAetheryteLocation.Uldah, "Ul'dah" },
+        { EAetheryteLocation.Ishgard, "Ishgard" },
+
+        { EAetheryteLocation.RhalgrsReach, "Rhalgr's Reach" },
+        { EAetheryteLocation.FringesCastrumOriens, "Fringes - Castrum Oriens" },
+        { EAetheryteLocation.FringesPeeringStones, "Fringes - Peering Stones" },
+        { EAetheryteLocation.PeaksAlaGannha, "Peaks - Ala Gannha" },
+        { EAetheryteLocation.PeaksAlaGhiri, "Peaks - Ala Ghiri" },
+        { EAetheryteLocation.LochsPortaPraetoria, "Lochs - Porta Praetoria" },
+        { EAetheryteLocation.LochsAlaMhiganQuarter, "Lochs - Ala Mhigan Quarter" },
+        { EAetheryteLocation.Kugane, "Kugane" },
+        { EAetheryteLocation.RubySeaTamamizu, "Ruby Sea - Tamamizu" },
+        { EAetheryteLocation.RubySeaOnokoro, "Ruby Sea - Onokoro" },
+        { EAetheryteLocation.YanxiaNamai, "Yanxia - Namai" },
+        { EAetheryteLocation.YanxiaHouseOfTheFierce, "Yanxia - House of the Fierce" },
+        { EAetheryteLocation.AzimSteppeReunion, "Azim Steppe - Reunion" },
+        { EAetheryteLocation.AzimSteppeDawnThrone, "Azim Steppe - Dawn Throne" },
+        { EAetheryteLocation.AzimSteppeDhoroIloh, "Azim Steppe - Dhoro Iloh" },
+        { EAetheryteLocation.DomanEnclave, "Doman Enclave" },
+        { EAetheryteLocation.DomamEnclaveNorthern, "Doman Enclave - Northern Enclave" },
+        { EAetheryteLocation.DomamEnclaveSouthern, "Doman Enclave - Southern Enclave" },
+
+        { EAetheryteLocation.Crystarium, "Crystarium" },
+        { EAetheryteLocation.Eulmore, "Eulmore" },
+        { EAetheryteLocation.LakelandFortJobb, "Lakeland - Fort Jobb" },
+        { EAetheryteLocation.LakelandOstallImperative, "Lakeland - Ostall Imperative" },
+        { EAetheryteLocation.KholusiaStilltide, "Kholusia - Stilltide" },
+        { EAetheryteLocation.KholusiaWright, "Kholusia - Wright" },
+        { EAetheryteLocation.KholusiaTomra, "Kholusia - Tomra" },
+        { EAetheryteLocation.AmhAraengMordSouq, "Amh Araeng - Mord Souq" },
+        { EAetheryteLocation.AmhAraengInnAtJourneysHead, "Amh Araeng - Inn at Journey's Head" },
+        { EAetheryteLocation.AmhAraengTwine, "Amh Araeng - Twine" },
+        { EAetheryteLocation.RaktikaSlitherbough, "Rak'tika - Slitherbough" },
+        { EAetheryteLocation.RaktikaFanow, "Rak'tika - Fanow" },
+        { EAetheryteLocation.IlMhegLydhaLran, "Il Mheg - Lydha Lran" },
+        { EAetheryteLocation.IlMhegPiaEnni, "Il Mheg - Pia Enni" },
+        { EAetheryteLocation.IlMhegWolekdorf, "Il Mheg - Wolekdorf" },
+        { EAetheryteLocation.TempestOndoCups, "Tempest - Ondo Cups" },
+        { EAetheryteLocation.TempestMacarensesAngle, "Tempest - Macarenses Angle" },
+
+        { EAetheryteLocation.OldSharlayan, "Old Sharlayan" },
+        { EAetheryteLocation.RadzAtHan, "Radz-at-Han" },
+        { EAetheryteLocation.LabyrinthosArcheion, "Labyrinthos - Archeion" },
+        { EAetheryteLocation.LabyrinthosSharlayanHamlet, "Labyrinthos - Sharlayan Hamlet" },
+        { EAetheryteLocation.LabyrinthosAporia, "Labyrinthos - Aporia" },
+        { EAetheryteLocation.ThavnairYedlihmad, "Thavnair - Yedlihmad" },
+        { EAetheryteLocation.ThavnairGreatWork, "Thavnair - Great Work" },
+        { EAetheryteLocation.ThavnairPalakasStand, "Thavnair - Palaka's Stand" },
+        { EAetheryteLocation.GarlemaldCampBrokenGlass, "Garlemald - Camp Broken Glass" },
+        { EAetheryteLocation.GarlemaldTertium, "Garlemald - Tertium" },
+        { EAetheryteLocation.MareLamentorumSinusLacrimarum, "Mare Lamentorum - Sinus Lacrimarum" },
+        { EAetheryteLocation.MareLamentorumBestwaysBurrow, "Mare Lamentorum - Bestways Burrow" },
+        { EAetheryteLocation.ElpisAnagnorisis, "Elpis - Anagnorisis" },
+        { EAetheryteLocation.ElpisTwelveWonders, "Elpis - Twelve Wonders" },
+        { EAetheryteLocation.ElpisPoietenOikos, "Elpis - Poieten Oikos" },
+        { EAetheryteLocation.UltimaThuleReahTahra, "Ultima Thule - Reah Tahra" },
+        { EAetheryteLocation.UltimaThuleAbodeOfTheEa, "Ultima Thula - Abode of the Ea" },
+        { EAetheryteLocation.UltimaThuleBaseOmicron, "Ultima Thule - Base Omicron" }
+    };
+
+    private static readonly Dictionary<string, EAetheryteLocation> StringToEnum =
+        EnumToString.ToDictionary(x => x.Value, x => x.Key);
+
+    public override EAetheryteLocation Read(ref Utf8JsonReader reader, Type typeToConvert,
+        JsonSerializerOptions options)
+    {
+        if (reader.TokenType != JsonTokenType.String)
+            throw new JsonException();
+
+        string? str = reader.GetString();
+        if (str == null)
+            throw new JsonException();
+
+        return StringToEnum.TryGetValue(str, out EAetheryteLocation value) ? value : throw new JsonException();
+    }
+
+    public override void Write(Utf8JsonWriter writer, EAetheryteLocation value, JsonSerializerOptions options)
+    {
+        ArgumentNullException.ThrowIfNull(writer);
+        writer.WriteStringValue(EnumToString[value]);
+    }
+}
 
     {
         { EInteractionType.Interact, "Interact" },
         { EInteractionType.WalkTo, "WalkTo" },
-        { EInteractionType.AttuneAethenetShard, "AttuneAethenetShard" },
+        { EInteractionType.AttuneAethernetShard, "AttuneAethenetShard" },
         { EInteractionType.AttuneAetheryte, "AttuneAetheryte" },
         { EInteractionType.AttuneAetherCurrent, "AttuneAetherCurrent" },
         { EInteractionType.Combat, "Combat" },
 
--- /dev/null
+using System;
+using System.Numerics;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Questionable.Model.V1.Converter;
+
+public class VectorConverter : JsonConverter<Vector3>
+{
+    public override Vector3 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+    {
+        if (reader.TokenType != JsonTokenType.StartObject)
+            throw new JsonException();
+
+        Vector3 vec = new Vector3();
+        while (reader.Read())
+        {
+            switch (reader.TokenType)
+            {
+                case JsonTokenType.PropertyName:
+                    string? propertyName = reader.GetString();
+                    if (propertyName == null || !reader.Read())
+                        throw new JsonException();
+
+                    switch (propertyName)
+                    {
+                        case nameof(Vector3.X):
+                            vec.X = reader.GetSingle();
+                            break;
+
+                        case nameof(Vector3.Y):
+                            vec.Y = reader.GetSingle();
+                            break;
+
+                        case nameof(Vector3.Z):
+                            vec.Z = reader.GetSingle();
+                            break;
+
+                        default:
+                            throw new JsonException();
+                    }
+
+                    break;
+
+                case JsonTokenType.EndObject:
+                    return vec;
+
+                default:
+                    throw new JsonException();
+            }
+        }
+
+        throw new JsonException();
+    }
+
+    public override void Write(Utf8JsonWriter writer, Vector3 value, JsonSerializerOptions options)
+    {
+        ArgumentNullException.ThrowIfNull(writer);
+
+        writer.WriteStartObject();
+        writer.WriteNumber(nameof(Vector3.X), value.X);
+        writer.WriteNumber(nameof(Vector3.Y), value.X);
+        writer.WriteNumber(nameof(Vector3.Z), value.X);
+        writer.WriteEndObject();
+    }
+}
 
 
 public enum EAetheryteLocation
 {
+    None = 0,
+
     Gridania = 2,
     GridaniaArcher = 25,
     GridaniaLeatherworker = 26,
     KuganeRakuzaDistrict = 119,
     KuganeAirship = 120,
 
+    FringesCastrumOriens = 98,
+    FringesPeeringStones = 99,
+    PeaksAlaGannha = 100,
+    PeaksAlaGhiri = 101,
+    LochsPortaPraetoria = 102,
+    LochsAlaMhiganQuarter = 103,
+    RubySeaTamamizu = 105,
+    RubySeaOnokoro = 106,
+    YanxiaNamai = 107,
+    YanxiaHouseOfTheFierce = 108,
+    AzimSteppeReunion = 109,
+    AzimSteppeDawnThrone = 110,
+    AzimSteppeDhoroIloh = 128,
+
+    DomanEnclave = 127,
+    DomamEnclaveNorthern = 129,
+    DomamEnclaveSouthern = 130,
+
     Crystarium = 133,
     CrystariumMarkets = 149,
     CrystariumThemenosRookery = 150,
     EulmoreGloryGate = 159,
     EulmoreSoutheastDerelict = 135,
 
+    LakelandFortJobb = 132,
+    LakelandOstallImperative = 136,
+    KholusiaStilltide = 137,
+    KholusiaWright = 138,
+    KholusiaTomra = 139,
+    AmhAraengMordSouq = 140,
+    AmhAraengInnAtJourneysHead = 141,
+    AmhAraengTwine = 142,
+    RaktikaSlitherbough = 143,
+    RaktikaFanow = 144,
+    IlMhegLydhaLran = 145,
+    IlMhegPiaEnni = 146,
+    IlMhegWolekdorf = 147,
+    TempestOndoCups = 148,
+    TempestMacarensesAngle = 156,
+
     OldSharlayan = 182,
     OldSharlayanStudium = 184,
     OldSharlayanBaldesionAnnex = 185,
     RadzAtHanMehrydesMeyhane = 196,
     RadzAtHanKama = 198,
     RadzAtHanHighCrucible = 199,
+
+    LabyrinthosArcheion = 166,
+    LabyrinthosSharlayanHamlet = 167,
+    LabyrinthosAporia = 168,
+    ThavnairYedlihmad = 169,
+    ThavnairGreatWork = 170,
+    ThavnairPalakasStand = 171,
+    GarlemaldCampBrokenGlass = 172,
+    GarlemaldTertium = 173,
+    MareLamentorumSinusLacrimarum = 174,
+    MareLamentorumBestwaysBurrow = 175,
+    ElpisAnagnorisis = 176,
+    ElpisTwelveWonders = 177,
+    ElpisPoietenOikos = 178,
+    UltimaThuleReahTahra = 179,
+    UltimaThuleAbodeOfTheEa = 180,
+    UltimaThuleBaseOmicron = 181
 }
 
 {
     Interact,
     WalkTo,
-    AttuneAethenetShard,
+    AttuneAethernetShard,
     AttuneAetheryte,
     AttuneAetherCurrent,
     Combat,
 
     public required int Version { get; set; }
     public required string Author { get; set; }
     public List<string> Contributors { get; set; } = new();
-    public string Comment { get; set; }
+    public string? Comment { get; set; }
     public List<ushort> TerritoryBlacklist { get; set; } = new();
     public required List<QuestSequence> QuestSequence { get; set; } = new();
 }
 
 public class QuestSequence
 {
     public required int Sequence { get; set; }
-    public string Comment { get; set; }
+    public string? Comment { get; set; }
     public List<QuestStep> Steps { get; set; } = new();
 }
 
     [JsonConverter(typeof(InteractionTypeConverter))]
     public EInteractionType InteractionType { get; set; }
 
-    public ulong? DataId { get; set; }
-    public Vector3 Position { get; set; }
+    public uint? DataId { get; set; }
+
+    [JsonConverter(typeof(VectorConverter))]
+    public Vector3? Position { get; set; }
+
+    public float? StopDistance { get; set; }
     public ushort TerritoryId { get; set; }
     public bool Disabled { get; set; }
+    public string? Comment { get; set; }
+
+    [JsonConverter(typeof(AetheryteConverter))]
+    public EAetheryteLocation? AetheryteShortcut { get; set; }
 
     [JsonConverter(typeof(AethernetShortcutConverter))]
-    public AethernetShortcut AethernetShortcut { get; set; }
+    public AethernetShortcut? AethernetShortcut { get; set; }
 }
 
           },
           "TerritoryId": 129,
           "InteractionType": "Interact",
+          "AetheryteShortcut": "Limsa Lominsa",
           "AethernetShortcut": [
             "[Limsa Lominsa] Aetheryte Plaza",
             "[Limsa Lominsa] Arcanist's Guild"
 
         {
           "DataId": 1038578,
           "Position": {
-            "X": -53.576973,
+            "X": -56.737106,
             "Y": -15.127001,
-            "Z": 131.09679
+            "Z": 130.76611
           },
+          "StopDistance": 0.25,
           "TerritoryId": 962,
           "InteractionType": "Interact"
         }
         {
           "DataId": 1038578,
           "Position": {
-            "X": 0.86839586,
-            "Y": 3.2250001,
-            "Z": 9.54673
+            "X": -0.03130532,
+            "Y": 3.2249997,
+            "Z": 8.909777
           },
+          "StopDistance": 0.25,
           "TerritoryId": 962,
           "InteractionType": "Interact"
         }
         {
           "DataId": 1038578,
           "Position": {
-            "X": 65.84385,
+            "X": 66.10567,
             "Y": 5.0999994,
-            "Z": -63.417946
+            "Z": -63.37148
           },
+          "StopDistance": 0.25,
           "TerritoryId": 962,
           "InteractionType": "Interact"
         }
     {
       "Sequence": 6,
       "Steps": [
+        {
+          "Position": {
+            "X": 93.30914,
+            "Y": 8.920153,
+            "Z": -89.12467
+          },
+          "TerritoryId": 962,
+          "InteractionType": "WalkTo"
+        },
         {
           "DataId": 1038578,
           "Position": {
             "Y": 41.37599,
             "Z": -142.5033
           },
+          "StopDistance": 0.25,
           "TerritoryId": 962,
           "InteractionType": "Interact"
         }
             "Y": 41.367188,
             "Z": -156.6034
           },
+          "StopDistance": 0.25,
           "TerritoryId": 962,
           "InteractionType": "AttuneAethenetShard"
         },
             "Y": 1.0594833,
             "Z": 30.052902
           },
+          "StopDistance": 0.25,
           "TerritoryId": 962,
           "InteractionType": "Interact",
           "AethernetShortcut": [
 
           "InteractionType": "Interact"
         }
       ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1038679,
+          "Position": {
+            "X": -275.5932,
+            "Y": 19.003881,
+            "Z": 13.321045
+          },
+          "TerritoryId": 962,
+          "InteractionType": "Interact"
+        }
+      ]
     }
   ]
 }
 
         {
           "DataId": 1037077,
           "Position": {
-            "X": -38.07129,
+            "X": -38.066784,
             "Y": -14.169313,
-            "Z": 105.30249
+            "Z": 107.68768
           },
           "TerritoryId": 962,
           "InteractionType": "Interact"
       "Steps": [
         {
           "Position": {
-            "X": 15.242085,
+            "X": 19.79008,
             "Y": -16.247002,
-            "Z": 109.177666
+            "Z": 108.36692
           },
           "TerritoryId": 962,
           "InteractionType": "WalkTo"
 
           },
           "TerritoryId": 956,
           "InteractionType": "Combat",
+          "EnemySpawnType": "AutoOnEnterArea",
           "KillEnemyDataIds": [
             14024
           ]
           },
           "TerritoryId": 956,
           "InteractionType": "Combat",
+          "EnemySpawnType": "AutoOnEnterArea",
           "KillEnemyDataIds": [
             14023,
             14022
 
           },
           "TerritoryId": 956,
           "InteractionType": "ManualAction",
-          "Comment": "Duty - Shoot some bird"
+          "Comment": "Duty - Shoot Large Green Bird"
         }
       ]
     },
 
             "Z": -72.22095
           },
           "TerritoryId": 956,
+          "EnemySpawnType": "AfterInteraction",
           "InteractionType": "Combat",
           "KillEnemyDataIds": [
             14020
           },
           "TerritoryId": 956,
           "InteractionType": "Combat",
+          "EnemySpawnType": "AfterInteraction",
           "KillEnemyDataIds": [
             14021
           ]
       "Sequence": 5,
       "Steps": [
         {
-          "DataId": 2011984,
-          "Position": {
-            "X": 497.09314,
-            "Y": 73.41101,
-            "Z": -267.23126
-          },
-          "TerritoryId": 956,
-          "InteractionType": "AttuneAetherCurrent"
-        },
-        {
-          "DataId": 1038708,
+          "DataId": 1037985,
           "Position": {
-            "X": 408.31604,
-            "Y": 65.3329,
-            "Z": -130.11371
+            "X": 481.8036,
+            "Y": 66.16195,
+            "Z": -108.537415
           },
           "TerritoryId": 956,
           "InteractionType": "Interact"
           "InteractionType": "Interact"
         },
         {
-          "DataId": 1037985,
+          "DataId": 1038708,
           "Position": {
-            "X": 481.8036,
-            "Y": 66.16195,
-            "Z": -108.537415
+            "X": 408.31604,
+            "Y": 65.3329,
+            "Z": -130.11371
           },
           "TerritoryId": 956,
           "InteractionType": "Interact"
     {
       "Sequence": 6,
       "Steps": [
+        {
+          "DataId": 2011984,
+          "Position": {
+            "X": 497.09314,
+            "Y": 73.41101,
+            "Z": -267.23126
+          },
+          "TerritoryId": 956,
+          "InteractionType": "AttuneAetherCurrent"
+        },
         {
           "DataId": 2011843,
           "Position": {
 
             "Y": 81.17488,
             "Z": -534.99316
           },
+          "StopDistance": 0.25,
           "TerritoryId": 956,
           "InteractionType": "WalkTo"
         }
 
     {
       "Sequence": 1,
       "Steps": [
+        {
+          "Position": {
+            "X": -329.64972,
+            "Y": 77.91884,
+            "Z": -448.5044
+          },
+          "TerritoryId": 956,
+          "InteractionType": "WalkTo"
+        },
+        {
+          "Position": {
+            "X": -327.6718,
+            "Y": 79.535736,
+            "Z": -400.00397
+          },
+          "TerritoryId": 956,
+          "InteractionType": "WalkTo"
+        },
         {
           "DataId": 2011982,
           "Position": {
           "TerritoryId": 956,
           "InteractionType": "AttuneAetherCurrent"
         },
+        {
+          "Position": {
+            "X": -327.6718,
+            "Y": 79.535736,
+            "Z": -400.00397
+          },
+          "TerritoryId": 956,
+          "InteractionType": "WalkTo"
+        },
         {
           "DataId": 2011983,
           "Position": {
 
             "Y": 6.991216,
             "Z": 629.2394
           },
+          "StopDistance": 5,
           "TerritoryId": 957,
           "InteractionType": "AttuneAetheryte"
         },
         {
+          "DataId": 2011948,
           "Position": {
-            "X": 190.45029,
-            "Y": 0.9965663,
-            "Z": 703.01746
-          },
-          "TerritoryId": 957,
-          "InteractionType": "WalkTo"
-        },
-        {
-          "DataId": 1037622,
-          "Position": {
-            "X": 187.9148,
-            "Y": 0.26447815,
-            "Z": 700.12964
+            "X": 204.66919,
+            "Y": 2.243042,
+            "Z": 715.4192
           },
           "TerritoryId": 957,
           "InteractionType": "Interact"
         },
         {
-          "DataId": 2011948,
+          "DataId": 1037622,
           "Position": {
-            "X": 204.66919,
-            "Y": 2.243042,
-            "Z": 715.4192
+            "X": 189.94562,
+            "Y": 0.8560083,
+            "Z": 702.7896
           },
+          "StopDistance": 0.25,
           "TerritoryId": 957,
           "InteractionType": "Interact"
         },
 
             "Y": 1.769943,
             "Z": 738.9843
           },
+          "StopDistance": 0.25,
           "TerritoryId": 957,
           "InteractionType": "Interact"
         }
 
           },
           "TerritoryId": 957,
           "InteractionType": "Combat",
+          "EnemySpawnType": "AutoOnEnterArea",
           "KillEnemyDataIds": [
             14006
           ]
 
             "Y": 4.785123,
             "Z": 36.76496
           },
+          "StopDistance": 5,
           "TerritoryId": 957,
           "InteractionType": "AttuneAetheryte"
         },
 
           },
           "TerritoryId": 957,
           "InteractionType": "Combat",
+          "EnemySpawnType": "AfterInteraction",
           "KillEnemyDataIds": [
             14004
           ]
 
             "Y": 88.84356,
             "Z": -608.6588
           },
+          "StopDistance": 0.25,
           "TerritoryId": 957,
           "InteractionType": "WalkTo"
         }
 
     {
       "Sequence": 1,
       "Steps": [
+        {
+          "Position": {
+            "X": -80.636894,
+            "Y": 99.974266,
+            "Z": -708.7214
+          },
+          "TerritoryId": 957,
+          "InteractionType": "WalkTo"
+        },
+        {
+          "Position": {
+            "X": -67.775665,
+            "Y": 97.140656,
+            "Z": -710.1025
+          },
+          "TerritoryId": 957,
+          "InteractionType": "WalkTo"
+        },
         {
           "DataId": 2011991,
           "Position": {
 
           },
           "TerritoryId": 962,
           "InteractionType": "Interact",
+          "AetheryteShortcut": "Old Sharlayan",
           "AethernetShortcut": [
             "[Old Sharlayan] Aetheryte Plaza",
             "[Old Sharlayan] The Baldesion Annex"
 
             "Z": -569.8787
           },
           "TerritoryId": 957,
+          "AetheryteShortcut": "Thavnair - Great Work",
           "InteractionType": "Interact"
         }
       ]
 
             "Z": 539.6046
           },
           "TerritoryId": 621,
-          "InteractionType": "Interact"
+          "InteractionType": "ManualAction",
+          "Comment": "Duty - A Frosty Reception"
         }
       ]
     },
 
           "InteractionType": "ManualAction",
           "Comment": "Cutscene Interaction needed",
           "AethernetShortcut": [
-            "[The Crystarium] Aetheryte Plaza",
-            "[The Crystarium] The Cabinet of Curiosity"
+            "[Crystarium] Aetheryte Plaza",
+            "[Crystarium] The Cabinet of Curiosity"
           ]
         }
       ]
 
           "TerritoryId": 819,
           "InteractionType": "Interact",
           "AethernetShortcut": [
-            "[The Crystarium] The Cabinet of Curiosity",
-            "[The Crystarium] The Dossal Gate"
+            "[Crystarium] The Cabinet of Curiosity",
+            "[Crystarium] The Dossal Gate"
           ]
         }
       ]
 
+++ /dev/null
-{
-  "Version": 1,
-  "Author": "liza",
-  "QuestSequence": [
-    {
-      "Sequence": 0,
-      "Steps": [
-        {
-          "DataId": 1040307,
-          "Position": {
-            "X": -469.29126,
-            "Y": 232.2548,
-            "Z": -252.8573
-          },
-          "TerritoryId": 960,
-          "InteractionType": "Interact"
-        }
-      ]
-    },
-    {
-      "Sequence": 1,
-      "Steps": [
-        {
-          "DataId": 1040315,
-          "Position": {
-            "X": -345.87628,
-            "Y": 254.66968,
-            "Z": -277.27173
-          },
-          "TerritoryId": 960,
-          "InteractionType": "Interact"
-        }
-      ]
-    },
-    {
-      "Sequence": 2,
-      "Steps": [
-        {
-          "DataId": 1040313,
-          "Position": {
-            "X": -339.10126,
-            "Y": 255.53401,
-            "Z": -281.75793
-          },
-          "TerritoryId": 960,
-          "InteractionType": "Interact"
-        }
-      ]
-    },
-    {
-      "Sequence": 3,
-      "Steps": [
-        {
-          "DataId": 2012030,
-          "Position": {
-            "X": -333.547,
-            "Y": 270.83228,
-            "Z": -361.50153
-          },
-          "TerritoryId": 960,
-          "InteractionType": "AttuneAetherCurrent"
-        },
-        {
-          "DataId": 2012035,
-          "Position": {
-            "X": -238.81903,
-            "Y": 320.36304,
-            "Z": -295.15533
-          },
-          "TerritoryId": 960,
-          "InteractionType": "AttuneAetherCurrent"
-        },
-        {
-          "DataId": 1040317,
-          "Position": {
-            "X": -200.57983,
-            "Y": 268.01642,
-            "Z": -312.58112
-          },
-          "TerritoryId": 960,
-          "InteractionType": "Interact"
-        }
-      ]
-    },
-    {
-      "Sequence": 4,
-      "Steps": [
-        {
-          "DataId": 1040318,
-          "Position": {
-            "X": 29.984009,
-            "Y": 270.45825,
-            "Z": -535.0271
-          },
-          "TerritoryId": 960,
-          "InteractionType": "Interact"
-        }
-      ]
-    },
-    {
-      "Sequence": 5,
-      "Steps": [
-        {
-          "DataId": 2012354,
-          "Position": {
-            "X": 30.777344,
-            "Y": 272.51086,
-            "Z": -600.7019
-          },
-          "TerritoryId": 960,
-          "InteractionType": "Interact"
-        },
-        {
-          "DataId": 2012355,
-          "Position": {
-            "X": 64.10315,
-            "Y": 272.4497,
-            "Z": -616.4492
-          },
-          "TerritoryId": 960,
-          "InteractionType": "Interact"
-        },
-        {
-          "DataId": 180,
-          "Position": {
-            "X": 64.286255,
-            "Y": 272.48022,
-            "Z": -657.49603
-          },
-          "TerritoryId": 960,
-          "InteractionType": "AttuneAetheryte"
-        },
-        {
-          "DataId": 2012356,
-          "Position": {
-            "X": 115.526,
-            "Y": 272.99915,
-            "Z": -617.853
-          },
-          "TerritoryId": 960,
-          "InteractionType": "Interact"
-        },
-        {
-          "DataId": 2012357,
-          "Position": {
-            "X": 151.59839,
-            "Y": 272.9381,
-            "Z": -592.5841
-          },
-          "TerritoryId": 960,
-          "InteractionType": "Interact"
-        }
-      ]
-    },
-    {
-      "Sequence": 255,
-      "Steps": [
-        {
-          "DataId": 1040318,
-          "Position": {
-            "X": 29.984009,
-            "Y": 270.45825,
-            "Z": -535.0271
-          },
-          "TerritoryId": 960,
-          "InteractionType": "Interact"
-        }
-      ]
-    }
-  ]
-}
 
--- /dev/null
+{
+  "Version": 1,
+  "Author": "liza",
+  "QuestSequence": [
+    {
+      "Sequence": 0,
+      "Steps": [
+        {
+          "DataId": 1040307,
+          "Position": {
+            "X": -469.29126,
+            "Y": 232.2548,
+            "Z": -252.8573
+          },
+          "TerritoryId": 960,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 1,
+      "Steps": [
+        {
+          "DataId": 1040315,
+          "Position": {
+            "X": -345.87628,
+            "Y": 254.66968,
+            "Z": -277.27173
+          },
+          "TerritoryId": 960,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 2,
+      "Steps": [
+        {
+          "DataId": 1040313,
+          "Position": {
+            "X": -339.10126,
+            "Y": 255.53401,
+            "Z": -281.75793
+          },
+          "TerritoryId": 960,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 3,
+      "Steps": [
+        {
+          "DataId": 2012030,
+          "Position": {
+            "X": -333.547,
+            "Y": 270.83228,
+            "Z": -361.50153
+          },
+          "TerritoryId": 960,
+          "InteractionType": "AttuneAetherCurrent"
+        },
+        {
+          "DataId": 2012035,
+          "Position": {
+            "X": -238.81903,
+            "Y": 320.36304,
+            "Z": -295.15533
+          },
+          "TerritoryId": 960,
+          "InteractionType": "AttuneAetherCurrent"
+        },
+        {
+          "DataId": 1040317,
+          "Position": {
+            "X": -200.57983,
+            "Y": 268.01642,
+            "Z": -312.58112
+          },
+          "TerritoryId": 960,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 4,
+      "Steps": [
+        {
+          "DataId": 1040318,
+          "Position": {
+            "X": 29.984009,
+            "Y": 270.45825,
+            "Z": -535.0271
+          },
+          "TerritoryId": 960,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 5,
+      "Steps": [
+        {
+          "DataId": 2012354,
+          "Position": {
+            "X": 30.777344,
+            "Y": 272.51086,
+            "Z": -600.7019
+          },
+          "TerritoryId": 960,
+          "InteractionType": "Interact"
+        },
+        {
+          "DataId": 2012355,
+          "Position": {
+            "X": 64.10315,
+            "Y": 272.4497,
+            "Z": -616.4492
+          },
+          "TerritoryId": 960,
+          "InteractionType": "Interact"
+        },
+        {
+          "DataId": 180,
+          "Position": {
+            "X": 64.286255,
+            "Y": 272.48022,
+            "Z": -657.49603
+          },
+          "TerritoryId": 960,
+          "InteractionType": "AttuneAetheryte"
+        },
+        {
+          "DataId": 2012356,
+          "Position": {
+            "X": 115.526,
+            "Y": 272.99915,
+            "Z": -617.853
+          },
+          "TerritoryId": 960,
+          "InteractionType": "Interact"
+        },
+        {
+          "DataId": 2012357,
+          "Position": {
+            "X": 151.59839,
+            "Y": 272.9381,
+            "Z": -592.5841
+          },
+          "TerritoryId": 960,
+          "InteractionType": "Interact"
+        }
+      ]
+    },
+    {
+      "Sequence": 255,
+      "Steps": [
+        {
+          "DataId": 1040318,
+          "Position": {
+            "X": 29.984009,
+            "Y": 270.45825,
+            "Z": -535.0271
+          },
+          "TerritoryId": 960,
+          "InteractionType": "Interact"
+        }
+      ]
+    }
+  ]
+}
 
           "TerritoryId": 819,
           "InteractionType": "Interact",
           "AethernetShortcut": [
-            "[The Crystarium] Aetheryte Plaza",
-            "[The Crystarium] The Cabinet of Curiosity"
+            "[Crystarium] Aetheryte Plaza",
+            "[Crystarium] The Cabinet of Curiosity"
           ]
         }
       ]
 
 {
-  "Version": 1
+  "Version": 1,
   "Author": "liza",
   "QuestSequence": [
     {
           "TerritoryId": 819,
           "InteractionType": "Interact",
           "AethernetShortcut": [
-            "[The Crystarium] Aetheryte Plaza",
-            "[The Crystarium] The Dossal Gate"
+            "[Crystarium] Aetheryte Plaza",
+            "[Crystarium] The Dossal Gate"
           ]
         }
       ]
 
           "TerritoryId": 819,
           "InteractionType": "Interact",
           "AethernetShortcut": [
-            "[The Crystarium] Aetheryte Plaza",
-            "[The Crystarium] The Dossal Gate"
+            "[Crystarium] Aetheryte Plaza",
+            "[Crystarium] The Dossal Gate"
           ]
         }
       ]
 
 {
   "$schema": "https://json-schema.org/draft/2020-12/schema",
-  "$id": "https://example.com/quest/1.0",
+  "$id": "/quest/1.0",
   "title": "Questionable V1",
   "description": "A series of quest sequences",
   "type": "object",
                     "Z"
                   ]
                 },
+                "StopDistance": {
+                  "type": "number",
+                  "exclusiveMinimum": 0
+                },
                 "TerritoryId": {
                   "type": "integer",
                   "exclusiveMinimum": 0
                 "Disabled": {
                   "type": "boolean"
                 },
+                "AetheryteShortcut": {
+                  "type": "string",
+                  "$comment": "TODO add remaining aetherytes for 2.x/3.x",
+                  "enum": [
+                    "Limsa Lominsa",
+                    "Gridania",
+                    "Ul'dah",
+                    "Ishgard",
+
+                    "Rhalgr's Reach",
+                    "Fringes - Castrum Oriens",
+                    "Fringes - Peering Stones",
+                    "Peaks - Ala Gannha",
+                    "Peaks - Ala Ghiri",
+                    "Lochs - Porta Praetoria",
+                    "Lochs - Ala Mhigan Quarter",
+                    "Kugane",
+                    "Ruby Sea - Tamamizu",
+                    "Ruby Sea - Onokoro",
+                    "Yanxia - Namai",
+                    "Yanxia - House of the Fierce",
+                    "Azim Steppe - Reunion",
+                    "Azim Steppe - Dawn Throne",
+                    "Azim Steppe - Dhoro Iloh",
+                    "Doman Enclave",
+                    "Doman Enclave - Northern Enclave",
+                    "Doman Enclave - Southern Enclave",
+
+                    "Crystarium",
+                    "Eulmore",
+                    "Lakeland - Fort Jobb",
+                    "Lakeland - Ostall Imperative",
+                    "Kholusia - Stilltide",
+                    "Kholusia - Wright",
+                    "Kholusia - Tomra",
+                    "Amh Araeng - Mord Souq",
+                    "Amh Araeng - Inn at Journey's Head",
+                    "Amh Araeng - Twine",
+                    "Rak'tika - Slitherbough",
+                    "Rak'tika - Fanow",
+                    "Il Mheg - Lydha Lran",
+                    "Il Mheg - Pia Enni",
+                    "Il Mheg - Wolekdorf",
+                    "Tempest - Ondo Cups",
+                    "Tempest - Macarenses Angle",
+
+                    "Old Sharlayan",
+                    "Radz-at-Han",
+                    "Labyrinthos - Archeion",
+                    "Labyrinthos - Sharlayan Hamlet",
+                    "Labyrinthos - Aporia",
+                    "Thavnair - Yedlihmad",
+                    "Thavnair - Great Work",
+                    "Thavnair - Palaka's Stand",
+                    "Garlemald - Camp Broken Glass",
+                    "Garlemald - Tertium",
+                    "Mare Lamentorum - Sinus Lacrimarum",
+                    "Mare Lamentorum - Bestways Burrow",
+                    "Elpis - Anagnorisis",
+                    "Elpis - Twelve Wonders",
+                    "Elpis - Poieten Oikos",
+                    "Ultima Thule - Reah Tahra",
+                    "Ultima Thula - Abode of the Ea",
+                    "Ultima Thule - Base Omicron"
+                  ]
+                },
                 "AethernetShortcut": {
                   "type": "array",
                   "minItems": 2,
                       "[Kugane] Sekiseigumi Barracks",
                       "[Kugane] Rakuza District",
                       "[Kugane] Airship Landing",
-                      "[The Crystarium] Aetheryte Plaza",
-                      "[The Crystarium] Musica Universalis Markets",
-                      "[The Crystarium] Themenos Rookery",
-                      "[The Crystarium] The Dossal Gate",
-                      "[The Crystarium] The Pendants",
-                      "[The Crystarium] The Amaro Launch",
-                      "[The Crystarium] The Crystalline Mean",
-                      "[The Crystarium] The Cabinet of Curiosity",
+                      "[Crystarium] Aetheryte Plaza",
+                      "[Crystarium] Musica Universalis Markets",
+                      "[Crystarium] Themenos Rookery",
+                      "[Crystarium] The Dossal Gate",
+                      "[Crystarium] The Pendants",
+                      "[Crystarium] The Amaro Launch",
+                      "[Crystarium] The Crystalline Mean",
+                      "[Crystarium] The Cabinet of Curiosity",
                       "[Eulmore] Aetheryte Plaza",
                       "[Eulmore] Southeast Derelicts",
                       "[Eulmore] Nightsoil Pots",
                     ]
                   }
                 },
+                "EnemySpawnType": {
+                  "type": "string",
+                  "enum": [
+                    "AutoOnEnterArea",
+                    "AfterInteraction"
+                  ]
+                },
                 "KillEnemyDataIds": {
                   "type": "array",
                   "items": {
 
-using System.Numerics;
+using System;
+using System.Numerics;
 using Dalamud.Game;
 using Dalamud.Game.ClientState.Objects;
 using Dalamud.Interface.Windowing;
     private readonly IFramework _framework;
     private readonly IGameGui _gameGui;
     private readonly GameFunctions _gameFunctions;
+    private readonly QuestController _questController;
+
     private readonly MovementController _movementController;
 
     public Questionable(DalamudPluginInterface pluginInterface, IClientState clientState, ITargetManager targetManager,
         IFramework framework, IGameGui gameGui, IDataManager dataManager, ISigScanner sigScanner,
-        IPluginLog pluginLog)
+        IObjectTable objectTable, IPluginLog pluginLog, ICondition condition, IChatGui chatGui, ICommandManager commandManager)
     {
+        ArgumentNullException.ThrowIfNull(pluginInterface);
+        ArgumentNullException.ThrowIfNull(sigScanner);
+        ArgumentNullException.ThrowIfNull(dataManager);
+        ArgumentNullException.ThrowIfNull(objectTable);
+
         _pluginInterface = pluginInterface;
         _clientState = clientState;
         _framework = framework;
         _gameGui = gameGui;
-        _gameFunctions = new GameFunctions(dataManager, sigScanner);
+        _gameFunctions = new GameFunctions(dataManager, objectTable, sigScanner, targetManager, pluginLog);
+
+        NavmeshIpc navmeshIpc = new NavmeshIpc(pluginInterface);
         _movementController =
-            new MovementController(new NavmeshIpc(pluginInterface), clientState, _gameFunctions, pluginLog);
-        _windowSystem.AddWindow(new DebugWindow(_movementController, _gameFunctions, clientState, targetManager));
+            new MovementController(navmeshIpc, clientState, _gameFunctions, pluginLog);
+        _questController = new QuestController(pluginInterface, dataManager, _clientState, _gameFunctions,
+            _movementController, pluginLog, condition, chatGui, commandManager);
+        _windowSystem.AddWindow(new DebugWindow(_movementController, _questController, _gameFunctions, clientState,
+            targetManager));
 
         _pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
         _framework.Update += FrameworkUpdate;
 
     private void FrameworkUpdate(IFramework framework)
     {
-        HandleNavigationShortcut();
+        _questController.Update();
 
+        HandleNavigationShortcut();
         _movementController.Update();
     }
 
 
 using System.Globalization;
 using System.Numerics;
 using Dalamud.Game.ClientState.Objects;
+using Dalamud.Interface;
+using Dalamud.Interface.Components;
 using Dalamud.Interface.Windowing;
 using Dalamud.Plugin.Services;
 using FFXIVClientStructs.FFXIV.Client.Game.Control;
 using FFXIVClientStructs.FFXIV.Client.UI.Agent;
 using ImGuiNET;
 using Questionable.Controller;
+using Questionable.Model.V1;
 
 namespace Questionable.Windows;
 
 internal sealed class DebugWindow : Window
 {
     private readonly MovementController _movementController;
+    private readonly QuestController _questController;
     private readonly GameFunctions _gameFunctions;
     private readonly IClientState _clientState;
     private readonly ITargetManager _targetManager;
 
-    public DebugWindow(MovementController movementController, GameFunctions gameFunctions, IClientState clientState,
+    public DebugWindow(MovementController movementController, QuestController questController,
+        GameFunctions gameFunctions, IClientState clientState,
         ITargetManager targetManager)
         : base("Questionable", ImGuiWindowFlags.AlwaysAutoResize)
     {
         _movementController = movementController;
+        _questController = questController;
         _gameFunctions = gameFunctions;
         _clientState = clientState;
         _targetManager = targetManager;
         if (!_clientState.IsLoggedIn || _clientState.LocalPlayer == null)
             return;
 
+        var currentQuest = _questController.CurrentQuest;
+        if (currentQuest != null)
+        {
+            ImGui.TextUnformatted($"Quest: {currentQuest.Quest.Name} / {currentQuest.Sequence} / {currentQuest.Step}");
+            ImGui.TextUnformatted(_questController.DebugState ?? "--");
+
+            ImGui.BeginDisabled(_questController.GetNextStep().Step == null);
+            ImGui.Text($"{_questController.GetNextStep().Step?.Position}");
+            if (ImGuiComponents.IconButton(FontAwesomeIcon.Play))
+            {
+                _questController.ExecuteNextStep();
+            }
+
+            ImGui.SameLine();
+
+            if (ImGuiComponents.IconButton(FontAwesomeIcon.StepForward))
+            {
+                _questController.IncreaseStepCount();
+            }
+
+            ImGui.EndDisabled();
+        }
+        else
+            ImGui.Text("No active quest");
+
+        ImGui.Separator();
+
         ImGui.Text(
             $"Current TerritoryId: {_clientState.TerritoryType}, Flying: {(_gameFunctions.IsFlyingUnlocked(_clientState.TerritoryType) ? "Yes" : "No")}");
 
         if (_targetManager.Target != null)
         {
             ImGui.Separator();
-            ImGui.Text($"Target: {_targetManager.Target.Name}");
+            ImGui.Text(string.Create(CultureInfo.InvariantCulture,
+                $"Target: {_targetManager.Target.Name} ({(_targetManager.Target.Position - _clientState.LocalPlayer.Position).Length():F2})"));
 
             ImGui.BeginDisabled(!_movementController.IsNavmeshReady);
             if (!_movementController.IsPathfinding)
 
             ImGui.SameLine();
 
-            if (ImGui.Button($"Copy"))
+            ImGui.Button("Copy");
+            if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
             {
                 ImGui.SetClipboardText($$"""
                                          "DataId": {{_targetManager.Target.DataId}},
                                          "InteractionType": "Interact"
                                          """);
             }
+            else if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
+            {
+                EAetheryteLocation location = (EAetheryteLocation)_targetManager.Target.DataId;
+                ImGui.SetClipboardText(string.Create(CultureInfo.InvariantCulture,
+                    $"{{EAetheryteLocation.{location}, new({_targetManager.Target.Position.X}f, {_targetManager.Target.Position.Y}f, {_targetManager.Target.Position.Z}f)}},"));
+            }
         }
         else
         {