using System; using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling.Payloads; using Deliveroo.GameData; using FFXIVClientStructs.FFXIV.Component.GUI; using LLib.GameUI; using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType; namespace Deliveroo; partial class DeliverooPlugin { private void InteractWithQuartermaster(GameObject personnelOfficer, GameObject quartermaster) { if (GetCurrentSealCount() < EffectiveReservedSealCount) { CurrentStage = Stage.RequestStop; return; } if (_targetManager.Target == personnelOfficer) return; InteractWithTarget(quartermaster); CurrentStage = Stage.SelectRewardTier; } private PurchaseItemRequest? GetNextItemToPurchase(PurchaseItemRequest? previousRequest = null) { foreach (PurchaseItemRequest request in _itemsToPurchaseNow) { int toBuy = 0; if (request == previousRequest) { toBuy = (int)request.StackSize; if (request.ItemId != ItemIds.Venture && !_configuration.IgnoreCertainLimitations) toBuy = Math.Min(toBuy, 99); } if (request.Type == Configuration.PurchaseType.KeepStocked) { if (GetItemCount(request.ItemId, request.CheckRetainerInventory) + toBuy < request.EffectiveLimit) return request; } else { if (toBuy < request.EffectiveLimit) return request; } } return null; } private unsafe void SelectRewardTier() { PurchaseItemRequest? item = GetNextItemToPurchase(); if (item == null) { CurrentStage = Stage.CloseGcExchange; return; } if (_gameGui.TryGetAddonByName("GrandCompanyExchange", out var addonExchange) && LAddon.IsAddonReady(addonExchange)) { _pluginLog.Information($"Selecting tier 1, {(int)item.Tier - 1}"); var selectRank = stackalloc AtkValue[] { new() { Type = ValueType.Int, Int = 1 }, new() { Type = ValueType.Int, Int = (int)item.Tier - 1 }, new() { Type = 0, Int = 0 }, new() { Type = 0, Int = 0 }, new() { Type = 0, Int = 0 }, new() { Type = 0, Int = 0 }, new() { Type = 0, Int = 0 }, new() { Type = 0, Int = 0 }, new() { Type = 0, Int = 0 } }; addonExchange->FireCallback(9, selectRank); _continueAt = DateTime.Now.AddSeconds(0.5); CurrentStage = Stage.SelectRewardSubCategory; } } private unsafe void SelectRewardSubCategory() { PurchaseItemRequest? item = GetNextItemToPurchase(); if (item == null) { CurrentStage = Stage.CloseGcExchange; return; } if (_gameGui.TryGetAddonByName("GrandCompanyExchange", out var addonExchange) && LAddon.IsAddonReady(addonExchange)) { _pluginLog.Information($"Selecting subcategory 2, {(int)item.SubCategory}"); var selectType = stackalloc AtkValue[] { new() { Type = ValueType.Int, Int = 2 }, new() { Type = ValueType.Int, Int = (int)item.SubCategory }, new() { Type = 0, Int = 0 }, new() { Type = 0, Int = 0 }, new() { Type = 0, Int = 0 }, new() { Type = 0, Int = 0 }, new() { Type = 0, Int = 0 }, new() { Type = 0, Int = 0 }, new() { Type = 0, Int = 0 } }; addonExchange->FireCallback(9, selectType); _continueAt = DateTime.Now.AddSeconds(0.5); CurrentStage = Stage.SelectReward; } } private unsafe void SelectReward() { if (_gameGui.TryGetAddonByName("GrandCompanyExchange", out var addonExchange) && LAddon.IsAddonReady(addonExchange)) { if (SelectRewardItem(addonExchange)) { _continueAt = DateTime.Now.AddSeconds(0.2); CurrentStage = Stage.ConfirmReward; } else { _continueAt = DateTime.Now.AddSeconds(0.2); CurrentStage = Stage.CloseGcExchange; } } } private unsafe bool SelectRewardItem(AtkUnitBase* addonExchange) { PurchaseItemRequest? item = GetNextItemToPurchase(); if (item == null) return false; uint itemsOnCurrentPage = addonExchange->AtkValues[1].UInt; for (uint i = 0; i < itemsOnCurrentPage; ++i) { uint itemId = addonExchange->AtkValues[317 + i].UInt; if (itemId == item.ItemId) { _pluginLog.Information($"Selecting item {itemId}, {i}"); long toBuy = (GetCurrentSealCount() - EffectiveReservedSealCount) / item.SealCost; if (item.Type == Configuration.PurchaseType.KeepStocked) toBuy = Math.Min(toBuy, item.EffectiveLimit - GetItemCount(item.ItemId, item.CheckRetainerInventory)); else toBuy = Math.Min(toBuy, item.EffectiveLimit); if (item.ItemId != ItemIds.Venture && !_configuration.IgnoreCertainLimitations) toBuy = Math.Min(toBuy, 99); if (toBuy <= 0) { _pluginLog.Information($"Items to buy = {toBuy}"); return false; } item.TemporaryPurchaseQuantity = toBuy; _chatGui.Print(new SeString(new TextPayload($"Buying {toBuy}x ")) .Append(SeString.CreateItemLink(item.ItemId)) .Append(new TextPayload("..."))); var selectReward = stackalloc AtkValue[] { new() { Type = ValueType.Int, Int = 0 }, new() { Type = ValueType.Int, Int = (int)i }, new() { Type = ValueType.Int, Int = (int)toBuy }, new() { Type = 0, Int = 0 }, new() { Type = ValueType.Bool, Byte = 1 }, new() { Type = ValueType.Bool, Byte = 0 }, new() { Type = 0, Int = 0 }, new() { Type = 0, Int = 0 }, new() { Type = 0, Int = 0 } }; addonExchange->FireCallback(9, selectReward); return true; } } _pluginLog.Warning("Could not find selected reward item"); return false; } private unsafe void CloseGcExchange() { if (_gameGui.TryGetAddonByName("GrandCompanyExchange", out var addonExchange) && LAddon.IsAddonReady(addonExchange)) { addonExchange->FireCallbackInt(-1); // If we just turned in the final item, there's no need to talk to the personnel officer again if (_lastTurnInListSize == 1) { _turnInWindow.State = false; CurrentStage = Stage.RequestStop; } else CurrentStage = Stage.TargetPersonnelOfficer; } } }