fix(kæde): afhængigheds-advarsel uden støj fra auto-flows, alternative opskrifter og kæder

- Auto-flowets mål tæller kun for varer gården forbruger (eller en kæde vil
  have); stald-foder/auto-behov uden kendt forbrug er ikke nødvendigt. Manuel
  flow-vare og kæde-input gælder også uden kendte lagerdage.
- En slukket opskrift springes over, når en anden tændt opskrift i samme
  fabrik laver varen.
- Behov kun fra kæder giver ingen advarsel/post (Task 10 melder kæderne).
This commit is contained in:
2026-09-30 15:13:15 +02:00
parent 9fde03f950
commit e9f1251471
5 changed files with 66 additions and 18 deletions
+10 -1
View File
@@ -334,8 +334,17 @@ function ADChainData.dependencyInputs(data, chain, flows)
end
end
table.sort(goods)
-- auto-flowets mål tager mange varer (fx biogas: korn, ensilage, gylle): kun varer gården faktisk forbruger
-- (stald eller fabrik) eller en kæde vil have, tæller
local consumed = {}
for _, name in ipairs(goods) do
local rate = (data.rates or {})[name]
if (rate ~= nil and (rate.consumption or 0) > 0) or ((chain ~= nil and chain.demand or {})[name] or 0) > 0 then
table.insert(consumed, name)
end
end
local needed = ADDependency.neededOutputs(flows, data.barnFood, ADChainData.chainInputs(chain, data.fillTitles),
#goods > 0 and ADChainData.acceptsMap(data, flows, goods) or {})
#consumed > 0 and ADChainData.acceptsMap(data, flows, consumed) or {})
local adjustment = data.timeAdjustment or 1
local capacity, demand, stockDays = {}, {}, {}
for name, perMonth in pairs(ADDependency.capacity(data.recipes)) do capacity[name] = perMonth * adjustment end
+38 -10
View File
@@ -23,24 +23,27 @@ end
-- flows = {{name, kind, stopped, targetBuildingIds, ingredientMode, ingredients}}
-- barnFood = {[vare] = {staldnavn...}}, chainInputs = {[vare] = {kædenavn...}}
-- accepts = {[bygnings-id] = {[vare] = true}}: hvad auto-flowenes mål tager (adapteren slår op)
-- -> {[vare] = {users = {navn...}, onlyChain}} (brugere i rækkefølgen flows, stalde, kæder; hver kun én gang)
-- -> {[vare] = {users = {navn...}, onlyChain, strong}} (brugere i rækkefølgen flows, stalde, kæder; hver kun én gang).
-- strong = varen er valgt som manuel vare i et flow eller er kæde-input: behovet gælder også uden kendt forbrug.
-- Stald-foder og auto-flowenes mål er "svage": uden kendt forbrug (lagerdage) er de ikke nødvendige.
function ADDependency.neededOutputs(flows, barnFood, chainInputs, accepts)
local result = {}
local function add(name, user, isChain)
local function add(name, user, isChain, isStrong)
if name == nil or user == nil then return end
local entry = result[name]
if entry == nil then
entry = {users = {}, onlyChain = true}
entry = {users = {}, onlyChain = true, strong = false}
result[name] = entry
end
if not isChain then entry.onlyChain = false end
if isStrong then entry.strong = true end
if not contains(entry.users, user) then table.insert(entry.users, user) end
end
for _, flow in ipairs(flows or {}) do
if flow.kind ~= "outbound" and not flow.stopped then
local user = tostring(flow.name or "?")
if flow.ingredientMode == "manual" then
for _, name in ipairs(flow.ingredients or {}) do add(name, user, false) end
for _, name in ipairs(flow.ingredients or {}) do add(name, user, false, true) end
else
for _, building in ipairs(flow.targetBuildingIds or {}) do
for _, name in ipairs(sortedKeys((accepts or {})[building])) do add(name, user, false) end
@@ -52,7 +55,7 @@ function ADDependency.neededOutputs(flows, barnFood, chainInputs, accepts)
for _, barn in ipairs(barnFood[name]) do add(name, tostring(barn), false) end
end
for _, name in ipairs(sortedKeys(chainInputs)) do
for _, root in ipairs(chainInputs[name]) do add(name, tostring(root), true) end
for _, root in ipairs(chainInputs[name]) do add(name, tostring(root), true, true) end
end
return result
end
@@ -91,13 +94,34 @@ local function stockLasts(name, stockDays)
return days ~= nil and days > ADDependency.STOCK_DAYS_OK
end
-- {[bygning|vare] = true} for tændte opskrifter: spilleren har valgt hvilken opskrift i fabrikken der kører.
local function enabledInBuilding(recipes)
local result = {}
for _, recipe in ipairs(recipes or {}) do
if recipe.enabled then
for name, amount in pairs(recipe.outputs or {}) do
if (amount or 0) > 0 then result[tostring(recipe.building) .. "|" .. name] = true end
end
end
end
return result
end
-- Er behovet for varen reelt? Kun kæder: nej (Task 10 melder kæderne). Svagt behov (stald-foder, auto-flowets mål)
-- kræver kendt forbrug (lagerdage); manuel flow-vare og kæde-input gælder også uden.
local function isNeeded(need, name, stockDays)
if need == nil or need.onlyChain then return false end
return need.strong == true or (stockDays or {})[name] ~= nil
end
-- Første nødvendige, udækkede vare (efter navn) for en slukket produktion (ikke kædens) -> advarsel eller nil.
local function check(recipe, needed, stockDays, otherCapacity, demand)
local function check(recipe, needed, stockDays, otherCapacity, demand, alternatives)
if recipe.enabled or recipe.byChain then return nil end
for _, name in ipairs(sortedKeys(recipe.outputs)) do
local need = (needed or {})[name]
if need ~= nil and (recipe.outputs[name] or 0) > 0 and not isCovered(name, otherCapacity, demand)
and not stockLasts(name, stockDays) then
if isNeeded(need, name, stockDays) and (recipe.outputs[name] or 0) > 0
and not alternatives[tostring(recipe.building) .. "|" .. name]
and not isCovered(name, otherCapacity, demand) and not stockLasts(name, stockDays) then
local days = (stockDays or {})[name]
return {recipeKey = recipe.key, building = recipe.building, buildingName = recipe.buildingName, fillType = name,
users = need.users, onlyChain = need.onlyChain == true, days = days}
@@ -109,8 +133,9 @@ end
-- Alle slukkede, nødvendige produktioner (én pr. fabrik) — "Slukket men nødvendig" i Kræver handling.
function ADDependency.offNeeded(recipes, needed, stockDays, otherCapacity, demand)
local result, seen = {}, {}
local alternatives = enabledInBuilding(recipes)
for _, recipe in ipairs(recipes or {}) do
local warning = check(recipe, needed, stockDays, otherCapacity, demand)
local warning = check(recipe, needed, stockDays, otherCapacity, demand, alternatives)
if warning ~= nil and not seen[tostring(warning.building)] then
seen[tostring(warning.building)] = true
table.insert(result, warning)
@@ -119,14 +144,17 @@ function ADDependency.offNeeded(recipes, needed, stockDays, otherCapacity, deman
return result
end
-- Fælles regler (warnings og offNeeded): ingen advarsel når en anden opskrift i SAMME fabrik laver varen og er
-- tændt, når andre tændte produktioner dækker behovet, når lageret rækker > 60 dage, eller når kun kæder bruger varen.
-- Nye slukninger siden sidste evaluering: tændt i prevEnabled, slukket nu, nødvendig og ikke dækket.
-- prevEnabled = nil (første evaluering efter indlæsning) -> ingen. Én pr. fabrik og vare.
function ADDependency.warnings(prevEnabled, recipes, needed, stockDays, otherCapacity, demand)
local result, seen = {}, {}
if prevEnabled == nil then return result end
local alternatives = enabledInBuilding(recipes)
for _, recipe in ipairs(recipes or {}) do
if prevEnabled[recipe.key] then
local warning = check(recipe, needed, stockDays, otherCapacity, demand)
local warning = check(recipe, needed, stockDays, otherCapacity, demand, alternatives)
local id = warning ~= nil and (tostring(warning.building) .. "|" .. warning.fillType) or nil
if warning ~= nil and not seen[id] then
seen[id] = true