-- 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) ---@type InventorySlot[] local slots = {} ---@type Barotrauma.Inventory.ItemSlot[] local inventorySlots = inventory.slots for i, _ in ipairs(inventorySlots) do local invSlot = MyModGlobal.InventorySlot.new(inventory, i) slots[#slots + 1] = invSlot 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.enqueuePlayerItems({ recurse = true, loadRefs = true, itemPredicate = function(ititem, itemRef) MyModGlobal.debugPrint(string.format("Checking item: %s", tostring(ititem))) -- 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.slotIndex1 - 1) -- 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 }) 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 invSlot InventorySlot ---@param preferMinCondition boolean local function tryReloadSlot(invSlot, preferMinCondition) ---@type Barotrauma.Item local item = invSlot.item 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 ---@type table local movableBySlot = getItemsPerSlot(slots) -- MyModGlobal.debugPrint("Movable by slot:") 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.stackSize 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 if not inventorySlot:canFit(ititem.Prefab) then break end utils.enqueueMove(ititem, inventorySlot) numMoved = numMoved + 1 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, }