-- luacheck: globals Character MyModGlobal Timer local quickstack = require("Cyka.quickstack") local utils = require("Cyka.utils") -- There is actually no need to recurse deep -- Because we can only have an item in the inventory open -- And not an item in an item in the inventory -- So in theory we only need to recurse 1 deep ---@param inventory Barotrauma.Inventory ---@param slots InventorySlot[] ---@param depth number ---@return InventorySlot[], string? local function getMouseoverSlots(inventory, slots, depth) slots = slots or {} depth = depth or 0 if depth > 1 then return slots, nil end local visualSlots = inventory.visualSlots if not visualSlots then return nil, "Inventory has no visual slots" end for i, visualSlot in ipairs(visualSlots) do local item local itemInventory -- local err local slot = inventory.slots[i] if not slot then -- MyModGlobal.debugPrint("Slot is not a valid slot") goto continue end if #slot.items == 0 then goto mouseover end item = slot.items[1] if not item then goto mouseover end itemInventory = item.OwnInventory if not itemInventory then goto mouseover end -- print("Before: " .. #slots)-- getMouseoverSlots(itemInventory, slots, depth + 1) -- if err then -- MyModGlobal.debugPrint(string.format("Error getting mouseover slots: %s", err)) -- end -- print("After: " .. #slots) ::mouseover:: if visualSlot:MouseOn() then slots[#slots + 1] = { inventory = inventory, slotIndex = i, slot = slot } end ::continue:: end return slots, nil end ---@class InventorySlot ---@field inventory Barotrauma.Inventory ---@field slotIndex number ---@field slot Barotrauma.Inventory.ItemSlot ---@return InventorySlot[], string? local function getInventorySlotsUnderCursor() -- Make sure we have a controlled character local controlledCharacter = Character.Controlled if not controlledCharacter then return nil, "No controlled character" end local inventory = controlledCharacter.Inventory if not inventory then return nil, "No inventory" end local mouseoverSlots, err = getMouseoverSlots(inventory) if err then return mouseoverSlots, err end local openContainers = quickstack.getOpenContainers() for _, container in ipairs(openContainers) do local containerInventories = container.OwnInventories for containerInventory in containerInventories do for i, visualSlot in ipairs(containerInventory.visualSlots) do if visualSlot:MouseOn() then local slot = containerInventory.slots[i] mouseoverSlots[#mouseoverSlots + 1] = { inventory = containerInventory, slotIndex = i, slot = slot } end end end end return mouseoverSlots, nil end local targetInventory = nil local slotThrottle = {} local function tryStackCursorItem() local slots, err = getInventorySlotsUnderCursor() if err then -- MyModGlobal.debugPrint(string.format("Error getting inventory slot: %s", err)) return end if not slots or #slots == 0 then -- MyModGlobal.debugPrint("No items in slot") return end local inventory = targetInventory -- MyModGlobal.debugPrint(string.format("Target inventory: %s", tostring(inventory))) if not inventory then local controlledCharacter = Character.Controlled if not controlledCharacter then -- MyModGlobal.debugPrint("No controlled character found") return end local cinventory = controlledCharacter.Inventory if not cinventory or not cinventory.slots then -- MyModGlobal.debugPrint("No inventory found") return end local bagSlot = cinventory.slots[MyModGlobal.BAG_SLOT] if not bagSlot or not bagSlot.items or not bagSlot.items[1] then -- MyModGlobal.debugPrint("No bag slot found") return end local bagItem = bagSlot.items[1] if not bagItem or not bagItem.OwnInventory then -- MyModGlobal.debugPrint("Bag item has no own inventory") return end local bagInventory = bagItem.OwnInventory if not bagInventory or not bagInventory.slots then -- MyModGlobal.debugPrint("Bag inventory has no slots") return end inventory = bagInventory end if not inventory then -- MyModGlobal.debugPrint("No inventory found") return end local itemTree itemTree, err = quickstack.buildItemTree(inventory) if err then -- MyModGlobal.debugPrint(string.format("Error building item tree: %s", err)) return end itemTree = quickstack.sortItemTree(itemTree) local itemsToMove = {} local now = Timer.GetTime() for _, slot in ipairs(slots) do local runAfter = slotThrottle[slot] or 0 if now < runAfter then goto continue end -- MyModGlobal.debugPrint(string.format("Enqueuing slot: %s, before: %d", tostring(slot), #itemsToMove)) utils.enqueueSlot(slot.slot, itemsToMove) -- MyModGlobal.debugPrint(string.format("Enqueuing slot: %s, after: %d", tostring(slot), #itemsToMove)) slotThrottle[slot] = now + 1 ::continue:: end -- for _, item in ipairs(itemsToMove) do -- MyModGlobal.debugPrint(string.format("Enqueued item: %s", tostring(item))) -- end -- -- MyModGlobal.debugPrint(string.format("Enqueued %d items from the inventory slot", #itemsToMove)) -- MyModGlobal.DumpTable(itemTree) quickstack.tryMoveItems(itemsToMove, itemTree, true) -- local errors = quickstack.tryMoveItems(itemsToMove, itemTree, true) -- for _, error in ipairs(errors) do -- MyModGlobal.debugPrint(string.format("Error moving item: %s", error)) -- end end local function setTargetInventory() ---@type InventorySlot[] local slots, err = getInventorySlotsUnderCursor() if err then MyModGlobal.debugPrint(string.format("Error getting inventory slot: %s", err)) return end if not slots or #slots == 0 then MyModGlobal.debugPrint("No inventory slots found") return end -- Yes we do this in a loop -- The idea is if we get one slot we're golden, great! -- If we get multiple we'll use the first valid one -- Although everything is valid to us... for _, slot in ipairs(slots) do local item local items = slot.slot.items if not items or #items == 0 then print(string.format("Slot is empty, setting target inventory to %s", tostring(slot.inventory))) targetInventory = slot.inventory goto continue end item = items[1] if not item then print(string.format("Item in slot is nil, setting target inventory to %s", tostring(slot.inventory))) targetInventory = slot.inventory goto continue end if not item.OwnInventory then print(string.format("Item has no own inventory, setting target inventory to %s", tostring(slot.inventory))) targetInventory = slot.inventory goto continue end print(string.format("Item has own inventory, setting target inventory to %s", tostring(item.OwnInventory))) targetInventory = item.OwnInventory break ::continue:: end end return { tryStackCursorItem = tryStackCursorItem, setTargetInventory = setTargetInventory, getInventorySlotsUnderCursor = getInventorySlotsUnderCursor }