using System; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game.UI; using Lumina.Excel.Sheets; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Model.Common; using Questionable.Model.Questing; namespace Questionable.Functions; internal sealed class AetheryteFunctions { private const uint TeleportAction = 5u; private const uint ReturnAction = 6u; private readonly IServiceProvider _serviceProvider; private readonly ILogger _logger; private readonly IDataManager _dataManager; private readonly IClientState _clientState; public DateTime ReturnRequestedAt { get; set; } = DateTime.MinValue; public AetheryteFunctions(IServiceProvider serviceProvider, ILogger logger, IDataManager dataManager, IClientState clientState) { _serviceProvider = serviceProvider; _logger = logger; _dataManager = dataManager; _clientState = clientState; } public unsafe bool IsAetheryteUnlocked(uint aetheryteId, out byte subIndex) { subIndex = 0; UIState* ptr = UIState.Instance(); if (ptr != null) { return ptr->IsAetheryteUnlocked(aetheryteId); } return false; } public bool IsAetheryteUnlocked(EAetheryteLocation aetheryteLocation) { if (aetheryteLocation.IsFirmamentAetheryte()) { return _serviceProvider.GetRequiredService().IsQuestComplete(new QuestId(3672)); } byte subIndex; return IsAetheryteUnlocked((uint)aetheryteLocation, out subIndex); } public unsafe bool CanTeleport(EAetheryteLocation aetheryteLocation) { if ((ushort)aetheryteLocation == PlayerState.Instance()->HomeAetheryteId && ActionManager.Instance()->GetActionStatus(ActionType.Action, 6u, 3758096384uL, checkRecastActive: true, checkCastingActive: true, null) == 0) { return true; } return ActionManager.Instance()->GetActionStatus(ActionType.Action, 5u, 3758096384uL, checkRecastActive: true, checkCastingActive: true, null) == 0; } public unsafe bool IsTeleportUnlocked() { uint rowId = _dataManager.GetExcelSheet().GetRow(5u).UnlockLink.RowId; return UIState.Instance()->IsUnlockLinkUnlocked(rowId); } public unsafe bool TeleportAetheryte(uint aetheryteId) { _logger.LogDebug("Attempting to teleport to aetheryte {AetheryteId}", aetheryteId); if (IsAetheryteUnlocked(aetheryteId, out var subIndex)) { if (aetheryteId == PlayerState.Instance()->HomeAetheryteId && ActionManager.Instance()->GetActionStatus(ActionType.Action, 6u, 3758096384uL, checkRecastActive: true, checkCastingActive: true, null) == 0) { ReturnRequestedAt = DateTime.Now; if (ActionManager.Instance()->UseAction(ActionType.Action, 6u, 3758096384uL, 0u, ActionManager.UseActionMode.None, 0u, null)) { _logger.LogInformation("Using 'return' for home aetheryte"); return true; } } if (ActionManager.Instance()->GetActionStatus(ActionType.Action, 5u, 3758096384uL, checkRecastActive: true, checkCastingActive: true, null) == 0) { _logger.LogInformation("Teleporting to aetheryte {AetheryteId}", aetheryteId); return Telepo.Instance()->Teleport(aetheryteId, subIndex); } } return false; } public bool TeleportAetheryte(EAetheryteLocation aetheryteLocation) { return TeleportAetheryte((uint)aetheryteLocation); } public unsafe bool IsFreeAetheryte(EAetheryteLocation aetheryteLocation) { PlayerState* ptr = PlayerState.Instance(); if (ptr != null) { if ((EAetheryteLocation)ptr->FreeAetheryteId != aetheryteLocation) { return (EAetheryteLocation)ptr->FreeAetherytePlayStationPlus == aetheryteLocation; } return true; } return false; } public unsafe AetheryteRegistrationResult CanRegisterFreeOrFavoriteAetheryte(EAetheryteLocation aetheryteLocation) { if (_clientState.LocalPlayer == null) { return AetheryteRegistrationResult.NotPossible; } PlayerState* ptr = PlayerState.Instance(); if (ptr == null) { return AetheryteRegistrationResult.NotPossible; } if (IsFreeAetheryte(aetheryteLocation)) { return AetheryteRegistrationResult.NotPossible; } bool flag = false; for (int i = 0; i < ptr->FavouriteAetheryteCount; i++) { if (ptr->FavouriteAetherytes[i] == (ushort)aetheryteLocation) { return AetheryteRegistrationResult.NotPossible; } if (ptr->FavouriteAetherytes[i] == 0) { flag = true; break; } } if (ptr->IsPlayerStateFlagSet(PlayerStateFlag.IsLoginSecurityToken) && ptr->FreeAetheryteId == 0) { return AetheryteRegistrationResult.SecurityTokenFreeDestinationAvailable; } if (!flag) { return AetheryteRegistrationResult.NotPossible; } return AetheryteRegistrationResult.FavoredDestinationAvailable; } }