195 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| -- luacheck: globals Character MyModGlobal Timer
 | |
| -- luacheck: max line length 420
 | |
| 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, 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,
 | |
| }
 |