diff --git a/Questionable/Controller/ContextMenuController.cs b/Questionable/Controller/ContextMenuController.cs index 6b3f7f9f..59f0d876 100644 --- a/Questionable/Controller/ContextMenuController.cs +++ b/Questionable/Controller/ContextMenuController.cs @@ -108,6 +108,8 @@ internal sealed class ContextMenuController : IDisposable lockedReasonn = $"{classJob} not unlocked"; else if (quantityToGather == 0) lockedReasonn = "No allowances"; + else if (quantityToGather > _gameFunctions.GetFreeInventorySlots()) + lockedReasonn = "Inventory full"; else if (_gameFunctions.IsOccupied()) lockedReasonn = "Can't be used while interacting"; diff --git a/Questionable/Controller/Steps/Gathering/DoGather.cs b/Questionable/Controller/Steps/Gathering/DoGather.cs index 71ba96b1..9bdf27a2 100644 --- a/Questionable/Controller/Steps/Gathering/DoGather.cs +++ b/Questionable/Controller/Steps/Gathering/DoGather.cs @@ -4,12 +4,14 @@ using Dalamud.Game.ClientState.Conditions; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Component.GUI; using LLib.GameUI; +using Questionable.Functions; using Questionable.Model.Gathering; namespace Questionable.Controller.Steps.Gathering; internal sealed class DoGather( GatheringController gatheringController, + GameFunctions gameFunctions, IGameGui gameGui, ICondition condition) : ITask { @@ -33,6 +35,9 @@ internal sealed class DoGather( if (gatheringController.HasNodeDisappeared(_currentNode)) return ETaskResult.TaskComplete; + if (gameFunctions.GetFreeInventorySlots() == 0) + throw new TaskException("Inventory full"); + if (condition[ConditionFlag.Gathering]) { if (gameGui.TryGetAddonByName("GatheringMasterpiece", out AtkUnitBase* _)) diff --git a/Questionable/Controller/Steps/Gathering/DoGatherCollectable.cs b/Questionable/Controller/Steps/Gathering/DoGatherCollectable.cs index 36447e99..63432931 100644 --- a/Questionable/Controller/Steps/Gathering/DoGatherCollectable.cs +++ b/Questionable/Controller/Steps/Gathering/DoGatherCollectable.cs @@ -52,6 +52,9 @@ internal sealed class DoGatherCollectable( } } + if (gameFunctions.GetFreeInventorySlots() == 0) + throw new TaskException("Inventory full"); + NodeCondition? nodeCondition = GetNodeCondition(); if (nodeCondition == null) return ETaskResult.TaskComplete; diff --git a/Questionable/Functions/GameFunctions.cs b/Questionable/Functions/GameFunctions.cs index 689c340e..2427c81d 100644 --- a/Questionable/Functions/GameFunctions.cs +++ b/Questionable/Functions/GameFunctions.cs @@ -477,4 +477,30 @@ internal sealed unsafe class GameFunctions LAddon.IsAddonReady(fade) && fade->IsVisible; } + + public int GetFreeInventorySlots() + { + InventoryManager* inventoryManager = InventoryManager.Instance(); + if (inventoryManager == null) + return 0; + + int slots = 0; + for (InventoryType inventoryType = InventoryType.Inventory1; + inventoryType <= InventoryType.Inventory4; + ++inventoryType) + { + InventoryContainer* inventoryContainer = inventoryManager->GetInventoryContainer(inventoryType); + if (inventoryContainer == null) + continue; + + for (int i = 0; i < inventoryContainer->Size; ++i) + { + InventoryItem* item = inventoryContainer->GetInventorySlot(i); + if (item == null || item->ItemId == 0) + ++slots; + } + } + + return slots; + } }