feat(kæde): advarsel når en fabrik gården er afhængig af slukkes
Slukker spilleren en produktion, hvis vare et tændt flow kører (manuel vare eller målet tager den i auto), en stald æder eller en aktiv kæde bruger, kommer én besked pr. slukning med brugere og lagerdage, og en rød post 'Slukket men nødvendig' i Kræver handling og statusvinduet så længe den er slukket og nødvendig. Ingen advarsel når en anden tændt produktion dækker, lageret rækker over 60 dage, kæden selv slukkede den eller den var slukket ved indlæsning. Tjekket kører i kædens tick også uden kæder; ren logik i adDependency.lua.
This commit is contained in:
+1
-1
@@ -8,7 +8,7 @@ står i [docs/BRUGERMANUAL.md](docs/BRUGERMANUAL.md) (dansk) og [docs/USER_MANUA
|
||||
|
||||
## 1.61 — Produktionskæder
|
||||
|
||||
- **1.61.0** Produktionskæder: slå et produkt til i en fabrik, og moden holder det kørende helt tilbage til marken. Kæden regner baglæns gennem dine egne fabrikker og stalde til afgrøderne og ser 12 måneder frem. Ny fane **Kæder** med træ pr. rod-produktion, farvet status, fold ud/ind og **[Pause]**/**[Start]**. Marker markeret **Fri til kæden** skifter afgrøde automatisk (højst 2 i minuttet); andre marker får forslag med **[Godkend]**/**[Afvis]** (højst 3 pr. afgrøde) i fanen og som ét samlet punkt i **Kræver handling**. En afgrøde, du selv har valgt, ændres aldrig. Mellemled tændes og slukkes kun igen, hvis kæden tændte dem. Flows **Kæde: <vare> → <bygning>** oprettes med en ledig pool-traktor og tipvogn (ellers stoppet: *mangler traktor/vogn*; paller altid stoppet) og stoppes, ikke slettes, når kæden slås fra. Dine egne tændte produktioner bruges som kilde først; slukker du en produktion, tænder kæden den ikke igen, før du tænder en ny. Stoppede kædeflows slippes af kæden. Ingen handlinger de første 2 minutter, ingen markskift før alle marker er scannet, og intet slukkes ved delvise læsefejl. Begrænsninger: intet køb, ingen dyrekøb, flerårige afgrøder og græsmarker skiftes aldrig, grundudbytte uden gødningsbonus. **Vigtigt:** hver produktion, du tænder i en fabrik, prøver moden at forsyne — tænd kun det, du vil have produceret; sluk produktionen eller tryk [Pause] for at stoppe kæden. Manglende led forklares i klart sprog med råd (*Ingen af dine fabrikker laver Mel — byg en eller køb*, *Mølle kan kun lave 800 af 1.0k/md*, *Dine stalde leverer ikke nok Mælk …*, *… er slukket af dig*, *Kredsløb omkring …*): som rød tekst under varen i fanen Kæder, som én rød linje pr. kæde i **Kræver handling** (højst 2; klik åbner kæden foldet ud) og som engangsbesked med kædens navn foran, når et nyt led mangler (ikke i opstartsfristen eller mens markerne scannes). Nyt **statusvindue** på skærmen (i stil med Simple Inspector), som slås til/fra med **venstre Alt + S** (kan ændres under Styring; virker til fods og i køretøjer): øverst til højre under info-boksen vises flow-traktorernes handling og fyld, markarbejde i gang, kæder med manglende led og advarsler (køretøjer der har stået stille over 2 min, ventende kædeforslag) — højst 18 linjer, opdateres hvert sekund, skjules ved menu/dialog, skjult HUD og søvn; tændt/slukket gemmes pr. bruger i `modSettings/FS25_ADSmartPickup/status.xml`. Manual og ordliste opdateret.
|
||||
- **1.61.0** Produktionskæder: slå et produkt til i en fabrik, og moden holder det kørende helt tilbage til marken. Kæden regner baglæns gennem dine egne fabrikker og stalde til afgrøderne og ser 12 måneder frem. Ny fane **Kæder** med træ pr. rod-produktion, farvet status, fold ud/ind og **[Pause]**/**[Start]**. Marker markeret **Fri til kæden** skifter afgrøde automatisk (højst 2 i minuttet); andre marker får forslag med **[Godkend]**/**[Afvis]** (højst 3 pr. afgrøde) i fanen og som ét samlet punkt i **Kræver handling**. En afgrøde, du selv har valgt, ændres aldrig. Mellemled tændes og slukkes kun igen, hvis kæden tændte dem. Flows **Kæde: <vare> → <bygning>** oprettes med en ledig pool-traktor og tipvogn (ellers stoppet: *mangler traktor/vogn*; paller altid stoppet) og stoppes, ikke slettes, når kæden slås fra. Dine egne tændte produktioner bruges som kilde først; slukker du en produktion, tænder kæden den ikke igen, før du tænder en ny. Stoppede kædeflows slippes af kæden. Ingen handlinger de første 2 minutter, ingen markskift før alle marker er scannet, og intet slukkes ved delvise læsefejl. Begrænsninger: intet køb, ingen dyrekøb, flerårige afgrøder og græsmarker skiftes aldrig, grundudbytte uden gødningsbonus. **Vigtigt:** hver produktion, du tænder i en fabrik, prøver moden at forsyne — tænd kun det, du vil have produceret; sluk produktionen eller tryk [Pause] for at stoppe kæden. Manglende led forklares i klart sprog med råd (*Ingen af dine fabrikker laver Mel — byg en eller køb*, *Mølle kan kun lave 800 af 1.0k/md*, *Dine stalde leverer ikke nok Mælk …*, *… er slukket af dig*, *Kredsløb omkring …*): som rød tekst under varen i fanen Kæder, som én rød linje pr. kæde i **Kræver handling** (højst 2; klik åbner kæden foldet ud) og som engangsbesked med kædens navn foran, når et nyt led mangler (ikke i opstartsfristen eller mens markerne scannes). Nyt **statusvindue** på skærmen (i stil med Simple Inspector), som slås til/fra med **venstre Alt + S** (kan ændres under Styring; virker til fods og i køretøjer): øverst til højre under info-boksen vises flow-traktorernes handling og fyld, markarbejde i gang, kæder med manglende led og advarsler (slukkede nødvendige fabrikker, køretøjer der har stået stille over 2 min, ventende kædeforslag) — højst 18 linjer, opdateres hvert sekund, skjules ved menu/dialog, skjult HUD og søvn; tændt/slukket gemmes pr. bruger i `modSettings/FS25_ADSmartPickup/status.xml`. **Advarsel når en nødvendig fabrik slukkes** (også uden kæder): slukker du en produktion, hvis vare et tændt flow kører (valgt vare eller målet tager den i auto), en stald æder eller en aktiv kæde bruger, kommer én besked pr. slukning (*Advarsel: du slukkede Fermenteringssilo 3 (Ensilage) — Cow Food, Goat Food +1 bruger det. Lageret rækker ca. 12 dage.*) og en rød linje *Slukket men nødvendig: …* i **Kræver handling** (højst 2; klik åbner fanen Fabrikker, eller Kæder hvis kun en kæde bruger varen) og i statusvinduet, så længe den er slukket og nødvendig. Ingen advarsel når en anden tændt produktion dækker med nok kapacitet, lageret rækker over 60 dage, kæden selv slukkede den, eller den allerede var slukket ved indlæsning; produktioner ingen bruger, advarer aldrig. Manual og ordliste opdateret.
|
||||
|
||||
## 1.60 — "Kræver handling" → flow, menuplacering, flow-vogne i guiden
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
-- AD Chain (kæde-kørsel)
|
||||
-- Hvert minut (efter opstartsfristen): læs gården (ADChainData), byg kæden (ADChainModel), find manglende
|
||||
-- afgrøder (ADCropPlan) og lad ADChainRun skifte frie marker, tænde/slukke mellemled og oprette/stoppe flows.
|
||||
-- Samme tick advarer (ADDependency), når spilleren slukker en produktion gården er afhængig af — også uden kæder.
|
||||
-- Resultatet gemmes i ADChain.last til Kæder-fanen. Tilstanden (byChain, pausede rødder, afviste forslag,
|
||||
-- userOff og det sidst kendte sæt af rødder) gemmes i ADSmartPickup_chain.xml under spillets gem.
|
||||
-- Spiladgang kun inde i funktioner (filen dofile's i test).
|
||||
@@ -31,6 +32,9 @@ ADChain.timer = 0
|
||||
ADChain.collectFailed = false
|
||||
-- {[rodnøgle|vare|art] = true}: manglende led der allerede er meldt som besked (kun i hukommelsen; nulstilles ved indlæsning)
|
||||
ADChain.problemKeys = {}
|
||||
-- {[nøgle] = true}: produktioner (ikke kædens) der var tændt ved sidste afhængighedstjek (kun kædens tick, kun på
|
||||
-- hele data). nil efter indlæsning: det der allerede er slukket ved første tjek, advares der ikke om.
|
||||
ADChain.depPrevEnabled = nil
|
||||
|
||||
local function contains(list, value)
|
||||
for _, item in ipairs(list or {}) do if item == value then return true end end
|
||||
@@ -320,6 +324,30 @@ local function applyReconcile(state, data)
|
||||
ADChain.afterLoad = false
|
||||
end
|
||||
|
||||
-- Afhængighedstjek (spec afsnit 8): nye slukninger (kun act) og "Slukket men nødvendig"-posterne. Uafhængigt af
|
||||
-- kædens rødder og af markscanningen; springes over ved læsefejl (så beholdes forrige poster, og slukninger i
|
||||
-- mellemtiden meldes ved næste hele tjek).
|
||||
-- Produktioner kæden selv er ved at tænde (plan.prod.enable), er ikke "slukket men nødvendig".
|
||||
local function dependencyCheck(data, plan, runs, act, previous)
|
||||
if ADDependency == nil or ADChainData.dependencyInputs == nil then return nil end
|
||||
if data.readFailed then
|
||||
return previous ~= nil and {warnings = {}, offNeeded = previous.offNeeded or {}} or nil
|
||||
end
|
||||
local inputs = ADChainData.dependencyInputs(data, plan.chain, runs)
|
||||
local enabling, recipes = {}, {}
|
||||
for _, key in ipairs(plan.prod ~= nil and plan.prod.enable or {}) do enabling[key] = true end
|
||||
for _, recipe in ipairs(data.recipes or {}) do
|
||||
if not enabling[recipe.key] then table.insert(recipes, recipe) end
|
||||
end
|
||||
local prev = act and ADChain.depPrevEnabled or nil
|
||||
local result = {
|
||||
warnings = ADDependency.warnings(prev, recipes, inputs.needed, inputs.stockDays, inputs.capacity, inputs.demand),
|
||||
offNeeded = ADDependency.offNeeded(recipes, inputs.needed, inputs.stockDays, inputs.capacity, inputs.demand),
|
||||
}
|
||||
if act then ADChain.depPrevEnabled = ADDependency.enabledKeys(data.recipes) end
|
||||
return result
|
||||
end
|
||||
|
||||
-- act = true: udfør handlingerne (tick). Uden act kun en frisk visning (GUI).
|
||||
function ADChain.evaluate(adEnv, act)
|
||||
local state = ADChain.state
|
||||
@@ -341,11 +369,17 @@ function ADChain.evaluate(adEnv, act)
|
||||
end
|
||||
if act and ADChainRun ~= nil then ADChainRun.apply(adEnv, data, result) end
|
||||
local runs = ADChain.runsView(ADRunsController.store.runs)
|
||||
local okDep, dependency = pcall(dependencyCheck, data, result, runs, act, ADChain.last ~= nil and ADChain.last.dependency or nil)
|
||||
if not okDep then
|
||||
Logging.warning(ADChain.LOG_PREFIX .. "afhængighedstjek fejlede: %s", tostring(dependency))
|
||||
dependency = nil
|
||||
end
|
||||
local paused = {}
|
||||
for key in pairs(state.paused) do paused[key] = true end
|
||||
ADChain.last = {chain = result.chain, shortages = result.shortages, actions = result.actions, edges = result.edges,
|
||||
missingFlows = ADChainActions.missingFlows(result.edges, runs), flowStatus = ADChain.flowStatus(result.edges, runs, ADChain.noVehicle),
|
||||
paused = paused, userOff = copySet(state.userOff), data = data, fields = data.fields, fieldsIncomplete = data.fieldsIncomplete == true, titles = data.fillTitles, at = ADChain.now, switchCount = ADChain.switchCount}
|
||||
paused = paused, userOff = copySet(state.userOff), data = data, fields = data.fields, fieldsIncomplete = data.fieldsIncomplete == true, titles = data.fillTitles, at = ADChain.now, switchCount = ADChain.switchCount,
|
||||
dependency = dependency}
|
||||
return ADChain.last
|
||||
end
|
||||
|
||||
@@ -378,6 +412,23 @@ function ADChain.notifyProblems(last)
|
||||
return #fresh
|
||||
end
|
||||
|
||||
-- Én besked pr. slukning af en nødvendig produktion (kun fra tick; advarslerne tømmes, når de er meldt).
|
||||
function ADChain.notifyDependencies(last)
|
||||
local dependency = last ~= nil and last.dependency or nil
|
||||
if dependency == nil or #(dependency.warnings or {}) == 0 or ADChain.now < ADChain.STARTUP_GRACE_MS then return 0 end
|
||||
local warnings = dependency.warnings
|
||||
dependency.warnings = {}
|
||||
if ADFieldJobs == nil or ADFieldJobs.notify == nil then return 0 end
|
||||
local textOf = function(key) return g_i18n ~= nil and g_i18n:getText(key) or key end
|
||||
local titleOf = function(name) return tostring((last.titles or {})[name] or name) end
|
||||
for _, warning in ipairs(warnings) do
|
||||
local text = ADDependency.notifyText(warning, textOf, titleOf)
|
||||
Logging.info(ADChain.LOG_PREFIX .. "nødvendig produktion slukket: %s", text)
|
||||
ADFieldJobs.notify(text, true)
|
||||
end
|
||||
return #warnings
|
||||
end
|
||||
|
||||
function ADChain.tick(adEnv, dt)
|
||||
if adEnv == nil then return end
|
||||
ADChain.now = ADChain.now + (dt or 0)
|
||||
@@ -387,6 +438,8 @@ function ADChain.tick(adEnv, dt)
|
||||
local last = ADChain.evaluate(adEnv, true)
|
||||
local ok, err = pcall(ADChain.notifyProblems, last)
|
||||
if not ok then Logging.warning(ADChain.LOG_PREFIX .. "besked om manglende led fejlede: %s", tostring(err)) end
|
||||
local okDep, errDep = pcall(ADChain.notifyDependencies, last)
|
||||
if not okDep then Logging.warning(ADChain.LOG_PREFIX .. "advarsel om slukket produktion fejlede: %s", tostring(errDep)) end
|
||||
end
|
||||
|
||||
-- ---- GUI-handlinger ----
|
||||
@@ -482,6 +535,7 @@ function ADChain.load()
|
||||
ADChain.noVehicle = {}
|
||||
ADChain.prevEnabled, ADChain.afterLoad = nil, true
|
||||
ADChain.problemKeys = {}
|
||||
ADChain.depPrevEnabled = nil
|
||||
local path = getPath()
|
||||
if path == nil or not fileExists(path) then return end
|
||||
local xmlFile = XMLFile.load("ADSmartPickupChain", path)
|
||||
|
||||
@@ -32,8 +32,9 @@ end
|
||||
|
||||
-- En læsefejl i dette kald: data.partial = true (også når advarslen allerede er logget), så kæden ikke
|
||||
-- slukker eller stopper noget på et ufuldstændigt billede af gården.
|
||||
-- data.readFailed skelner en ægte læsefejl fra en ufærdig markscanning (afhængighedstjekket bruger ikke markerne).
|
||||
local function failed(data, key, fmt, ...)
|
||||
data.partial = true
|
||||
data.partial, data.readFailed = true, true
|
||||
ADChainData.warnOnce(key, fmt, ...)
|
||||
end
|
||||
|
||||
@@ -118,11 +119,27 @@ local function readHerd(placeable, nameOf)
|
||||
return {building = uid, buildingName = placeableName(placeable, uid), outputs = outputs}
|
||||
end
|
||||
|
||||
-- Stald-foder: {[vare] = {staldnavn...}} for det truget æder nu (forbrug > 0) — til afhængighedstjekket.
|
||||
local function readBarnFood(data, placeable, nameOf)
|
||||
if ADSources.getHusbandryConsumption == nil then return end
|
||||
local barnName
|
||||
for index, perDay in pairs(ADSources.getHusbandryConsumption(placeable) or {}) do
|
||||
local name = nameOf(index)
|
||||
if name ~= nil and (perDay or 0) > 0 then
|
||||
barnName = barnName or placeableName(placeable, placeableId(placeable) or "?")
|
||||
data.barnFood[name] = data.barnFood[name] or {}
|
||||
table.insert(data.barnFood[name], barnName)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function readPlaceables(data, farmId, byChain, nameOf)
|
||||
local placeables = g_currentMission ~= nil and g_currentMission.placeableSystem ~= nil and g_currentMission.placeableSystem.placeables or {}
|
||||
for index, placeable in pairs(placeables) do
|
||||
local ok, err = pcall(function()
|
||||
if not ADPrices.isOwnedBy(placeable, farmId) then return end
|
||||
local uid = placeableId(placeable)
|
||||
if uid ~= nil then data.placeables[uid] = placeable end
|
||||
local point = placeable.spec_productionPoint ~= nil and placeable.spec_productionPoint.productionPoint or nil
|
||||
if point ~= nil then
|
||||
local recipes, points = readFactory(placeable, point, byChain, nameOf)
|
||||
@@ -131,6 +148,7 @@ local function readPlaceables(data, farmId, byChain, nameOf)
|
||||
elseif placeable.spec_husbandry ~= nil or placeable.getHusbandryFillLevel ~= nil then
|
||||
local herd = readHerd(placeable, nameOf)
|
||||
if herd ~= nil then table.insert(data.husbandry, herd) end
|
||||
readBarnFood(data, placeable, nameOf)
|
||||
end
|
||||
end)
|
||||
if not ok then
|
||||
@@ -182,13 +200,30 @@ end
|
||||
local function readStock(data, adEnv, farmId, nameOf)
|
||||
local ok, err = pcall(function()
|
||||
for index, liters in pairs(ADStorageStats.farmTotals(ADSources.getFarmInventory(adEnv, farmId))) do
|
||||
local fruit = data.crops[nameOf(index) or ""]
|
||||
local name = nameOf(index)
|
||||
if name ~= nil then data.stockByFill[name] = (data.stockByFill[name] or 0) + liters end
|
||||
local fruit = data.crops[name or ""]
|
||||
if fruit ~= nil then data.stock[fruit] = (data.stock[fruit] or 0) + liters end
|
||||
end
|
||||
end)
|
||||
if not ok then failed(data, "stock", "lager kunne ikke læses: %s", tostring(err)) end
|
||||
end
|
||||
|
||||
-- Gårdens forbrug og produktion pr. døgn (fabrikker der kører + stalde) pr. varenavn og spillets tidsfaktor
|
||||
-- (rå rater pr. måned × faktor = pr. døgn) — til lagerdage og dækning i afhængighedstjekket.
|
||||
local function readRates(data, adEnv, farmId, nameOf)
|
||||
local environment = g_currentMission ~= nil and g_currentMission.environment or nil
|
||||
local adjustment = environment ~= nil and tonumber(environment.timeAdjustment) or nil
|
||||
data.timeAdjustment = adjustment ~= nil and adjustment > 0 and adjustment or 1
|
||||
local ok, err = pcall(function()
|
||||
for index, rate in pairs(ADSources.getFarmRates(adEnv, farmId, false) or {}) do
|
||||
local name = nameOf(index)
|
||||
if name ~= nil then data.rates[name] = {consumption = rate.consumption or 0, production = rate.production or 0} end
|
||||
end
|
||||
end)
|
||||
if not ok then failed(data, "allRates", "gårdens forbrug kunne ikke læses: %s", tostring(err)) end
|
||||
end
|
||||
|
||||
-- Afgrøder gården selv bruger: input i en tændt produktion eller foder/halm i en stald (kun staldenes forbrug
|
||||
-- læses: feedOnly springer fabrikkernes rater over — dem dækker opskrifterne allerede).
|
||||
local function readUsedFruits(data, adEnv, farmId, nameOf)
|
||||
@@ -231,19 +266,107 @@ local function readFields(data)
|
||||
end
|
||||
end
|
||||
|
||||
-- ---- afhængighedstjek (spec afsnit 8) ----
|
||||
|
||||
local function unloadStationsOf(placeable)
|
||||
local storage = g_currentMission ~= nil and g_currentMission.storageSystem or nil
|
||||
local result = {}
|
||||
if storage == nil or storage.getUnloadingStations == nil then return result end
|
||||
for _, station in pairs(storage:getUnloadingStations() or {}) do
|
||||
if station.owningPlaceable == placeable then table.insert(result, station) end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Hvad auto-flowenes mål tager af varerne `goods` (navne): {[bygnings-id] = {[vare] = true}}.
|
||||
-- Kun tændte forsyningsflows i auto-tilstand; hvert mål slås op én gang.
|
||||
function ADChainData.acceptsMap(data, flows, goods)
|
||||
local result = {}
|
||||
for _, flow in ipairs(flows or {}) do
|
||||
if flow.kind ~= "outbound" and not flow.stopped and flow.ingredientMode ~= "manual" then
|
||||
for _, id in ipairs(flow.targetBuildingIds or {}) do
|
||||
local placeable = data.placeables[id]
|
||||
if result[id] == nil and placeable ~= nil then
|
||||
result[id] = {}
|
||||
local ok, err = pcall(function()
|
||||
local stations = unloadStationsOf(placeable)
|
||||
for _, name in ipairs(goods) do
|
||||
local index = data.fillIndex[name]
|
||||
for _, station in ipairs(stations) do
|
||||
if index ~= nil and ADSources.stationAccepts(station, index) then result[id][name] = true; break end
|
||||
end
|
||||
end
|
||||
end)
|
||||
if not ok then ADChainData.warnOnce("accepts:" .. tostring(id), "mål %s kunne ikke læses: %s", tostring(id), tostring(err)) end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Kædens input-varer (alle varer i de aktive kæders træer) -> {[vare] = {kædenavn...}}
|
||||
function ADChainData.chainInputs(chain, titles)
|
||||
local result = {}
|
||||
local function walk(nodes, rootTitle)
|
||||
for _, node in ipairs(nodes or {}) do
|
||||
result[node.fillType] = result[node.fillType] or {}
|
||||
local list = result[node.fillType]
|
||||
if list[#list] ~= rootTitle then table.insert(list, rootTitle) end
|
||||
walk(node.children, rootTitle)
|
||||
end
|
||||
end
|
||||
for _, root in ipairs(chain ~= nil and chain.roots or {}) do
|
||||
walk(root.children, tostring((titles or {})[root.name] or root.name))
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Alt afhængighedstjekket regner på, i liter pr. døgn: {needed, stockDays, capacity, demand}.
|
||||
-- flows = ADChain.runsView(...); chain = kædemodellen (kan være uden rødder).
|
||||
function ADChainData.dependencyInputs(data, chain, flows)
|
||||
local goods, seen = {}, {}
|
||||
for _, recipe in ipairs(data.recipes or {}) do
|
||||
if not recipe.enabled and not recipe.byChain then
|
||||
for name in pairs(recipe.outputs or {}) do
|
||||
if not seen[name] then seen[name] = true; table.insert(goods, name) end
|
||||
end
|
||||
end
|
||||
end
|
||||
table.sort(goods)
|
||||
local needed = ADDependency.neededOutputs(flows, data.barnFood, ADChainData.chainInputs(chain, data.fillTitles),
|
||||
#goods > 0 and ADChainData.acceptsMap(data, flows, goods) 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
|
||||
for _, name in ipairs(goods) do
|
||||
local rate = (data.rates or {})[name] or {}
|
||||
local consumption, production = rate.consumption or 0, rate.production or 0
|
||||
local chainDemand = ((chain ~= nil and chain.demand or {})[name] or 0) * adjustment
|
||||
demand[name] = math.max(consumption, chainDemand)
|
||||
if consumption > production then
|
||||
stockDays[name] = ((data.stockByFill or {})[name] or 0) / (consumption - production)
|
||||
elseif consumption > 0 then
|
||||
stockDays[name] = math.huge
|
||||
end
|
||||
end
|
||||
return {needed = needed, stockDays = stockDays, capacity = capacity, demand = demand}
|
||||
end
|
||||
|
||||
-- ---- samlet ----
|
||||
|
||||
-- byChain = {[recipeKey] = true} for produktioner kæden selv har tændt (ikke rødder).
|
||||
-- data.partial = true når noget ikke kunne læses i dette kald; data.fieldsIncomplete = true mens markscanningen
|
||||
-- data.partial = true når noget ikke kunne læses i dette kald (data.readFailed) eller markscanningen kører; data.fieldsIncomplete = true mens markscanningen
|
||||
-- ikke har nået alle marker.
|
||||
function ADChainData.collect(adEnv, farmId, byChain)
|
||||
local data = {recipes = {}, husbandry = {}, crops = {}, stock = {}, fields = {}, yields = {}, fruitFillIndex = {},
|
||||
usedFruits = {}, points = {}, fillTitles = {}, fillIndex = {}}
|
||||
usedFruits = {}, points = {}, fillTitles = {}, fillIndex = {}, placeables = {}, barnFood = {}, stockByFill = {}, rates = {}}
|
||||
local nameOf = nameResolver(data)
|
||||
data.priceOf = priceResolver(data)
|
||||
readPlaceables(data, farmId, byChain, nameOf)
|
||||
readCrops(data, nameOf)
|
||||
readStock(data, adEnv, farmId, nameOf)
|
||||
readRates(data, adEnv, farmId, nameOf)
|
||||
readUsedFruits(data, adEnv, farmId, nameOf)
|
||||
readFields(data)
|
||||
return data
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
-- AD Dependency (ren logik)
|
||||
-- Advarsel når spilleren slukker en produktion gården er afhængig af (spec 2026-09-30-produktionskaeder afsnit 8).
|
||||
-- En vare er "nødvendig" når et tændt forsyningsflow kører den (manuel vare, eller flowets mål tager den i
|
||||
-- auto-tilstand), en stald æder den, eller en aktiv kæde har den som input. Varer er NAVNE; kapacitet og forbrug
|
||||
-- i samme enhed (adapteren i adChain.lua vælger), lagerdage i spillets døgn. Ingen spiladgang.
|
||||
|
||||
ADDependency = {}
|
||||
ADDependency.STOCK_DAYS_OK = 60 -- lager til mere end så mange døgn: ingen advarsel
|
||||
ADDependency.MAX_USERS = 2 -- brugere nævnt i beskeden; resten "+k"
|
||||
|
||||
local function contains(list, value)
|
||||
for _, item in ipairs(list or {}) do if item == value then return true end end
|
||||
return false
|
||||
end
|
||||
|
||||
local function sortedKeys(map)
|
||||
local keys = {}
|
||||
for key in pairs(map or {}) do table.insert(keys, key) end
|
||||
table.sort(keys)
|
||||
return keys
|
||||
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)
|
||||
function ADDependency.neededOutputs(flows, barnFood, chainInputs, accepts)
|
||||
local result = {}
|
||||
local function add(name, user, isChain)
|
||||
if name == nil or user == nil then return end
|
||||
local entry = result[name]
|
||||
if entry == nil then
|
||||
entry = {users = {}, onlyChain = true}
|
||||
result[name] = entry
|
||||
end
|
||||
if not isChain then entry.onlyChain = false 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
|
||||
else
|
||||
for _, building in ipairs(flow.targetBuildingIds or {}) do
|
||||
for _, name in ipairs(sortedKeys((accepts or {})[building])) do add(name, user, false) end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, name in ipairs(sortedKeys(barnFood)) do
|
||||
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
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Tændte produktioner der ikke er kædens (samme regel som ADChain.enabledKeys) -> {[nøgle] = true}
|
||||
function ADDependency.enabledKeys(recipes)
|
||||
local result = {}
|
||||
for _, recipe in ipairs(recipes or {}) do
|
||||
if recipe.enabled and not recipe.byChain then result[recipe.key] = true end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Tændte produktioners kapacitet pr. vare (outputs × cyklusser pr. måned) -> {[vare] = mængde}
|
||||
function ADDependency.capacity(recipes)
|
||||
local result = {}
|
||||
for _, recipe in ipairs(recipes or {}) do
|
||||
if recipe.enabled then
|
||||
for name, amount in pairs(recipe.outputs or {}) do
|
||||
result[name] = (result[name] or 0) + (amount or 0) * (recipe.cyclesPerMonth or 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Dækker andre tændte produktioner varen? Ukendt/intet forbrug: enhver kapacitet dækker.
|
||||
local function isCovered(name, otherCapacity, demand)
|
||||
local capacity = (otherCapacity or {})[name] or 0
|
||||
return capacity > 0 and capacity >= ((demand or {})[name] or 0)
|
||||
end
|
||||
|
||||
-- Rækker lageret længe nok? nil = ukendt (advar, uden dage).
|
||||
local function stockLasts(name, stockDays)
|
||||
local days = (stockDays or {})[name]
|
||||
return days ~= nil and days > ADDependency.STOCK_DAYS_OK
|
||||
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)
|
||||
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
|
||||
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}
|
||||
end
|
||||
end
|
||||
return nil
|
||||
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 = {}, {}
|
||||
for _, recipe in ipairs(recipes or {}) do
|
||||
local warning = check(recipe, needed, stockDays, otherCapacity, demand)
|
||||
if warning ~= nil and not seen[tostring(warning.building)] then
|
||||
seen[tostring(warning.building)] = true
|
||||
table.insert(result, warning)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- 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
|
||||
for _, recipe in ipairs(recipes or {}) do
|
||||
if prevEnabled[recipe.key] then
|
||||
local warning = check(recipe, needed, stockDays, otherCapacity, demand)
|
||||
local id = warning ~= nil and (tostring(warning.building) .. "|" .. warning.fillType) or nil
|
||||
if warning ~= nil and not seen[id] then
|
||||
seen[id] = true
|
||||
table.insert(result, warning)
|
||||
end
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- "A, B +2"
|
||||
function ADDependency.usersText(users)
|
||||
local shown = {}
|
||||
for index = 1, math.min(#(users or {}), ADDependency.MAX_USERS) do shown[index] = tostring(users[index]) end
|
||||
if #shown == 0 then return "?" end
|
||||
local text = table.concat(shown, ", ")
|
||||
if #users > #shown then text = text .. " +" .. tostring(#users - #shown) end
|
||||
return text
|
||||
end
|
||||
|
||||
-- Beskedtekst (spu_dep_warn med dage, spu_dep_warnNoDays uden).
|
||||
function ADDependency.notifyText(warning, textOf, titleOf)
|
||||
local title = tostring(titleOf ~= nil and titleOf(warning.fillType) or warning.fillType)
|
||||
local users = ADDependency.usersText(warning.users)
|
||||
local building = tostring(warning.buildingName or warning.building or "?")
|
||||
local days = warning.days
|
||||
if days ~= nil and days < math.huge then
|
||||
return string.format(textOf("spu_dep_warn"), building, title, users, math.max(0, math.floor(days)))
|
||||
end
|
||||
return string.format(textOf("spu_dep_warnNoDays"), building, title, users)
|
||||
end
|
||||
@@ -963,6 +963,18 @@ function ADSources.getFarmRates(adEnv, farmId, feedOnly)
|
||||
return rates
|
||||
end
|
||||
|
||||
-- Én stalds forbrug (foder efter trugets indhold, halm, vand): {[fillType] = liter} kun for consumption > 0.
|
||||
-- Rå rate uden timeAdjustment (som getHusbandryOutputs).
|
||||
function ADSources.getHusbandryConsumption(placeable)
|
||||
local rates, result = {}, {}
|
||||
if placeable == nil then return result end
|
||||
pcall(addHusbandryRates, rates, placeable)
|
||||
for fillType, rate in pairs(rates) do
|
||||
if (rate.consumption or 0) > 0 then result[fillType] = rate.consumption end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Én stalds produktion (mælk, gødning, ...): {[fillType] = liter} kun for production > 0. Spillets rå rate
|
||||
-- (pr. måned = én 24-timers dag) UDEN timeAdjustment — samme enhed som fabrikkernes cyklusser pr. måned i kæden.
|
||||
function ADSources.getHusbandryOutputs(placeable)
|
||||
|
||||
@@ -168,10 +168,11 @@ function ADStatusHud.fieldEntries(proxy)
|
||||
return entries
|
||||
end
|
||||
|
||||
-- Kæder med manglende led + ventende forslag (samme punkter og tekster som "Kræver handling").
|
||||
-- Kæder med manglende led + ventende forslag + slukkede nødvendige fabrikker (samme punkter og tekster som
|
||||
-- "Kræver handling"; de to sidste står under Advarsler).
|
||||
function ADStatusHud.chainEntries(proxy)
|
||||
local chains, suggestions = {}, {}
|
||||
local result = {chains = chains, suggestions = suggestions}
|
||||
local result = {chains = chains, suggestions = suggestions, dependencies = {}}
|
||||
if ADChain == nil or ADChain.last == nil or ADStorageStats == nil or ADStorageStats.chainEntries == nil or proxy == nil then
|
||||
return result
|
||||
end
|
||||
@@ -180,6 +181,8 @@ function ADStatusHud.chainEntries(proxy)
|
||||
table.insert(chains, {text = proxy:alertText(entry), level = "error"})
|
||||
elseif entry.kind == "chainSuggest" then
|
||||
table.insert(suggestions, {text = proxy:alertText(entry), level = "waiting"})
|
||||
elseif entry.kind == "dependencyOff" then
|
||||
table.insert(result.dependencies, {text = proxy:alertText(entry), level = "error"})
|
||||
end
|
||||
end
|
||||
return result
|
||||
@@ -212,6 +215,7 @@ function ADStatusHud.snapshot(adEnv)
|
||||
snapshot.fields = guarded("fields", ADStatusHud.fieldEntries, proxy) or {}
|
||||
local chainResult = guarded("chains", ADStatusHud.chainEntries, proxy) or {}
|
||||
snapshot.chains = chainResult.chains or {}
|
||||
for _, entry in ipairs(chainResult.dependencies or {}) do table.insert(snapshot.warnings, entry) end
|
||||
for _, entry in ipairs(guarded("stuck", ADStatusHud.stuckEntries) or {}) do table.insert(snapshot.warnings, entry) end
|
||||
for _, entry in ipairs(chainResult.suggestions or {}) do table.insert(snapshot.warnings, entry) end
|
||||
return snapshot
|
||||
|
||||
@@ -336,9 +336,36 @@ local function chainProblemEntries(last)
|
||||
return result
|
||||
end
|
||||
|
||||
-- "Slukket men nødvendig" (ADChain.last.dependency.offNeeded): én rød post pr. fabrik, højst MAX_DEPENDENCY_ENTRIES
|
||||
-- (den sidste får more = antal skjulte). Score DEPENDENCY_SCORE + hast (0-99, færre lagerdage = højere; ukendt = 50):
|
||||
-- over manglende led (3500-3599), under "rød tom" (3900-4000).
|
||||
ADStorageStats.DEPENDENCY_SCORE = 3700
|
||||
ADStorageStats.MAX_DEPENDENCY_ENTRIES = 2
|
||||
|
||||
local function urgency(days)
|
||||
if days == nil then return 50 end
|
||||
if days == math.huge then return 0 end
|
||||
return math.max(0, 99 - math.min(99, math.floor(days)))
|
||||
end
|
||||
|
||||
function ADStorageStats.dependencyEntries(last)
|
||||
local entries = {}
|
||||
for _, item in ipairs(last ~= nil and last.dependency ~= nil and last.dependency.offNeeded or {}) do
|
||||
local name = tostring(item.buildingName or item.building or "?")
|
||||
table.insert(entries, {kind = "dependencyOff", level = "red", score = ADStorageStats.DEPENDENCY_SCORE + urgency(item.days),
|
||||
building = item.building, buildingName = name, fillType = item.fillType, onlyChain = item.onlyChain == true, text = name})
|
||||
end
|
||||
entries = ADStorageStats.rankAttention(entries)
|
||||
local result = {}
|
||||
for index = 1, math.min(#entries, ADStorageStats.MAX_DEPENDENCY_ENTRIES) do result[index] = entries[index] end
|
||||
if #entries > #result then result[#result].more = #entries - #result end
|
||||
return result
|
||||
end
|
||||
|
||||
function ADStorageStats.chainEntries(last)
|
||||
if last == nil then return {} end
|
||||
local result = chainProblemEntries(last)
|
||||
for _, entry in ipairs(ADStorageStats.dependencyEntries(last)) do table.insert(result, entry) end
|
||||
local count = 0
|
||||
for _, action in ipairs(last.actions or {}) do
|
||||
if action.mode == "suggest" then count = count + 1 end
|
||||
|
||||
@@ -4,6 +4,14 @@
|
||||
-- siges det at et flow ikke hjælper (producér/køb). Afgørelsen er ADStorageStats.flowAdvice (testet).
|
||||
-- Funktionerne lægges på SmartPickupFrame (indlæses efter SmartPickupFrame.lua).
|
||||
|
||||
-- Lagerfanen for en bygningstype (TAB_KINDS), fx "factory" -> fanen Fabrikker.
|
||||
function SmartPickupFrame.tabOfKind(kind)
|
||||
for tab, tabKind in pairs(SmartPickupFrame.TAB_KINDS or {}) do
|
||||
if tabKind == kind then return tab end
|
||||
end
|
||||
return SmartPickupFrame.TAB_OVERVIEW
|
||||
end
|
||||
|
||||
local function fillTypeName(fillType)
|
||||
return g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(fillType) or tostring(fillType)
|
||||
end
|
||||
@@ -64,6 +72,8 @@ end
|
||||
function SmartPickupFrame:attentionAdvice(entry)
|
||||
-- kæde-forslag og manglende led har ingen vare (stat): klik fører til fanen Kæder
|
||||
if entry ~= nil and (entry.kind == "chainSuggest" or entry.kind == "chainProblem") then return "chain", nil end
|
||||
-- slukket men nødvendig: fanen Fabrikker (Kæder når kun en kæde bruger varen)
|
||||
if entry ~= nil and entry.kind == "dependencyOff" then return entry.onlyChain and "chain" or "factories", nil end
|
||||
if entry ~= nil and entry.kind == "sell" and entry.stat ~= nil then return sellAdviceFor(entry.stat) end
|
||||
if entry == nil or entry.kind ~= "empty" or entry.stat == nil then return "none", nil end
|
||||
local stat = entry.stat
|
||||
@@ -86,6 +96,7 @@ end
|
||||
|
||||
function SmartPickupFrame:attentionHint(advice, info)
|
||||
if advice == "chain" then return self.i18n:getText("spu_attention_hintChain") end
|
||||
if advice == "factories" then return self.i18n:getText("spu_attention_hintFactories") end
|
||||
if advice == "open" then return string.format(self.i18n:getText("spu_attention_hintOpen"), tostring(info.run.name)) end
|
||||
if advice == "flow" then return self.i18n:getText(info.sell and "spu_attention_hintSellFlow" or "spu_attention_hintFlow") end
|
||||
if advice == "produce" then return self.i18n:getText("spu_attention_hintProduce") end
|
||||
@@ -103,6 +114,10 @@ function SmartPickupFrame:onAttentionClick(entry)
|
||||
frame:switchTab(SmartPickupFrame.TAB_CHAINS)
|
||||
return
|
||||
end
|
||||
if entry ~= nil and entry.kind == "dependencyOff" then
|
||||
frame:switchTab(entry.onlyChain and SmartPickupFrame.TAB_CHAINS or SmartPickupFrame.tabOfKind("factory"))
|
||||
return
|
||||
end
|
||||
local adEnv = frame.getAdEnv()
|
||||
local advice, info = frame:attentionAdvice(entry)
|
||||
if adEnv == nil or advice == "none" then return end
|
||||
|
||||
@@ -183,10 +183,15 @@ function SmartPickupFrame:addKpiRow(stats)
|
||||
return row
|
||||
end
|
||||
|
||||
-- Varepunkterne + kædens punkter (røde manglende led, højst 2, og ét samlet punkt for afgrødeforslag; ADChain.last,
|
||||
-- ingen evaluering her), samme loft MAX_ATTENTION.
|
||||
-- Varepunkterne + kædens punkter (røde manglende led, højst 2, røde "Slukket men nødvendig", højst 2, og ét samlet
|
||||
-- punkt for afgrødeforslag), samme loft MAX_ATTENTION. ADChain.last genbruges; er det ældre end CHAIN_MAX_AGE_MS,
|
||||
-- evalueres der (visning, handler ikke), så en slukket nødvendig fabrik ses straks.
|
||||
function SmartPickupFrame:attentionFor(stats)
|
||||
local attention = ADStorageStats.attentionList(stats, SmartPickupFrame.MAX_ATTENTION)
|
||||
if ADChain ~= nil and ADChain.evaluate ~= nil and self.chainLast ~= nil and self.getAdEnv ~= nil then
|
||||
local okEnv, adEnv = pcall(self.getAdEnv)
|
||||
if okEnv and adEnv ~= nil then pcall(self.chainLast, self, adEnv) end
|
||||
end
|
||||
if ADChain == nil or ADChain.last == nil then return attention end
|
||||
return ADStorageStats.mergeAttention(attention, ADStorageStats.chainEntries(ADChain.last), SmartPickupFrame.MAX_ATTENTION)
|
||||
end
|
||||
@@ -201,6 +206,11 @@ function SmartPickupFrame:alertText(entry)
|
||||
if (entry.more or 0) > 0 then text = text .. string.format(" (+%d)", entry.more) end
|
||||
return text
|
||||
end
|
||||
if entry.kind == "dependencyOff" then
|
||||
local text = string.format(i18n:getText("spu_attention_depOff"), tostring(entry.buildingName))
|
||||
if (entry.more or 0) > 0 then text = text .. string.format(" (+%d)", entry.more) end
|
||||
return text
|
||||
end
|
||||
if entry.kind == "empty" then
|
||||
return string.format(i18n:getText("spu_alert_empty"), stat.title, self:formatDays(stat.days), fc(stat.farmLevel or 0), fc(math.abs(stat.net or 0)))
|
||||
elseif entry.kind == "full" then
|
||||
|
||||
@@ -632,5 +632,9 @@
|
||||
<text name="spu_status_act_emptying" text="tømmer vognen"/>
|
||||
<text name="spu_status_act_homing" text="på vej hjem"/>
|
||||
<text name="spu_status_stuck" text="%s står stille (%d min)"/>
|
||||
<text name="spu_dep_warn" text="Advarsel: du slukkede %s (%s) — %s bruger det. Lageret rækker ca. %d dage."/>
|
||||
<text name="spu_dep_warnNoDays" text="Advarsel: du slukkede %s (%s) — %s bruger det."/>
|
||||
<text name="spu_attention_depOff" text="Slukket men nødvendig: %s"/>
|
||||
<text name="spu_attention_hintFactories" text=" → klik: se Fabrikker"/>
|
||||
</texts>
|
||||
</l10n>
|
||||
|
||||
@@ -632,5 +632,9 @@
|
||||
<text name="spu_status_act_emptying" text="emptying the wagon"/>
|
||||
<text name="spu_status_act_homing" text="heading home"/>
|
||||
<text name="spu_status_stuck" text="%s standing still (%d min)"/>
|
||||
<text name="spu_dep_warn" text="Warning: you switched off %s (%s) — %s uses it. Stock lasts about %d days."/>
|
||||
<text name="spu_dep_warnNoDays" text="Warning: you switched off %s (%s) — %s uses it."/>
|
||||
<text name="spu_attention_depOff" text="Switched off but needed: %s"/>
|
||||
<text name="spu_attention_hintFactories" text=" → click: see Factories"/>
|
||||
</texts>
|
||||
</l10n>
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
<sourceFile filename="adChainModel.lua"/>
|
||||
<sourceFile filename="adCropPlan.lua"/>
|
||||
<sourceFile filename="adChainActions.lua"/>
|
||||
<sourceFile filename="adDependency.lua"/>
|
||||
<sourceFile filename="adChainData.lua"/>
|
||||
<sourceFile filename="adChain.lua"/>
|
||||
<sourceFile filename="adChainRun.lua"/>
|
||||
|
||||
+32
-2
@@ -344,8 +344,9 @@ spillets info-boks. Tasten virker både til fods og i et køretøj og kan ændre
|
||||
grå = stoppet.
|
||||
- **Marker** — én linje pr. mark med markarbejde i gang: *F92 Høstes · Roeoptager · 45 %* (farve som i Marker-fanen).
|
||||
- **Kæder** — kun kæder med et manglende led: *Brød mangler et led: Mel*.
|
||||
- **Advarsler** — køretøjer der har stået stille i over 2 minutter (uden at Smart Pickup selv holder dem ved
|
||||
Wait/udkørsel) og ventende kædeforslag (*Kæde: 2 forslag*).
|
||||
- **Advarsler** — fabrikker gården er afhængig af, men som er slukket (*Slukket men nødvendig: Fermenteringssilo 3*,
|
||||
se [Advarsel når en nødvendig fabrik slukkes](#advarsel-når-en-nødvendig-fabrik-slukkes)), køretøjer der har
|
||||
stået stille i over 2 minutter (uden at Smart Pickup selv holder dem ved Wait/udkørsel) og ventende kædeforslag (*Kæde: 2 forslag*).
|
||||
|
||||
Højst 18 linjer; resten samles i *+k mere*. Vinduet skjules, mens en menu eller dialog er åben, når HUD'en er
|
||||
skjult, og når du sover. Om vinduet er tændt, gemmes pr. bruger i
|
||||
@@ -687,6 +688,33 @@ Beskederne:
|
||||
- *Mølle (Mel) er slukket af dig — tænd den eller sæt kæden på pause*: du har selv slukket produktionen.
|
||||
- *Kredsløb omkring Mel — kæden kan ikke beregnes*: varen bruges til at lave sig selv.
|
||||
|
||||
#### Advarsel når en nødvendig fabrik slukkes
|
||||
|
||||
Slukker du en produktion, som gården er afhængig af, advarer moden dig — også når ingen kæde er i gang. En
|
||||
produktion er nødvendig, når en af dens varer bruges af gården:
|
||||
|
||||
- et tændt forsyningsflow kører varen (valgt som vare, eller flowets mål tager varen i auto),
|
||||
- en stald æder varen lige nu, eller
|
||||
- en aktiv kæde har varen som input.
|
||||
|
||||
Eksempel: du slukker fermenteringssiloerne, men flowene *Cow Food*, *Goat Food* og *Biogas Silage* henter
|
||||
ensilage. Så kommer beskeden *Advarsel: du slukkede Fermenteringssilo 3 (Ensilage) — Cow Food, Goat Food +1
|
||||
bruger det. Lageret rækker ca. 12 dage.* (dagene ud fra gårdens lager og forbrug; kendes de ikke, udelades
|
||||
de). Beskeden kommer én gang pr. slukning, højst et minut efter.
|
||||
|
||||
Så længe produktionen er slukket og stadig nødvendig, står der en rød linje i **Kræver handling**:
|
||||
*Slukket men nødvendig: Fermenteringssilo 3* (højst 2; også i statusvinduet under Advarsler). Et klik åbner
|
||||
lagerfanen **Fabrikker** — eller **Kæder**, hvis kun en kæde bruger varen.
|
||||
|
||||
Der advares ikke, når:
|
||||
|
||||
- en anden tændt produktion laver varen med nok kapacitet,
|
||||
- gården har lager til mere end 60 dage,
|
||||
- kæden selv slukkede produktionen, eller
|
||||
- produktionen allerede var slukket, da spillet blev indlæst (så vises kun linjen i Kræver handling).
|
||||
|
||||
Produktioner, som ingen flows, stalde eller kæder bruger (fx et bageri uden flow), giver aldrig en advarsel.
|
||||
|
||||
#### Markér en mark fri til kæden
|
||||
|
||||
Åbn marken i markguiden og slå **Fri til kæden (moden må skifte afgrøde)** til. Kun sådan en mark skifter
|
||||
@@ -794,6 +822,7 @@ ens. Øverst vælger du **Vis: Varer | Bygninger**. Fanen husker valget. Tallene
|
||||
| *Hvede løber tør om … — gården har …, bruger …/døgn* | Gården bruger mere, end den producerer, og varen rækker under 3 døgn (rød under 1 døgn) |
|
||||
| *Mælk er 92 % fuld — fuld om …* | En produceret vare er mindst 85 % fuld (rød fra 95 %) |
|
||||
| *Sælg Raps nu: prisen er 94 % af årets top — …* | Prisen er mindst 90 % af årets top, beholdningen er værd mindst 10.000, og gården bruger den ikke op |
|
||||
| *Slukket men nødvendig: Fermenteringssilo 3* | Du har slukket en produktion, som et flow, en stald eller en kæde bruger (se [Advarsel når en nødvendig fabrik slukkes](#advarsel-når-en-nødvendig-fabrik-slukkes)); klik åbner fanen Fabrikker |
|
||||
|
||||
**Klik på en linje** for at handle:
|
||||
|
||||
@@ -1280,4 +1309,5 @@ Moden testes løbende, og fejlrapporter er meget velkomne.
|
||||
| **Marksilo** | En silo ved en mark, der bruges som mellemlager |
|
||||
| **Kæde** | Den samlede vej fra en produktion tilbage gennem fabrikker og stalde til afgrøderne på markerne |
|
||||
| **Rod-produktion** | Den produktion, du selv slår til, og som kæden holder kørende |
|
||||
| **Slukket men nødvendig** | En slukket produktion, hvis vare et flow, en stald eller en kæde bruger — moden advarer én gang og viser en rød linje i Kræver handling |
|
||||
| **Fri til kæden** | Markering på en mark, der lader moden skifte afgrøde automatisk |
|
||||
|
||||
+32
-2
@@ -349,8 +349,9 @@ that have something in them:
|
||||
- **Fields** — one line per field with field work in progress: *F92 Harvesting · Beet harvester · 45 %*
|
||||
(colours as in the Fields tab).
|
||||
- **Chains** — only chains with a missing link: *Bread is missing a link: Flour*.
|
||||
- **Warnings** — vehicles that have stood still for more than 2 minutes (without Smart Pickup holding them at
|
||||
Wait/outbound) and pending chain suggestions (*Chain: 2 suggestions*).
|
||||
- **Warnings** — factories the farm depends on that are switched off (*Switched off but needed: Fermenting
|
||||
silo 3*, see [Warning when a needed factory is switched off](#warning-when-a-needed-factory-is-switched-off)),
|
||||
vehicles that have stood still for more than 2 minutes (without Smart Pickup holding them at Wait/outbound) and pending chain suggestions (*Chain: 2 suggestions*).
|
||||
|
||||
At most 18 lines; the rest is summed up as *+k more*. The window is hidden while a menu or dialog is open,
|
||||
when the HUD is hidden and while you sleep. Whether it is on is saved per user in
|
||||
@@ -703,6 +704,33 @@ The messages:
|
||||
- *Mill (Flour) was turned off by you — turn it on or pause the chain*: you switched the production off yourself.
|
||||
- *Loop around Flour — the chain cannot be calculated*: the goods are needed to make themselves.
|
||||
|
||||
#### Warning when a needed factory is switched off
|
||||
|
||||
If you switch off a production the farm depends on, the mod warns you — also when no chain is running. A
|
||||
production is needed when one of its goods is used by the farm:
|
||||
|
||||
- a running supply flow carries the goods (chosen as goods, or the flow's target takes the goods in auto),
|
||||
- a barn is eating the goods right now, or
|
||||
- an active chain has the goods as input.
|
||||
|
||||
Example: you switch off the fermenting silos, but the flows *Cow Food*, *Goat Food* and *Biogas Silage* fetch
|
||||
silage. You then get the message *Warning: you switched off Fermenting silo 3 (Silage) — Cow Food, Goat Food
|
||||
+1 uses it. Stock lasts about 12 days.* (days from the farm's stock and consumption; left out when unknown).
|
||||
The message comes once per switch-off, at most a minute later.
|
||||
|
||||
As long as the production is off and still needed, **Needs attention** shows a red line: *Switched off but
|
||||
needed: Fermenting silo 3* (at most 2; also in the status window under Warnings). Clicking opens the storage
|
||||
tab **Factories** — or **Chains** if only a chain uses the goods.
|
||||
|
||||
No warning when:
|
||||
|
||||
- another running production makes the goods with enough capacity,
|
||||
- the farm has stock for more than 60 days,
|
||||
- the chain switched the production off itself, or
|
||||
- the production was already off when the game was loaded (then only the Needs attention line is shown).
|
||||
|
||||
Productions that no flow, barn or chain uses (for example a bakery without a flow) never give a warning.
|
||||
|
||||
#### Mark a field free for chains
|
||||
|
||||
Open the field in the field guide and switch on **Free for chains (mod may change the crop)**. Only such a
|
||||
@@ -814,6 +842,7 @@ every second.
|
||||
| *Wheat runs out in … — farm has …, uses …/day* | The farm uses more than it produces, and the good lasts less than 3 days (red below 1 day) |
|
||||
| *Milk is 92 % full — full in …* | A produced good is at least 85 % full (red from 95 %) |
|
||||
| *Sell Canola now: price is 94 % of the yearly top — …* | The price is at least 90 % of the yearly top, the stock is worth at least 10,000, and the farm does not use it up |
|
||||
| *Switched off but needed: Fermenting silo 3* | You switched off a production that a flow, a barn or a chain uses (see [Warning when a needed factory is switched off](#warning-when-a-needed-factory-is-switched-off)); clicking opens the Factories tab |
|
||||
|
||||
**Click a line** to act on it:
|
||||
|
||||
@@ -1317,4 +1346,5 @@ The mod is being tested continuously, and bug reports are very welcome.
|
||||
| **Field silo** | A silo near a field used as intermediate storage |
|
||||
| **Chain** | The whole path from a production back through factories and barns to the crops in the fields |
|
||||
| **Root production** | The production you switch on yourself, which the chain keeps running |
|
||||
| **Switched off but needed** | A switched-off production whose goods a flow, a barn or a chain uses — the mod warns once and shows a red line in Needs attention |
|
||||
| **Free for chains** | A field marking that lets the mod change the crop automatically |
|
||||
|
||||
Reference in New Issue
Block a user