Add fallback for missing versper bay aetheryte tickets

arr-p5
Liza 2024-07-15 21:38:38 +02:00
parent 0eb77927b3
commit d20a768996
Signed by: liza
GPG Key ID: 7199F8D727D55F67
3 changed files with 87 additions and 26 deletions

View File

@ -1,11 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Numerics;
using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Questionable.Controller.Steps.Common; using Questionable.Controller.Steps.Common;
using Questionable.Controller.Steps.Shared;
using Questionable.Model; using Questionable.Model;
using Questionable.Model.V1; using Questionable.Model.V1;
using AethernetShortcut = Questionable.Controller.Steps.Shared.AethernetShortcut;
namespace Questionable.Controller.Steps.Interactions; namespace Questionable.Controller.Steps.Interactions;
@ -13,7 +16,7 @@ internal static class UseItem
{ {
public const int VesperBayAetheryteTicket = 30362; 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) public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
{ {
@ -22,6 +25,16 @@ internal static class UseItem
ArgumentNullException.ThrowIfNull(step.ItemId); 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>(); var unmount = serviceProvider.GetRequiredService<UnmountTask>();
if (step.GroundTarget == true) if (step.GroundTarget == true)
{ {
@ -47,6 +60,23 @@ internal static class UseItem
public ITask CreateTask(Quest quest, QuestSequence sequence, QuestStep step) public ITask CreateTask(Quest quest, QuestSequence sequence, QuestStep step)
=> throw new InvalidOperationException(); => 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 internal abstract class UseItemBase(ILogger logger) : ITask

View File

@ -45,7 +45,7 @@ internal static class AetheryteShortcut
{ {
private DateTime _continueAt; private DateTime _continueAt;
public QuestStep Step { get; set; } = null!; public QuestStep? Step { get; set; }
public EAetheryteLocation TargetAetheryte { get; set; } public EAetheryteLocation TargetAetheryte { get; set; }
/// <summary> /// <summary>
@ -54,7 +54,7 @@ internal static class AetheryteShortcut
/// </summary> /// </summary>
public ushort ExpectedTerritoryId { get; set; } 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; Step = step;
TargetAetheryte = targetAetheryte; TargetAetheryte = targetAetheryte;
@ -66,7 +66,7 @@ internal static class AetheryteShortcut
{ {
_continueAt = DateTime.Now.AddSeconds(8); _continueAt = DateTime.Now.AddSeconds(8);
ushort territoryType = clientState.TerritoryType; ushort territoryType = clientState.TerritoryType;
if (ExpectedTerritoryId == territoryType) if (Step != null && ExpectedTerritoryId == territoryType)
{ {
if (Step.SkipIf.Contains(ESkipCondition.AetheryteShortcutIfInSameTerritory)) if (Step.SkipIf.Contains(ESkipCondition.AetheryteShortcutIfInSameTerritory))
{ {

View File

@ -99,15 +99,7 @@ internal static class Move
if (actualDistance > distance) if (actualDistance > distance)
{ {
yield return serviceProvider.GetRequiredService<MoveInternal>() yield return serviceProvider.GetRequiredService<MoveInternal>()
.With(Destination, m => .With(Step, Destination);
{
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);
});
} }
} }
else else
@ -116,14 +108,7 @@ internal static class Move
if (actualDistance > distance) if (actualDistance > distance)
{ {
yield return serviceProvider.GetRequiredService<MoveInternal>() yield return serviceProvider.GetRequiredService<MoveInternal>()
.With(Destination, m => .With(Step, Destination);
{
m.NavigateTo(EMovementType.Quest, Step.DataId, [Destination],
fly: Step.Fly == true && gameFunctions.IsFlyingUnlockedInCurrentZone(),
sprint: Step.Sprint != false,
stopDistance: distance,
land: Step.Land == true);
});
} }
} }
@ -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 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; 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; return this;
} }
public bool Start() public bool Start()
{ {
logger.LogInformation("Moving to {Destination}", Destination.ToString("G", CultureInfo.InvariantCulture)); logger.LogInformation("Moving to {Destination}", Destination.ToString("G", CultureInfo.InvariantCulture));
StartAction(movementController); StartAction();
return true; return true;
} }