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