Files
barotrauma-localmods/CykaQuick/Lua/Cyka/quickunload.lua

130 lines
3.6 KiB
Lua

-- luacheck: globals Character MyModGlobal Timer CLIENT
if not CLIENT then return end
local utils = require("Cyka.utils")
---@param inventory Barotrauma.ItemInventory
---@param predicate fun(slot: InventorySlot): boolean
---@return InventorySlot[], string?
local function findSlotsThat(inventory, predicate)
local slots = {}
for i, slot in ipairs(inventory.slots) do
local inventorySlot = {
slot = slot,
inventory = inventory,
slotIndex = i - 1
}
if predicate(inventorySlot) then
slots[#slots + 1] = inventorySlot
end
end
return slots
end
---@param slot InventorySlot
local function tryUnloadSlot(slot)
---@type Barotrauma.Item
local item = slot.slot.items[1]
if not item then
MyModGlobal.debugPrint("No item in slot")
return
end
local inventory = item.OwnInventory
if not inventory then
MyModGlobal.debugPrint("Item has no own inventory")
return
end
local toUnload = {}
local toUnloadByPrefab = {}
local inventorySlots = inventory.slots
for _, inventorySlot in ipairs(inventorySlots) do
for _, inventoryItem in ipairs(inventorySlot.items) do
toUnload[#toUnload + 1] = inventoryItem
-- This will only serve as O(1) lookup
toUnloadByPrefab[inventoryItem.Prefab] = true
end
end
-- Where can we put our toUnload items?
local nearbySlots = findSlotsThat(slot.inventory, function(islot)
local isEmpty = #islot.slot.items == 0
if isEmpty then return true end
for _, prefab in ipairs(toUnloadByPrefab) do
local canAccept = islot.inventory.CanBePutInSlot(prefab, islot.slotIndex)
if canAccept then return true end
end
return false
end)
-- print("Before sorting:")
-- dump(nearbySlots)
-- Some inventories don't have slots per row, like the player inventory
local slotsPerRow = 900
local ok, err = pcall(function()
slotsPerRow = slot.inventory.slotsPerRow
end)
if not ok then
MyModGlobal.debugPrint(string.format("Error getting slots per row: %s", err))
end
local getGridPos = function(slotIndex)
local x = slotIndex % slotsPerRow
local y = math.floor(slotIndex / slotsPerRow)
return x, y
end
-- We are offsetting here by 1 because the backend uses 0-indexed slots
-- And the lua uses 1-indexed slots
-- We are trying to match the backend behavior for sorting
local slotx, sloty = getGridPos(slot.slotIndex - 1)
-- print(string.format("Slot position %d: %d, %d", slot.slotIndex, slotx, sloty))
table.sort(nearbySlots, function(a, b)
local ax, ay = getGridPos(a.slotIndex)
local bx, by = getGridPos(b.slotIndex)
local distA = math.max(math.abs(ax - slotx), math.abs(ay - sloty))
local distB = math.max(math.abs(bx - slotx), math.abs(by - sloty))
if distA == distB then
return a.slotIndex < b.slotIndex
end
return distA < distB
end)
-- print(string.format("Current slot: %d at (%d, %d)", slot.slotIndex, slotx, sloty))
for _, iitem in ipairs(toUnload) do
for _, nearbySlot in ipairs(nearbySlots) do
local canAccept = nearbySlot.inventory.CanBePutInSlot(iitem.Prefab, nearbySlot.slotIndex)
if canAccept then
local moved = nearbySlot.inventory.TryPutItem(iitem, nearbySlot.slotIndex, true, false,
Character.Controlled, true)
-- print(string.format("Moved item %s to slot %d", iitem.Name, nearbySlot.slotIndex))
if moved then break end
end
end
end
end
local function tryUnloadCursorItem()
local slots, err = utils.getSlotsUnderCursor()
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
for _, slot in ipairs(slots) do
tryUnloadSlot(slot)
end
end
return {
tryUnloadCursorItem = tryUnloadCursorItem,
}