181 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			181 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| -- luacheck: globals Character Game MyModGlobal
 | |
| local utils = require("Cyka.utils")
 | |
| local dump = require("Cyka.dump")
 | |
| 
 | |
| ---@return {item: Barotrauma.Item, fabricator: Barotrauma.FabricatorComponent}, string?
 | |
| local function getOpenFabricator()
 | |
| 	-- Get the controlled character
 | |
| 	local controlledCharacter = Character.Controlled
 | |
| 	if not controlledCharacter then return nil, "No controlled character found" end
 | |
| 
 | |
| 	-- Check if the character has a selected item
 | |
| 	local selectedItem = controlledCharacter.SelectedItem
 | |
| 	if not selectedItem then return nil, "No selected item found" end
 | |
| 
 | |
| 	-- Check if the selected item has a Fabricator component
 | |
| 	local fabricator = Game.GetFabricatorComponent(selectedItem)
 | |
| 	if not fabricator then return nil, "No fabricator component found" end
 | |
| 
 | |
| 	return {
 | |
| 		item = selectedItem,
 | |
| 		fabricator = fabricator
 | |
| 	}
 | |
| end
 | |
| 
 | |
| --- Recipes can have multiple inputs, for example ammo
 | |
| --- Can be made either out of copper iron or steel, 1 of either
 | |
| ---@class RecipeInfo
 | |
| ---@field targetItem {identifier: string, name: string, amount: number}
 | |
| ---@field requiredItems {amount: number, minCondition: number, maxCondition: number, prefabs: string[]}[]
 | |
| 
 | |
| ---@param fabricator Barotrauma.FabricatorComponent
 | |
| ---@return RecipeInfo, string?
 | |
| local function getSelectedRecipeRequirements(fabricator)
 | |
| 	-- local openFabricator, err = getOpenFabricator()
 | |
| 	-- if err then return nil, err end
 | |
| 	-- local fabricator = openFabricator.fabricator
 | |
| 
 | |
| 	local selectedRecipe = fabricator.SelectedItem
 | |
| 	if not selectedRecipe then return nil, "No selected recipe found" end
 | |
| 
 | |
| 	local requiredItems = {}
 | |
| 	for requiredItem in selectedRecipe.RequiredItems do
 | |
| 		local itemInfo = {
 | |
| 			amount = tonumber(requiredItem.Amount),
 | |
| 			minCondition = tonumber(requiredItem.MinCondition),
 | |
| 			maxCondition = tonumber(requiredItem.MaxCondition),
 | |
| 			prefabs = {}
 | |
| 		}
 | |
| 
 | |
| 		for prefab in requiredItem.ItemPrefabs do
 | |
| 			itemInfo.prefabs[#itemInfo.prefabs + 1] = prefab.Identifier.Value
 | |
| 		end
 | |
| 
 | |
| 		requiredItems[#requiredItems + 1] = itemInfo
 | |
| 	end
 | |
| 
 | |
| 	return {
 | |
| 		targetItem = {
 | |
| 			identifier = selectedRecipe.TargetItem.Identifier,
 | |
| 			name = selectedRecipe.TargetItem.Name,
 | |
| 			amount = selectedRecipe.Amount
 | |
| 		},
 | |
| 		requiredItems = requiredItems
 | |
| 	}
 | |
| end
 | |
| 
 | |
| ---@param character Barotrauma.Character
 | |
| local function tryStackFabricator(character)
 | |
| 	---@type Barotrauma.CharacterInventory
 | |
| 	local inventory = character.Inventory
 | |
| 	if not inventory then
 | |
| 		MyModGlobal.debugPrint("Character inventory is nil.")
 | |
| 		return
 | |
| 	end
 | |
| 	---@type Barotrauma.ItemInventory.Slot
 | |
| 	local bagSlot = inventory.slots[MyModGlobal.BAG_SLOT]
 | |
| 	if not bagSlot then
 | |
| 		MyModGlobal.debugPrint("Bag slot not found.")
 | |
| 		return
 | |
| 	end
 | |
| 	if #bagSlot.items == 0 then
 | |
| 		MyModGlobal.debugPrint("Bag slot is empty.")
 | |
| 		return
 | |
| 	end
 | |
| 	---@type Barotrauma.Item
 | |
| 	local bagItem = bagSlot.items[1]
 | |
| 	if not bagItem then
 | |
| 		MyModGlobal.debugPrint("Bag item not found.")
 | |
| 		return
 | |
| 	end
 | |
| 
 | |
| 	local fabricator, err = getOpenFabricator()
 | |
| 	if err then
 | |
| 		print(string.format("Error getting open fabricator: %s", err))
 | |
| 		return
 | |
| 	end
 | |
| 
 | |
| 	local recipe
 | |
| 	recipe, err = getSelectedRecipeRequirements(fabricator.fabricator)
 | |
| 	if err then
 | |
| 		print(string.format("Error getting selected recipe requirements: %s", err))
 | |
| 		return
 | |
| 	end
 | |
| 	-- MyModGlobal.DumpTable(recipe)
 | |
| 
 | |
| 	-- TODO: Maybe make it so every press cycles the input
 | |
| 	-- For recipes that have multiple prefabs
 | |
| 	-- But then again what if it has 3 items with 4 prefabs each..
 | |
| 	-- Is that 4 iterations or 3*4 iterations?
 | |
| 	-- We can not use #toFind because we can remove 0th item
 | |
| 	-- Which means it's no longer contiguous
 | |
| 	-- Which means #toFind returns 0
 | |
| 	local toFind = recipe.requiredItems
 | |
| 	local remaining = #toFind
 | |
| 	---@type Barotrauma.Item[]
 | |
| 	local toGet = {}
 | |
| 	---@type fun(item: Barotrauma.Item): boolean, boolean
 | |
| 	local filter = function(item)
 | |
| 		-- TODO: Take into account minCondition and maxCondition
 | |
| 		local found = false
 | |
| 		-- MyModGlobal.DumpTable(toFind)
 | |
| 		-- toFind are all items we need to find
 | |
| 		for i, itemInfo in pairs(toFind) do
 | |
| 			-- prefabs are all items that satisfy the requirements
 | |
| 			for _, prefab in ipairs(itemInfo.prefabs) do
 | |
| 				-- MyModGlobal.debugPrint(string.format("Checking %s against %s", item.Prefab.Identifier.Value, prefab))
 | |
| 				if item.Prefab.Identifier.Value == prefab then
 | |
| 					-- MyModGlobal.debugPrint(string.format("That'll do %s %s", item.Prefab.Identifier.Value, prefab))
 | |
| 					toGet[#toGet + 1] = item
 | |
| 					itemInfo.amount = itemInfo.amount - 1
 | |
| 					found = true
 | |
| 					break
 | |
| 				end
 | |
| 			end
 | |
| 			if itemInfo.amount <= 0 then
 | |
| 				-- MyModGlobal.debugPrint(string.format("Removing %s from toFind", itemInfo.prefabs[1]))
 | |
| 				toFind[i] = nil
 | |
| 				remaining = remaining - 1
 | |
| 			end
 | |
| 			if found then break end
 | |
| 		end
 | |
| 		-- MyModGlobal.DumpTable(toFind)
 | |
| 		-- MyModGlobal.debugPrint(string.format("Found %s %s", item.Prefab.Identifier.Value, tostring(remaining)))
 | |
| 		return found, remaining == 0
 | |
| 	end
 | |
| 	-- dump(itemsOnSubmarine)
 | |
| 	-- MyModGlobal.DumpTable(toGet)
 | |
| 
 | |
| 	local items, _ = utils.enqueueAllOwnedItems({}, filter)
 | |
| 	-- if err then
 | |
| 	-- 	print(string.format("Error enqueueing all owned items: %s", err))
 | |
| 	-- 	return
 | |
| 	-- end
 | |
| 	-- dump(items)
 | |
| 
 | |
| 	-- MyModGlobal.DumpTable(items)
 | |
| 	-- TODO: This might explode... Oh well?
 | |
| 	local inputInventory = fabricator.item.OwnInventories[1]
 | |
| 	for iinventory in fabricator.item.OwnInventories do
 | |
| 		if #iinventory.slots > 1 then
 | |
| 			inputInventory = iinventory
 | |
| 			break
 | |
| 		end
 | |
| 	end
 | |
| 
 | |
| 	local slot = -1
 | |
| 	local previous = nil
 | |
| 	for _, item in ipairs(items) do
 | |
| 		if previous ~= item.Prefab.Identifier then slot = slot + 1 end
 | |
| 		local moved = inputInventory.TryPutItem(item, slot, false, true, nil)
 | |
| 		if not moved then
 | |
| 			MyModGlobal.debugPrint(string.format("Failed to move %s", item.Prefab.Identifier.Value))
 | |
| 		end
 | |
| 		previous = item.Prefab.Identifier
 | |
| 	end
 | |
| end
 | |
| 
 | |
| return {
 | |
| 	tryStackFabricator = tryStackFabricator
 | |
| }
 |