224 lines
6.5 KiB
C#
224 lines
6.5 KiB
C#
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using Dalamud.Game.ClientState.Conditions;
|
|
using Dalamud.Game.ClientState.Objects.SubKinds;
|
|
using Dalamud.Plugin.Services;
|
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
|
using LLib.GameUI;
|
|
using Lumina.Excel.Sheets;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace LLib.GameData;
|
|
|
|
public sealed class GameStateHelper
|
|
{
|
|
private readonly IDataManager _dataManager;
|
|
|
|
private readonly IClientState _clientState;
|
|
|
|
private readonly ICondition _condition;
|
|
|
|
private readonly IObjectTable _objectTable;
|
|
|
|
private readonly IGameGui _gameGui;
|
|
|
|
private readonly ILogger<GameStateHelper> _logger;
|
|
|
|
private readonly ReadOnlyDictionary<uint, uint> _territoryToAetherCurrentCompFlgSet;
|
|
|
|
public GameStateHelper(IDataManager dataManager, IClientState clientState, ICondition condition, IObjectTable objectTable, IGameGui gameGui, ILogger<GameStateHelper> logger)
|
|
{
|
|
_dataManager = dataManager;
|
|
_clientState = clientState;
|
|
_condition = condition;
|
|
_objectTable = objectTable;
|
|
_gameGui = gameGui;
|
|
_logger = logger;
|
|
_territoryToAetherCurrentCompFlgSet = (from x in dataManager.GetExcelSheet<TerritoryType>()
|
|
where x.RowId != 0
|
|
where x.AetherCurrentCompFlgSet.RowId != 0
|
|
select x).ToDictionary((TerritoryType x) => x.RowId, (TerritoryType x) => x.AetherCurrentCompFlgSet.RowId).AsReadOnly();
|
|
}
|
|
|
|
public bool IsFlyingUnlocked(uint territoryId)
|
|
{
|
|
if (_territoryToAetherCurrentCompFlgSet.TryGetValue(territoryId, out var value))
|
|
{
|
|
return PlayerStateHelper.IsAetherCurrentZoneComplete(value);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool IsFlyingUnlockedInCurrentZone()
|
|
{
|
|
return IsFlyingUnlocked(_clientState.TerritoryType);
|
|
}
|
|
|
|
public unsafe ushort? GetMountId()
|
|
{
|
|
IPlayerCharacter localPlayer = _objectTable.LocalPlayer;
|
|
if (localPlayer == null)
|
|
{
|
|
return null;
|
|
}
|
|
BattleChara* address = (BattleChara*)localPlayer.Address;
|
|
if (address == null || address->Mount.MountId == 0)
|
|
{
|
|
return null;
|
|
}
|
|
return address->Mount.MountId;
|
|
}
|
|
|
|
public unsafe bool HasStatusPreventingMount()
|
|
{
|
|
if (_condition[ConditionFlag.Swimming] && !IsFlyingUnlockedInCurrentZone())
|
|
{
|
|
return true;
|
|
}
|
|
if (!PlayerStateHelper.IsAnyMountUnlocked())
|
|
{
|
|
return true;
|
|
}
|
|
IPlayerCharacter localPlayer = _objectTable.LocalPlayer;
|
|
if (localPlayer == null)
|
|
{
|
|
return false;
|
|
}
|
|
BattleChara* address = (BattleChara*)localPlayer.Address;
|
|
StatusManager* statusManager = address->GetStatusManager();
|
|
if (statusManager->HasStatus(1151u) || statusManager->HasStatus(1945u))
|
|
{
|
|
return true;
|
|
}
|
|
return HasStatusPreventingMountOrSprint();
|
|
}
|
|
|
|
public bool HasStatusPreventingSprint()
|
|
{
|
|
return HasStatusPreventingMountOrSprint();
|
|
}
|
|
|
|
public unsafe bool Mount(uint preferredMountId = 0u)
|
|
{
|
|
if (_condition[ConditionFlag.Mounted])
|
|
{
|
|
return true;
|
|
}
|
|
if (HasStatusPreventingMount())
|
|
{
|
|
_logger.LogDebug("Cannot mount: status or condition prevents it");
|
|
return false;
|
|
}
|
|
if (preferredMountId != 0 && PlayerStateHelper.IsMountUnlocked(preferredMountId))
|
|
{
|
|
if (ActionManager.Instance()->GetActionStatus(ActionType.Mount, preferredMountId, 3758096384uL, checkRecastActive: true, checkCastingActive: true, null) == 0)
|
|
{
|
|
_logger.LogDebug("Attempting preferred mount {Id}", preferredMountId);
|
|
if (ActionManager.Instance()->UseAction(ActionType.Mount, preferredMountId, 3758096384uL, 0u, ActionManager.UseActionMode.None, 0u, null))
|
|
{
|
|
_logger.LogInformation("Mounted (preferred {Id})", preferredMountId);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
if (ActionManager.Instance()->GetActionStatus(ActionType.GeneralAction, 9u, 3758096384uL, checkRecastActive: true, checkCastingActive: true, null) == 0)
|
|
{
|
|
_logger.LogDebug("Attempting mount roulette");
|
|
if (ActionManager.Instance()->UseAction(ActionType.GeneralAction, 9u, 3758096384uL, 0u, ActionManager.UseActionMode.None, 0u, null))
|
|
{
|
|
_logger.LogInformation("Mounted (roulette)");
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public unsafe bool Unmount()
|
|
{
|
|
if (!_condition[ConditionFlag.Mounted])
|
|
{
|
|
return true;
|
|
}
|
|
if (ActionManager.Instance()->GetActionStatus(ActionType.GeneralAction, 23u, 3758096384uL, checkRecastActive: true, checkCastingActive: true, null) != 0)
|
|
{
|
|
_logger.LogDebug("Cannot unmount: action on cooldown");
|
|
return false;
|
|
}
|
|
_logger.LogDebug("Attempting dismount");
|
|
if (ActionManager.Instance()->UseAction(ActionType.GeneralAction, 23u, 3758096384uL, 0u, ActionManager.UseActionMode.None, 0u, null))
|
|
{
|
|
_logger.LogInformation("Unmounted");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public unsafe int? GetFreeInventorySlots()
|
|
{
|
|
InventoryManager* ptr = InventoryManager.Instance();
|
|
if (ptr == null)
|
|
{
|
|
return null;
|
|
}
|
|
int num = 0;
|
|
for (InventoryType inventoryType = InventoryType.Inventory1; inventoryType <= InventoryType.Inventory4; inventoryType++)
|
|
{
|
|
InventoryContainer* inventoryContainer = ptr->GetInventoryContainer(inventoryType);
|
|
if (inventoryContainer == null)
|
|
{
|
|
return null;
|
|
}
|
|
for (int i = 0; i < inventoryContainer->Size; i++)
|
|
{
|
|
InventoryItem* inventorySlot = inventoryContainer->GetInventorySlot(i);
|
|
if (inventorySlot == null || inventorySlot->ItemId == 0)
|
|
{
|
|
num++;
|
|
}
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public uint GetItemLevel(uint itemId)
|
|
{
|
|
return _dataManager.GetExcelSheet<Item>().GetRowOrDefault(itemId)?.LevelItem.RowId ?? 0;
|
|
}
|
|
|
|
public unsafe bool IsLoadingScreenVisible()
|
|
{
|
|
if (_gameGui.TryGetAddonByName<AtkUnitBase>("FadeMiddle", out var addonPtr) && LAddon.IsAddonReady(addonPtr) && addonPtr->IsVisible)
|
|
{
|
|
return true;
|
|
}
|
|
if (_gameGui.TryGetAddonByName<AtkUnitBase>("FadeBack", out addonPtr) && LAddon.IsAddonReady(addonPtr) && addonPtr->IsVisible)
|
|
{
|
|
return true;
|
|
}
|
|
if (_gameGui.TryGetAddonByName<AtkUnitBase>("NowLoading", out addonPtr) && LAddon.IsAddonReady(addonPtr) && addonPtr->IsVisible)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private unsafe bool HasStatusPreventingMountOrSprint()
|
|
{
|
|
IPlayerCharacter localPlayer = _objectTable.LocalPlayer;
|
|
if (localPlayer == null)
|
|
{
|
|
return false;
|
|
}
|
|
BattleChara* address = (BattleChara*)localPlayer.Address;
|
|
StatusManager* statusManager = address->GetStatusManager();
|
|
if (!statusManager->HasStatus(565u) && !statusManager->HasStatus(404u) && !statusManager->HasStatus(416u) && !statusManager->HasStatus(2729u))
|
|
{
|
|
return statusManager->HasStatus(2730u);
|
|
}
|
|
return true;
|
|
}
|
|
}
|