166 lines
7.0 KiB
Lua
166 lines
7.0 KiB
Lua
-- AD Chain Actions (ren logik): mellemled der skal tændes/slukkes, flows der mangler eller skal stoppes.
|
|
|
|
ADChainActions = {}
|
|
|
|
-- protected = {[nøgle] = cyklusser}: behov fra pausede rødder — slukkes ikke, men tændes heller ikke.
|
|
function ADChainActions.productions(recipes, needRecipes, protected)
|
|
local result = {enable = {}, disable = {}}
|
|
for _, recipe in ipairs(recipes or {}) do
|
|
local needed = ((needRecipes or {})[recipe.key] or 0) > 0
|
|
local kept = ((protected or {})[recipe.key] or 0) > 0
|
|
if needed and not recipe.enabled then table.insert(result.enable, recipe.key) end
|
|
if not needed and not kept and recipe.enabled and recipe.byChain then table.insert(result.disable, recipe.key) end
|
|
end
|
|
table.sort(result.enable); table.sort(result.disable)
|
|
return result
|
|
end
|
|
|
|
local SUPPLIED = {production = true, husbandry = true, field = true}
|
|
|
|
function ADChainActions.edges(chain)
|
|
local list, seen = {}, {}
|
|
local function walk(nodes, rootKey)
|
|
for _, node in ipairs(nodes or {}) do
|
|
local id = tostring(node.consumer) .. "|" .. tostring(node.fillType)
|
|
if SUPPLIED[node.source] and node.consumer ~= nil and not seen[id] then
|
|
seen[id] = true
|
|
table.insert(list, {fillType = node.fillType, consumer = node.consumer, consumerName = node.consumerName, rootKey = rootKey})
|
|
end
|
|
walk(node.children, rootKey)
|
|
end
|
|
end
|
|
for _, root in ipairs((chain or {}).roots or {}) do walk(root.children, root.key) end
|
|
return list
|
|
end
|
|
|
|
local function contains(list, value)
|
|
for _, item in ipairs(list or {}) do if item == value then return true end end
|
|
return false
|
|
end
|
|
|
|
function ADChainActions.isCovered(edge, runs)
|
|
for _, run in ipairs(runs or {}) do
|
|
if run.kind == "supply" and contains(run.targetBuildingIds, edge.consumer)
|
|
and (run.ingredientMode ~= "manual" or contains(run.ingredients, edge.fillType)) then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function ADChainActions.missingFlows(edges, runs)
|
|
local list = {}
|
|
for _, edge in ipairs(edges or {}) do
|
|
if not ADChainActions.isCovered(edge, runs) then table.insert(list, edge) end
|
|
end
|
|
return list
|
|
end
|
|
|
|
function ADChainActions.flowsToStop(runs, activeRootKeys)
|
|
local list = {}
|
|
for _, run in ipairs(runs or {}) do
|
|
if run.chain ~= nil and run.chain ~= "" and not run.stopped and not (activeRootKeys or {})[run.chain] then
|
|
table.insert(list, run)
|
|
end
|
|
end
|
|
return list
|
|
end
|
|
|
|
-- ---- ét kædeflow pr. bygning (in-game 30/9: ét flow pr. vare og bygning gav mange stoppede flows) ----
|
|
|
|
-- Manglende kanter samlet pr. modtagerbygning: {consumer, consumerName, rootKey, fillTypes} i fundet rækkefølge.
|
|
function ADChainActions.groupMissing(missing)
|
|
local groups, byConsumer = {}, {}
|
|
for _, edge in ipairs(missing or {}) do
|
|
local group = byConsumer[edge.consumer]
|
|
if group == nil then
|
|
group = {consumer = edge.consumer, consumerName = edge.consumerName, rootKey = edge.rootKey, fillTypes = {}}
|
|
byConsumer[edge.consumer] = group
|
|
table.insert(groups, group)
|
|
end
|
|
if not contains(group.fillTypes, edge.fillType) then table.insert(group.fillTypes, edge.fillType) end
|
|
end
|
|
return groups
|
|
end
|
|
|
|
local function isChainRun(run)
|
|
return run.chain ~= nil and run.chain ~= "" and run.kind == "supply" and run.ingredientMode == "manual"
|
|
end
|
|
|
|
-- Kædens eget flow (manuelle varer) til bygningen -> run-id, så nye varer lægges i det i stedet for et nyt flow.
|
|
function ADChainActions.chainRunFor(runs, consumer)
|
|
for _, run in ipairs(runs or {}) do
|
|
if isChainRun(run) and contains(run.targetBuildingIds, consumer) then return run.id end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- Flere tomme kædeflows (uden traktorer) til samme bygning: det første beholdes med alle varerne, resten slettes.
|
|
-- -> {{keepId, add = {varer}, deleteIds = {id}}}
|
|
function ADChainActions.mergeIdle(runs)
|
|
local byConsumer, order = {}, {}
|
|
for _, run in ipairs(runs or {}) do
|
|
local target = (run.targetBuildingIds or {})[1]
|
|
if isChainRun(run) and target ~= nil and #(run.targetBuildingIds or {}) == 1 and #(run.vehicleIds or {}) == 0 then
|
|
if byConsumer[target] == nil then byConsumer[target] = {}; table.insert(order, target) end
|
|
table.insert(byConsumer[target], run)
|
|
end
|
|
end
|
|
local merges = {}
|
|
for _, target in ipairs(order) do
|
|
local list = byConsumer[target]
|
|
if #list > 1 then
|
|
local keep, add, deleteIds = list[1], {}, {}
|
|
for index = 2, #list do
|
|
for _, name in ipairs(list[index].ingredients or {}) do
|
|
if not contains(keep.ingredients, name) and not contains(add, name) then table.insert(add, name) end
|
|
end
|
|
table.insert(deleteIds, list[index].id)
|
|
end
|
|
table.insert(merges, {keepId = keep.id, add = add, deleteIds = deleteIds})
|
|
end
|
|
end
|
|
return merges
|
|
end
|
|
|
|
-- Varer gården selv bruger: stalde æder dem, en tændt produktion bruger dem, gården har forbrug af dem, eller et
|
|
-- flow (ikke udkørsel) kører dem. -> {[vare] = true}. Den slags sælges aldrig straks (in-game 30/9: TMR og roesnitter).
|
|
function ADChainActions.farmUses(data, runs)
|
|
local uses = {}
|
|
for name in pairs((data or {}).barnFood or {}) do uses[name] = true end
|
|
for name, rate in pairs((data or {}).rates or {}) do
|
|
if (rate.consumption or 0) > 0 then uses[name] = true end
|
|
end
|
|
for _, recipe in ipairs((data or {}).recipes or {}) do
|
|
if recipe.enabled then
|
|
for name in pairs(recipe.inputs or {}) do uses[name] = true end
|
|
end
|
|
end
|
|
for _, run in ipairs(runs or {}) do
|
|
if run.kind ~= "outbound" and run.ingredientMode == "manual" then
|
|
for _, name in ipairs(run.ingredients or {}) do uses[name] = true end
|
|
end
|
|
end
|
|
return uses
|
|
end
|
|
|
|
-- Slutprodukter der skal sælges straks: aktive rødders udgange, som ikke selv er en kant i kæden (mellemvare) og
|
|
-- som gården ikke selv bruger (farmUses). keep = {[rodnøgle] = true} for rødder sat til "Behold". -> {{key, fillType}}
|
|
function ADChainActions.finalSales(chain, recipes, edges, keep, farmUses)
|
|
local intermediate, byKey, list = {}, {}, {}
|
|
for _, edge in ipairs(edges or {}) do intermediate[edge.fillType] = true end
|
|
for _, recipe in ipairs(recipes or {}) do byKey[recipe.key] = recipe end
|
|
for _, root in ipairs((chain or {}).roots or {}) do
|
|
local recipe = byKey[root.key]
|
|
if recipe ~= nil and not (keep or {})[root.key] then
|
|
local names = {}
|
|
for name in pairs(recipe.outputs or {}) do table.insert(names, name) end
|
|
table.sort(names)
|
|
for _, name in ipairs(names) do
|
|
if not intermediate[name] and not (farmUses or {})[name] then table.insert(list, {key = root.key, fillType = name}) end
|
|
end
|
|
end
|
|
end
|
|
return list
|
|
end
|