197 lines
6.7 KiB
Lua
197 lines
6.7 KiB
Lua
-- 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<string, table<string, number>>
|
|
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<InventorySlot, Barotrauma.Item[]>
|
|
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<InventorySlot, Barotrauma.Item[]>
|
|
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<InventorySlot, Barotrauma.Item[]>
|
|
---@return table<InventorySlot, table<Barotrauma.ItemPrefab, boolean>>
|
|
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<InventorySlot, table<Barotrauma.ItemPrefab, boolean>>
|
|
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<InventorySlot, Barotrauma.Item[]>
|
|
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<InventorySlot, Barotrauma.Item[]>
|
|
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, Character.Controlled, true)
|
|
-- 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,
|
|
}
|