-- luacheck: globals Character MyModGlobal Timer CLIENT -- luacheck: max line length 420 if not CLIENT then return end local utils = require("Cyka.utils") local dump = require("Cyka.dump") -- Some items allow multiple items to be loaded -- Such as welders and cutters -- But we don't really want to disqualify those programmatically -- Because it is not so obvious what item we REALLY want to load -- So we will just hardcode tools and their whitelisted magazines ---@type table> local LOAD_MAP = require("Cyka.quickreload_loadmap") ---@param inventory Barotrauma.ItemInventory ---@return InventorySlot[] local function getSlots(inventory) local slots = {} local inventorySlots = inventory.slots for i, inventorySlot in ipairs(inventorySlots) do slots[#slots + 1] = { inventory = inventory, slotIndex = i - 1, slot = inventorySlot } end return slots end ---@param slots InventorySlot[] ---@return table local function getItemsPerSlot(slots) -- How many items can we move to what slot -- We don't yet know what can fit into what slot ---@type table local movableBySlot = {} -- Get all the items and then we will sort them by condition and shit utils.enqueueAllPlayerItems({}, function(ititem, itemRef) -- We don't want to take oxygen out of our diving suit to load our plasma cutter -- Most loadable items have 1 capacity -- But some have 2 or 3 (coil speargun) if itemRef and itemRef.inventory and itemRef.inventory.Capacity < 4 then -- MyModGlobal.debugPrint(string.format("Skipping small inventory %s", tostring(itemRef.inventory))) return false end -- MyModGlobal.debugPrint("Checking item:") -- dump(slots) -- MyModGlobal.debugPrint(ititem.Prefab.Identifier.Value) for _, inventorySlot in ipairs(slots) do local canMove = inventorySlot.inventory.CanBePutInSlot(ititem, inventorySlot.slotIndex) -- MyModGlobal.debugPrint(string.format("Can move to slot %d: %s", inventorySlot.slotIndex, tostring(canMove))) if canMove then movableBySlot[inventorySlot] = movableBySlot[inventorySlot] or {} movableBySlot[inventorySlot][#movableBySlot[inventorySlot] + 1] = ititem return true end end return false end, true) return movableBySlot end ---@param movableBySlot table ---@return table> local function getPermissibleItemsPerSlot(movableBySlot) -- The point of this exercise is to eliminate slots that can have -- Multiple items -- What do we put into those? Any? All? -- What if those slots belong to a container? -- Are we reloading 30 slot containers? ---@type table> local permissibleItemsPerSlot = {} for inventorySlot, items in pairs(movableBySlot) do for _, ititem in ipairs(items) do local thisone = tostring(ititem.Prefab.Identifier.Value) permissibleItemsPerSlot[inventorySlot] = permissibleItemsPerSlot[inventorySlot] or {} permissibleItemsPerSlot[inventorySlot][thisone] = true end end return permissibleItemsPerSlot end ---@param movableBySlot table local function printPermissibleItems(movableBySlot) local permissibleItemsPerSlot = getPermissibleItemsPerSlot(movableBySlot) MyModGlobal.debugPrint("Can load:") for _, loadableItems in pairs(permissibleItemsPerSlot) do for loadableItem, _ in pairs(loadableItems) do MyModGlobal.debugPrint(" " .. loadableItem) end end end ---@param slot InventorySlot ---@param preferMinCondition boolean local function tryReloadSlot(slot, preferMinCondition) ---@type Barotrauma.Item local item = slot.slot.items[1] if not item then MyModGlobal.debugPrint("No item in slot") return end MyModGlobal.debugPrint(string.format("Reloading item %s", item.Prefab.Identifier.Value)) local inventory = item.OwnInventory if not inventory then MyModGlobal.debugPrint("Item has no own inventory") return end ---@type InventorySlot[] local slots = getSlots(inventory) if #slots == 0 then MyModGlobal.debugPrint("No slots") return end -- MyModGlobal.debugPrint("Slots:") -- dump(slots) ---@type table local movableBySlot = getItemsPerSlot(slots) -- MyModGlobal.debugPrint("Movable by slot:") -- dump(movableBySlot) local permissibleItems = LOAD_MAP[tostring(item.Prefab.Identifier.Value)] if not permissibleItems then MyModGlobal.debugPrint("No permissible items for " .. tostring(item.Prefab.Identifier.Value)) printPermissibleItems(movableBySlot) return end -- Sort items by condition (asc or desc) but also -- Make sure items with 0 condition are at the end -- We don't really want to load those for _, items in pairs(movableBySlot) do table.sort(items, function(a, b) if a.Condition == 0 and b.Condition ~= 0 then return false elseif a.Condition ~= 0 and b.Condition == 0 then return true elseif preferMinCondition then return a.Condition < b.Condition else return a.Condition > b.Condition end end) end -- dump(movableBySlot) local numMoved = 0 for inventorySlot, items in pairs(movableBySlot) do for _, ititem in ipairs(items) do local permissible = permissibleItems[tostring(ititem.Prefab.Identifier.Value)] if permissible then -- We loaded as many as we have been allowed to -- And we do this check up front because an item may already -- Be partially loaded local nowHave = #inventorySlot.slot.items if nowHave >= permissible then -- MyModGlobal.debugPrint(string.format( -- "Finished processing item: %s. Current slot has reached the permissible limit of %d items.", -- tostring(ititem.Prefab.Identifier.Value), permissible)) break end local moved = inventorySlot.inventory.TryPutItem(ititem, inventorySlot.slotIndex, false, true, nil) -- When the slot is full no more will be able to be moved -- And tat that point we're done with that slot if not moved then break end numMoved = numMoved + 1 -- else -- MyModGlobal.debugPrint(string.format("Not permissible: %s", tostring(ititem.Prefab.Identifier.Value))) end end end MyModGlobal.debugPrint(string.format("Moved %d items to load %s", numMoved, tostring(item.Prefab.Identifier.Value))) end ---@param preferMinCondition boolean Prefer items with lowest condition local function tryReloadCursorItem(preferMinCondition) local slots, err = utils.getSlotsUnderCursor() if err then MyModGlobal.debugPrint(string.format("Error getting slots under cursor: %s", err)) return end for _, slot in ipairs(slots) do tryReloadSlot(slot, preferMinCondition) end end return { tryReloadCursorItem = tryReloadCursorItem, }