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
 | 
						|
}
 |