diff --git a/Questionable/Controller/Steps/Interactions/UseItem.cs b/Questionable/Controller/Steps/Interactions/UseItem.cs
index 05dbd72e..497ae617 100644
--- a/Questionable/Controller/Steps/Interactions/UseItem.cs
+++ b/Questionable/Controller/Steps/Interactions/UseItem.cs
@@ -1,11 +1,14 @@
 using System;
 using System.Collections.Generic;
+using System.Numerics;
 using FFXIVClientStructs.FFXIV.Client.Game;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
 using Questionable.Controller.Steps.Common;
+using Questionable.Controller.Steps.Shared;
 using Questionable.Model;
 using Questionable.Model.V1;
+using AethernetShortcut = Questionable.Controller.Steps.Shared.AethernetShortcut;
 
 namespace Questionable.Controller.Steps.Interactions;
 
@@ -13,7 +16,7 @@ internal static class UseItem
 {
     public const int VesperBayAetheryteTicket = 30362;
 
-    internal sealed class Factory(IServiceProvider serviceProvider) : ITaskFactory
+    internal sealed class Factory(IServiceProvider serviceProvider, ILogger<Factory> logger) : ITaskFactory
     {
         public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
         {
@@ -22,6 +25,16 @@ internal static class UseItem
 
             ArgumentNullException.ThrowIfNull(step.ItemId);
 
+            if (step.ItemId == VesperBayAetheryteTicket)
+            {
+                unsafe
+                {
+                    InventoryManager* inventoryManager = InventoryManager.Instance();
+                    if (inventoryManager->GetInventoryItemCount(step.ItemId.Value) == 0)
+                        return CreateVesperBayFallbackTask();
+                }
+            }
+
             var unmount = serviceProvider.GetRequiredService<UnmountTask>();
             if (step.GroundTarget == true)
             {
@@ -47,6 +60,23 @@ internal static class UseItem
 
         public ITask CreateTask(Quest quest, QuestSequence sequence, QuestStep step)
             => throw new InvalidOperationException();
+
+        private IEnumerable<ITask> CreateVesperBayFallbackTask()
+        {
+            logger.LogWarning("No vesper bay aetheryte tickets in inventory, navigating via ferry in Limsa instead");
+
+            uint npcId = 1003540;
+            ushort territoryId = 129;
+            Vector3 destination = new(-360.9217f, 8f, 38.92566f);
+            yield return serviceProvider.GetRequiredService<AetheryteShortcut.UseAetheryteShortcut>()
+                .With(null, EAetheryteLocation.Limsa, territoryId);
+            yield return serviceProvider.GetRequiredService<AethernetShortcut.UseAethernetShortcut>()
+                .With(EAetheryteLocation.Limsa, EAetheryteLocation.LimsaArcanist);
+            yield return serviceProvider.GetRequiredService<Move.MoveInternal>()
+                .With(territoryId, destination, dataId: npcId, sprint: false);
+            yield return serviceProvider.GetRequiredService<Interact.DoInteract>()
+                .With(npcId, true);
+        }
     }
 
     internal abstract class UseItemBase(ILogger logger) : ITask
diff --git a/Questionable/Controller/Steps/Shared/AetheryteShortcut.cs b/Questionable/Controller/Steps/Shared/AetheryteShortcut.cs
index 2f645ea6..f897fe64 100644
--- a/Questionable/Controller/Steps/Shared/AetheryteShortcut.cs
+++ b/Questionable/Controller/Steps/Shared/AetheryteShortcut.cs
@@ -45,7 +45,7 @@ internal static class AetheryteShortcut
     {
         private DateTime _continueAt;
 
-        public QuestStep Step { get; set; } = null!;
+        public QuestStep? Step { get; set; }
         public EAetheryteLocation TargetAetheryte { get; set; }
 
         /// <summary>
@@ -54,7 +54,7 @@ internal static class AetheryteShortcut
         /// </summary>
         public ushort ExpectedTerritoryId { get; set; }
 
-        public ITask With(QuestStep step, EAetheryteLocation targetAetheryte, ushort expectedTerritoryId)
+        public ITask With(QuestStep? step, EAetheryteLocation targetAetheryte, ushort expectedTerritoryId)
         {
             Step = step;
             TargetAetheryte = targetAetheryte;
@@ -66,7 +66,7 @@ internal static class AetheryteShortcut
         {
             _continueAt = DateTime.Now.AddSeconds(8);
             ushort territoryType = clientState.TerritoryType;
-            if (ExpectedTerritoryId == territoryType)
+            if (Step != null && ExpectedTerritoryId == territoryType)
             {
                 if (Step.SkipIf.Contains(ESkipCondition.AetheryteShortcutIfInSameTerritory))
                 {
diff --git a/Questionable/Controller/Steps/Shared/Move.cs b/Questionable/Controller/Steps/Shared/Move.cs
index d6da1491..75fd691a 100644
--- a/Questionable/Controller/Steps/Shared/Move.cs
+++ b/Questionable/Controller/Steps/Shared/Move.cs
@@ -99,15 +99,7 @@ internal static class Move
                 if (actualDistance > distance)
                 {
                     yield return serviceProvider.GetRequiredService<MoveInternal>()
-                        .With(Destination, m =>
-                        {
-                            m.NavigateTo(EMovementType.Quest, Step.DataId, Destination,
-                                fly: Step.Fly == true && gameFunctions.IsFlyingUnlocked(Step.TerritoryId),
-                                sprint: Step.Sprint != false,
-                                stopDistance: distance,
-                                ignoreDistanceToObject: Step.IgnoreDistanceToObject == true,
-                                land: Step.Land == true);
-                        });
+                        .With(Step, Destination);
                 }
             }
             else
@@ -116,14 +108,7 @@ internal static class Move
                 if (actualDistance > distance)
                 {
                     yield return serviceProvider.GetRequiredService<MoveInternal>()
-                        .With(Destination, m =>
-                        {
-                            m.NavigateTo(EMovementType.Quest, Step.DataId, [Destination],
-                                fly: Step.Fly == true && gameFunctions.IsFlyingUnlockedInCurrentZone(),
-                                sprint: Step.Sprint != false,
-                                stopDistance: distance,
-                                land: Step.Land == true);
-                        });
+                        .With(Step, Destination);
                 }
             }
 
@@ -132,22 +117,68 @@ internal static class Move
         }
     }
 
-    internal sealed class MoveInternal(MovementController movementController, ILogger<MoveInternal> logger) : ITask
+    internal sealed class MoveInternal(
+        MovementController movementController,
+        GameFunctions gameFunctions,
+        ILogger<MoveInternal> logger) : ITask
     {
-        public Action<MovementController> StartAction { get; set; } = null!;
+        public Action StartAction { get; set; } = null!;
         public Vector3 Destination { get; set; }
 
-        public ITask With(Vector3 destination, Action<MovementController> startAction)
+        public ITask With(QuestStep step, Vector3 destination)
+        {
+            return With(
+                territoryId: step.TerritoryId,
+                destination: destination,
+                stopDistance: step.StopDistance,
+                dataId: step.DataId,
+                disableNavMesh: step.DisableNavmesh,
+                sprint: step.Sprint != false,
+                fly: step.Fly == true,
+                land: step.Land == true,
+                ignoreDistanceToObject: step.IgnoreDistanceToObject == true);
+        }
+
+        public ITask With(ushort territoryId, Vector3 destination, float? stopDistance = null, uint? dataId = null,
+            bool disableNavMesh = false, bool sprint = true, bool fly = false, bool land = false,
+            bool ignoreDistanceToObject = false)
         {
             Destination = destination;
-            StartAction = startAction;
+
+            if (!gameFunctions.IsFlyingUnlocked(territoryId))
+            {
+                fly = false;
+                land = false;
+            }
+
+            if (!disableNavMesh)
+            {
+                StartAction = () =>
+                    movementController.NavigateTo(EMovementType.Quest, dataId, Destination,
+                        fly: fly,
+                        sprint: sprint,
+                        stopDistance: stopDistance,
+                        ignoreDistanceToObject: ignoreDistanceToObject,
+                        land: land);
+            }
+            else
+            {
+                StartAction = () =>
+                    movementController.NavigateTo(EMovementType.Quest, dataId, [Destination],
+                        fly: fly,
+                        sprint: sprint,
+                        stopDistance: stopDistance,
+                        ignoreDistanceToObject: ignoreDistanceToObject,
+                        land: land);
+            }
+
             return this;
         }
 
         public bool Start()
         {
             logger.LogInformation("Moving to {Destination}", Destination.ToString("G", CultureInfo.InvariantCulture));
-            StartAction(movementController);
+            StartAction();
             return true;
         }