logistica-cd2025/logic/autocrafting_logic.lua

90 lines
3.0 KiB
Lua

-- returns a name-indexed count of items in the given list
-- adds to the existingMap if provided
local function count_items(list, existingMap)
local map = existingMap or {}
for _, stack in ipairs(list) do
if not stack:is_empty() then
local stName = stack:get_name()
if not map[stName] then map[stName] = 0 end
map[stName] = map[stName] + stack:get_count()
end
end
return map
end
-- returns a name indexed map to count of items in the given list
local function count_only_required_items(list)
local asList = logistica.get_smart_craft_output_results(list).requiredItems
if not asList then return {} end
local map = {}
for _, stack in ipairs(asList) do
map[stack:get_name()] = stack:get_count()
end
return map
end
-- returns {item = ItemStack, extras = {ItemStack, ItemStack...}}
-- item is an empty Itemstack if not successful
local function get_combined_crafting_ouputs(stacklist3x3)
local smartResult = logistica.get_smart_craft_output_results(stacklist3x3)
if not smartResult.output then return {item = ItemStack(), extras = {}} end
local item = smartResult.output
local extraMap = {}
count_items(smartResult.replacements or {}, extraMap)
count_items(smartResult.remainingDecrInput or {}, extraMap)
local extras = {}
local index = 0
for stName, count in pairs(extraMap) do
local stack = ItemStack(stName) ; stack:set_count(count)
index = index + 1
extras[index] = stack
end
return {item = item, extras = extras}
end
-- public functions
-- returns true if something was crafted, false if nothing was crafted
-- optSourceListName is optional: if nil, no checks will be made if enough materials exist
function logistica.autocrafting_produce_single_item(inv, recipeList3x3Name, optSourceListName, outputListName)
local recipeList = logistica.get_list(inv, recipeList3x3Name)
local craftRes = get_combined_crafting_ouputs(recipeList, true)
if craftRes.item:is_empty() then return false end
-- check if there's room for all the outputs
if not inv:room_for_item(outputListName, craftRes.item) then return false end
for _, st in ipairs(craftRes.extras) do
if not inv:room_for_item(outputListName, st) then return false end
end
if optSourceListName ~= nil then
-- check if source has enough materials
local recCounts = count_only_required_items(recipeList)
local srcCounts = count_items(logistica.get_list(inv, optSourceListName))
for name, count in pairs(recCounts) do
if srcCounts[name] == nil or srcCounts[name] < count then return false end
end
-- remove items from source
for name, _count in pairs(recCounts) do
local count = _count
repeat
local stack = ItemStack(name)
local take = math.min(count, stack:get_stack_max())
stack:set_count(take)
count = count - take
inv:remove_item(optSourceListName, stack)
until (count == 0)
end
end
-- add the output
inv:add_item(outputListName, craftRes.item)
for _, st in ipairs(craftRes.extras) do
inv:add_item(outputListName, st)
end
return true
end