127 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			127 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| -- luacheck: globals Character MyModGlobal Timer
 | |
| 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, nil)
 | |
| 				-- 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,
 | |
| }
 |