using System; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.UI.Agent; using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.Interop; using LLib.GameUI; namespace LLib.Shop; public static class SatisfactionSupplyActions { public readonly record struct NpcState(int Rank, int SatisfactionCurrent, int SatisfactionMax, int UsedDeliveries); private const string SatisfactionSupplyAddon = "SatisfactionSupply"; private const string SatisfactionSupplyResultAddon = "SatisfactionSupplyResult"; private const string TalkAddon = "Talk"; public unsafe static bool IsSatisfactionSupplyReady(IGameGui gameGui) { if (!gameGui.TryGetAddonByName("SatisfactionSupply", out var addonPtr)) { return false; } return LAddon.IsAddonReady(addonPtr); } public unsafe static bool IsSatisfactionSupplyFullyReady(IGameGui gameGui) { if (!gameGui.TryGetAddonByName("SatisfactionSupply", out var addonPtr)) { return false; } if (!LAddon.IsAddonReady(addonPtr)) { return false; } AgentSatisfactionSupply* ptr = AgentSatisfactionSupply.Instance(); if (ptr != null && ptr->IsAgentActive() && ptr->NpcInfo.Valid) { return ptr->NpcInfo.Initialized; } return false; } public unsafe static bool TrySelectDeliverySlot(IGameGui gameGui, int slot) { if (!IsSatisfactionSupplyFullyReady(gameGui)) { return false; } AgentSatisfactionSupply* ptr = AgentSatisfactionSupply.Instance(); AtkValue atkValue = new AtkValue(); Span span = stackalloc AtkValue[2]; span[0].SetInt(1); span[1].SetInt(slot); ptr->ReceiveEvent(&atkValue, span.GetPointer(0), 2u, 0uL); return true; } public unsafe static bool TryCloseSatisfactionSupply(IGameGui gameGui) { if (!gameGui.TryGetAddonByName("SatisfactionSupply", out var addonPtr)) { return false; } addonPtr->FireCallbackInt(0); return true; } public unsafe static bool IsTalkInProgress(IGameGui gameGui) { if (!gameGui.TryGetAddonByName("Talk", out var addonPtr)) { return false; } if (addonPtr->IsVisible) { return LAddon.IsAddonReady(addonPtr); } return false; } public unsafe static bool TryProgressTalk(IGameGui gameGui) { if (!gameGui.TryGetAddonByName("Talk", out var addonPtr)) { return false; } if (!addonPtr->IsVisible || !LAddon.IsAddonReady(addonPtr)) { return false; } addonPtr->FireCallbackInt(0); return true; } public unsafe static bool IsSatisfactionSupplyResultVisible(IGameGui gameGui) { if (!gameGui.TryGetAddonByName("SatisfactionSupplyResult", out var addonPtr)) { return false; } return LAddon.IsAddonReady(addonPtr); } public unsafe static bool TryCloseSatisfactionSupplyResult(IGameGui gameGui) { if (!gameGui.TryGetAddonByName("SatisfactionSupplyResult", out var addonPtr)) { return false; } addonPtr->Close(fireCallback: true); return true; } public unsafe static bool IsNpcTradeReady() { AgentNpcTrade* ptr = AgentNpcTrade.Instance(); if (ptr != null) { return ptr->IsAgentActive(); } return false; } public unsafe static (bool Exists, bool Active, int SelectedSlot) GetNpcTradeState() { AgentNpcTrade* ptr = AgentNpcTrade.Instance(); if (ptr == null) { return (Exists: false, Active: false, SelectedSlot: -99); } return (Exists: true, Active: ptr->IsAgentActive(), SelectedSlot: ptr->SelectedTurnInSlot); } public unsafe static bool TryConfirmTrade() { AgentNpcTrade* ptr = AgentNpcTrade.Instance(); if (ptr == null || !ptr->IsAgentActive()) { return false; } AtkValue atkValue = new AtkValue(); Span span = stackalloc AtkValue[4]; if (ptr->SelectedTurnInSlot < 0) { span[0].SetInt(2); span[1].SetInt(0); span[2].SetInt(0); span[3].SetInt(0); ptr->ReceiveEvent(&atkValue, span.GetPointer(0), 4u, 0uL); if (ptr->SelectedTurnInSlot != 0 || ptr->SelectedTurnInSlotItemOptions <= 0) { return false; } } else if (ptr->SelectedTurnInSlot != 0) { return false; } span[0].SetInt(0); span[1].SetInt(0); span[2].SetInt(0); span[3].SetInt(0); ptr->ReceiveEvent(&atkValue, span.GetPointer(0), 4u, 1uL); ptr->ReceiveEvent(&atkValue, span.GetPointer(0), 4u, 0uL); return true; } public unsafe static int GetRemainingAllowances() { SatisfactionSupplyManager* ptr = SatisfactionSupplyManager.Instance(); if (ptr == null) { return 0; } return ptr->GetRemainingAllowances(); } public unsafe static NpcState GetNpcState(int npcIndex) { SatisfactionSupplyManager* ptr = SatisfactionSupplyManager.Instance(); if (ptr == null) { return default(NpcState); } if (npcIndex < 0 || npcIndex >= ptr->SatisfactionRanks.Length) { return default(NpcState); } return new NpcState(ptr->SatisfactionRanks[npcIndex], ptr->Satisfaction[npcIndex], 0, ptr->UsedAllowances[npcIndex]); } public unsafe static uint GetSupplySeed() { SatisfactionSupplyManager* ptr = SatisfactionSupplyManager.Instance(); if (ptr == null) { return 0u; } return ptr->SupplySeed; } public unsafe static byte GetBonusGuaranteeRowId() { SatisfactionSupplyManager* ptr = SatisfactionSupplyManager.Instance(); if (ptr == null) { return byte.MaxValue; } return ptr->BonusGuaranteeRowId; } }