diff --git a/Workshoppa/Windows/CeruleumTankWindow.cs b/Workshoppa/Windows/CeruleumTankWindow.cs index 045de8c..ee8e554 100644 --- a/Workshoppa/Windows/CeruleumTankWindow.cs +++ b/Workshoppa/Windows/CeruleumTankWindow.cs @@ -20,18 +20,21 @@ internal sealed class CeruleumTankWindow : ShopWindow private readonly WorkshopPlugin _plugin; private readonly IPluginLog _pluginLog; private readonly Configuration _configuration; + private readonly IChatGui _chatGui; private int _companyCredits; private int _buyStackCount; private bool _buyPartialStacks = true; - public CeruleumTankWindow(WorkshopPlugin plugin, IPluginLog pluginLog, - IGameGui gameGui, IAddonLifecycle addonLifecycle, Configuration configuration, - ExternalPluginHandler externalPluginHandler) - : base("Ceruleum Tanks###WorkshoppaCeruleumTankWindow", "FreeCompanyCreditShop", plugin, pluginLog, gameGui, addonLifecycle, externalPluginHandler) + public CeruleumTankWindow(WorkshopPlugin plugin, IPluginLog pluginLog, IGameGui gameGui, + IAddonLifecycle addonLifecycle, Configuration configuration, ExternalPluginHandler externalPluginHandler, + IChatGui chatGui) + : base("Ceruleum Tanks###WorkshoppaCeruleumTankWindow", "FreeCompanyCreditShop", plugin, pluginLog, gameGui, + addonLifecycle, externalPluginHandler) { _plugin = plugin; _pluginLog = pluginLog; + _chatGui = chatGui; _configuration = configuration; } @@ -41,7 +44,8 @@ internal sealed class CeruleumTankWindow : ShopWindow { if (addon->AtkValuesCount != 170) { - _pluginLog.Error($"Unexpected amount of atkvalues for FreeCompanyCreditShop addon ({addon->AtkValuesCount})"); + _pluginLog.Error( + $"Unexpected amount of atkvalues for FreeCompanyCreditShop addon ({addon->AtkValuesCount})"); _companyCredits = 0; ItemForSale = null; return; @@ -56,6 +60,7 @@ internal sealed class CeruleumTankWindow : ShopWindow ItemForSale = null; return; } + ItemForSale = Enumerable.Range(0, (int)itemCount) .Select(i => new ItemForSale { @@ -79,7 +84,7 @@ internal sealed class CeruleumTankWindow : ShopWindow } int ceruleumTanks = GetItemCount(CeruleumTankItemId); - int freeInventorySlots = _plugin.GetFreeInventorySlots(); + int freeInventorySlots = _plugin.CountFreeInventorySlots(); ImGui.Text("Inventory"); ImGui.Indent(); @@ -149,4 +154,61 @@ internal sealed class CeruleumTankWindow : ShopWindow }; addonShop->FireCallback(3, buyItem); } + + public bool TryParseBuyRequest(string arguments, out int missingQuantity) + { + if (!int.TryParse(arguments, out int stackCount) || stackCount <= 0) + { + missingQuantity = 0; + return false; + } + + int freeInventorySlots = _plugin.CountFreeInventorySlots(); + stackCount = Math.Min(freeInventorySlots, stackCount); + missingQuantity = Math.Min(GetMaxItemsToPurchase(), stackCount * 999); + return true; + } + + public bool TryParseFillRequest(string arguments, out int missingQuantity) + { + if (!int.TryParse(arguments, out int stackCount) || stackCount < 0) + { + missingQuantity = 0; + return false; + } + + int freeInventorySlots = _plugin.CountFreeInventorySlots(); + int partialStacks = _plugin.CountInventorySlotsWithCondition(CeruleumTankItemId, q => q < 999); + int fullStacks = _plugin.CountInventorySlotsWithCondition(CeruleumTankItemId, q => q == 999); + + int tanks = Math.Min((fullStacks + partialStacks + freeInventorySlots) * 999, + Math.Max(stackCount * 999, (fullStacks + partialStacks) * 999)); + _pluginLog.Information("T: " + tanks); + int owned = GetItemCount(CeruleumTankItemId); + if (tanks <= owned) + missingQuantity = 0; + else + missingQuantity = Math.Min(GetMaxItemsToPurchase(), tanks - owned); + + return true; + } + + public void StartPurchase(int quantity) + { + if (!IsOpen || ItemForSale == null) + { + _chatGui.PrintError("Could not start purchase, shop window is not open."); + return; + } + + if (quantity <= 0) + { + _chatGui.Print("Not buying ceruleum tanks, you already have enough."); + return; + } + + _chatGui.Print($"Starting purchase of {FormatStackCount(quantity)} ceruleum tanks."); + //StartAutoPurchase(quantity); + //HandleNextPurchaseStep(); + } } diff --git a/Workshoppa/WorkshopPlugin.GameFunctions.cs b/Workshoppa/WorkshopPlugin.GameFunctions.cs index a27ae48..04f69e7 100644 --- a/Workshoppa/WorkshopPlugin.GameFunctions.cs +++ b/Workshoppa/WorkshopPlugin.GameFunctions.cs @@ -232,9 +232,9 @@ partial class WorkshopPlugin return false; } - public bool HasFreeInventorySlot() => GetFreeInventorySlots() > 0; + public bool HasFreeInventorySlot() => CountFreeInventorySlots() > 0; - public unsafe int GetFreeInventorySlots() + public unsafe int CountFreeInventorySlots() { var inventoryManger = InventoryManager.Instance(); if (inventoryManger == null) @@ -255,6 +255,32 @@ partial class WorkshopPlugin return count; } + public unsafe int CountInventorySlotsWithCondition(uint itemId, Predicate predicate) + { + ArgumentNullException.ThrowIfNull(predicate); + + var inventoryManager = InventoryManager.Instance(); + if (inventoryManager == null) + return 0; + + int count = 0; + for (InventoryType t = InventoryType.Inventory1; t <= InventoryType.Inventory4; ++t) + { + var container = inventoryManager->GetInventoryContainer(t); + for (int i = 0; i < container->Size; ++i) + { + var item = container->GetInventorySlot(i); + if (item == null || item->ItemID == 0) + continue; + + if (item->ItemID == itemId && predicate((int)item->Quantity)) + ++count; + } + } + + return count; + } + public unsafe int DetermineMaxStackSize(uint itemId) { var inventoryManger = InventoryManager.Instance(); diff --git a/Workshoppa/WorkshopPlugin.cs b/Workshoppa/WorkshopPlugin.cs index 3f247df..8f1b509 100644 --- a/Workshoppa/WorkshopPlugin.cs +++ b/Workshoppa/WorkshopPlugin.cs @@ -80,7 +80,7 @@ public sealed partial class WorkshopPlugin : IDalamudPlugin _externalPluginHandler); _windowSystem.AddWindow(_repairKitWindow); _ceruleumTankWindow = new(this, _pluginLog, _gameGui, addonLifecycle, _configuration, - _externalPluginHandler); + _externalPluginHandler, _chatGui); _windowSystem.AddWindow(_ceruleumTankWindow); _pluginInterface.UiBuilder.Draw += _windowSystem.Draw; @@ -91,6 +91,18 @@ public sealed partial class WorkshopPlugin : IDalamudPlugin { HelpMessage = "Open UI" }); + _commandManager.AddHandler("/workshoppa", new CommandInfo(ProcessCommand) + { + ShowInHelp = false, + }); + _commandManager.AddHandler("/buy-tanks", new CommandInfo(ProcessBuyCommand) + { + HelpMessage = "Buy a given number of ceruleum tank stacks.", + }); + _commandManager.AddHandler("/fill-tanks", new CommandInfo(ProcessFillCommand) + { + HelpMessage = "Fill your inventory with a given number of ceruleum tank stacks.", + }); _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "SelectYesno", SelectYesNoPostSetup); _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "Request", RequestPostSetup); @@ -259,6 +271,22 @@ public sealed partial class WorkshopPlugin : IDalamudPlugin _mainWindow.Toggle(MainWindow.EOpenReason.Command); } + private void ProcessBuyCommand(string command, string arguments) + { + if (_ceruleumTankWindow.TryParseBuyRequest(arguments, out int missingQuantity)) + _ceruleumTankWindow.StartPurchase(missingQuantity); + else + _chatGui.PrintError($"Usage: {command} "); + } + + private void ProcessFillCommand(string command, string arguments) + { + if (_ceruleumTankWindow.TryParseFillRequest(arguments, out int missingQuantity)) + _ceruleumTankWindow.StartPurchase(missingQuantity); + else + _chatGui.PrintError($"Usage: {command} "); + } + private void OpenMainUi() => _mainWindow.Toggle(MainWindow.EOpenReason.PluginInstaller); @@ -268,6 +296,9 @@ public sealed partial class WorkshopPlugin : IDalamudPlugin _addonLifecycle.UnregisterListener(AddonEvent.PostRefresh, "Request", RequestPostRefresh); _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "Request", RequestPostSetup); _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "SelectYesno", SelectYesNoPostSetup); + _commandManager.RemoveHandler("/fill-tanks"); + _commandManager.RemoveHandler("/buy-tanks"); + _commandManager.RemoveHandler("/workshoppa"); _commandManager.RemoveHandler("/ws"); _pluginInterface.UiBuilder.Draw -= _windowSystem.Draw; _pluginInterface.UiBuilder.OpenConfigUi -= _configWindow.Toggle; diff --git a/Workshoppa/Workshoppa.csproj b/Workshoppa/Workshoppa.csproj index 5512134..e47e559 100644 --- a/Workshoppa/Workshoppa.csproj +++ b/Workshoppa/Workshoppa.csproj @@ -1,7 +1,7 @@ net8.0-windows - 5.3 + 5.4 11.0 enable true