diff --git a/FS25_ADSmartPickup/adChain.lua b/FS25_ADSmartPickup/adChain.lua
index 2fdbaec..e91f581 100644
--- a/FS25_ADSmartPickup/adChain.lua
+++ b/FS25_ADSmartPickup/adChain.lua
@@ -290,11 +290,11 @@ end
local function plan(data, state)
local recipes = ADChain.modelRecipes(data.recipes, state.paused, state.userOff)
- local chain = ADChainModel.build(recipes, data.husbandry, data.crops)
+ local chain = ADChainModel.build(recipes, data.husbandry, data.crops, data.fieldGoods)
-- pausede rødder: det de bruger, er beskyttet mod slukning (modellen regnet som om de ikke var pauset)
local protected = {}
if next(state.paused) ~= nil then
- protected = ADChainModel.build(ADChain.modelRecipes(data.recipes, {}, state.userOff), data.husbandry, data.crops).needRecipes
+ protected = ADChainModel.build(ADChain.modelRecipes(data.recipes, {}, state.userOff), data.husbandry, data.crops, data.fieldGoods).needRecipes
end
local used = ADChain.unionFruits(data.usedFruits, chain.fieldDemand)
-- ufuldstændig markliste: udbuddet ville være undervurderet -> ingen mangler, forslag eller markskift endnu
diff --git a/FS25_ADSmartPickup/adChainData.lua b/FS25_ADSmartPickup/adChainData.lua
index 981aa1f..bba9b5e 100644
--- a/FS25_ADSmartPickup/adChainData.lua
+++ b/FS25_ADSmartPickup/adChainData.lua
@@ -197,6 +197,76 @@ local function readCrops(data, nameOf)
end
end
+-- ---- markvarer (hø, hakkelse, halm …) ----
+-- Varer der høstes/laves på marken uden at være en afgrødes hovedvare. Spillets konvertere hedder forskelligt
+-- mellem versioner/kort (FORAGEHARVESTER/FORAGE_HARVESTER), så alle navne prøves; et ukendt navn giver nil.
+ADChainData.FIELD_CONVERTERS = {"FORAGEHARVESTER", "FORAGE_HARVESTER", "MOWER", "COMBINE", "CUTTER"}
+-- Kendte markvarer (basisspil, FermentingSiloPack, Dakota); kun dem der findes som fill type bruges.
+ADChainData.KNOWN_FIELD_GOODS = {"STRAW", "CHAFF", "CROP_WINDROW", "GRASS_WINDROW", "ALFALFA_WINDROW", "CLOVER_WINDROW",
+ "DRYGRASS_WINDROW", "DRYALFALFA_WINDROW", "DRYCLOVER_WINDROW", "CCM", "CCMRAW", "WCS"}
+
+-- fruit.windrowFillType kan være et indeks eller en fill type-beskrivelse
+local function windrowIndex(fruit)
+ local windrow = fruit.windrowFillType
+ if type(windrow) == "number" then return windrow end
+ if type(windrow) == "table" then
+ if windrow.index ~= nil then return windrow.index end
+ if windrow.name ~= nil and g_fillTypeManager.getFillTypeIndexByName ~= nil then
+ return g_fillTypeManager:getFillTypeIndexByName(windrow.name)
+ end
+ end
+ return nil
+end
+
+-- Én konverters mål-indekser ({[fra] = {targetFillTypeIndex|fillTypeIndex}}, samme form som adFields.buildMowable)
+local function converterTargets(converter, add)
+ for _, entry in pairs(converter or {}) do
+ if type(entry) == "table" then add(entry.targetFillTypeIndex or entry.fillTypeIndex) end
+ end
+end
+
+-- data.fieldGoods = {[navn] = true}. Kun eksisterende fill types; fejl logges én gang og gør ikke læsningen delvis
+-- (en ændret spil-API må ikke blokere kæden for altid) — værst tænkeligt meldes en markvare som "køb".
+local function readFieldGoods(data, nameOf)
+ local indices = {}
+ local function add(index) if type(index) == "number" then indices[index] = true end end
+ local function guarded(key, fn)
+ local ok, err = pcall(fn)
+ if not ok then ADChainData.warnOnce("fieldGoods:" .. key, "markvarer (%s) kunne ikke læses: %s", key, tostring(err)) end
+ end
+ if g_fillTypeManager == nil then return end
+ local fruitManager = g_fruitTypeManager
+ for _, fruit in ipairs(fruitManager ~= nil and fruitManager.fruitTypes or {}) do
+ guarded("windrow:" .. tostring(fruit.name), function() add(windrowIndex(fruit)) end)
+ end
+ if fruitManager ~= nil and fruitManager.getConverterDataByName ~= nil then
+ for _, name in ipairs(ADChainData.FIELD_CONVERTERS) do
+ guarded(name, function() converterTargets(fruitManager:getConverterDataByName(name), add) end)
+ end
+ end
+ if g_fillTypeManager.getFillTypeIndexByName ~= nil then
+ for _, name in ipairs(ADChainData.KNOWN_FIELD_GOODS) do
+ guarded(name, function() add(g_fillTypeManager:getFillTypeIndexByName(name)) end)
+ end
+ end
+ -- tørrede varianter (vender: græs-vindue -> hø)
+ if g_fillTypeManager.getConverterDataByName ~= nil then
+ guarded("TEDDER", function()
+ local tedder = g_fillTypeManager:getConverterDataByName("TEDDER") or {}
+ local windrows = {}
+ for index in pairs(indices) do table.insert(windrows, index) end
+ for _, index in ipairs(windrows) do
+ local entry = tedder[index]
+ if type(entry) == "table" then add(entry.targetFillTypeIndex or entry.fillTypeIndex) end
+ end
+ end)
+ end
+ for index in pairs(indices) do
+ local ok, name = pcall(nameOf, index)
+ if ok and name ~= nil and data.crops[name] == nil then data.fieldGoods[name] = true end
+ end
+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
@@ -369,11 +439,12 @@ end
-- 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 = {}, placeables = {}, barnFood = {}, stockByFill = {}, rates = {}}
+ usedFruits = {}, points = {}, fillTitles = {}, fillIndex = {}, placeables = {}, barnFood = {}, stockByFill = {}, rates = {}, fieldGoods = {}}
local nameOf = nameResolver(data)
data.priceOf = priceResolver(data)
readPlaceables(data, farmId, byChain, nameOf)
readCrops(data, nameOf)
+ readFieldGoods(data, nameOf)
readStock(data, adEnv, farmId, nameOf)
readRates(data, adEnv, farmId, nameOf)
readUsedFruits(data, adEnv, farmId, nameOf)
diff --git a/FS25_ADSmartPickup/adChainModel.lua b/FS25_ADSmartPickup/adChainModel.lua
index cb9c0c3..9a07c9e 100644
--- a/FS25_ADSmartPickup/adChainModel.lua
+++ b/FS25_ADSmartPickup/adChainModel.lua
@@ -47,7 +47,9 @@ local function sortedNames(map)
return names
end
-function ADChainModel.build(recipes, husbandry, crops)
+-- fieldGoods = {[vare] = true}: varer der høstes/laves på marken uden at være en afgrødes hovedvare (hø, hakkelse,
+-- halm …). Uden producent/stald er kilden "field" uden afgrøde: intet markbehov og intet problem.
+function ADChainModel.build(recipes, husbandry, crops, fieldGoods)
local chain = {roots = {}, demand = {}, fieldDemand = {}, needRecipes = {}, problems = {}}
local producers, herds = indexProducers(recipes), indexHerds(husbandry)
-- Rødderne kører for sig selv med fuld fart: deres egne input kræves af deres eget træ. Som leverandør til en
@@ -136,6 +138,11 @@ function ADChainModel.build(recipes, husbandry, crops)
chain.fieldDemand[node.fruit] = (chain.fieldDemand[node.fruit] or 0) + rest
rest = 0
end
+ -- c2) markvare uden egen afgrøde (fx hø, hakkelse): kommer fra markerne, ingen afgrødeplan
+ if rest > 1e-9 and #node.producers == 0 and #node.herds == 0 and fieldGoods ~= nil and fieldGoods[name] then
+ node.source, node.fruit = "field", nil
+ rest = 0
+ end
-- d) ingen kilde (eller rest efter stald), eller exhausted producers
if rest > 1e-9 and makers ~= nil and #node.producers == 0 and #node.herds == 0 then
node.source = "production"
diff --git a/FS25_ADSmartPickup/adChainView.lua b/FS25_ADSmartPickup/adChainView.lua
index 3c7d1b2..cc99382 100644
--- a/FS25_ADSmartPickup/adChainView.lua
+++ b/FS25_ADSmartPickup/adChainView.lua
@@ -22,7 +22,7 @@ ADChainView.TIGHT_MONTHS = 3
-- nøgler rækkerne bruger (til l10n-testen)
ADChainView.TEXT_KEYS = {"spu_chain_empty", "spu_chain_approve", "spu_chain_dismiss", "spu_chain_auto",
"spu_chain_flowOk", "spu_chain_flowMissing", "spu_chain_flowPallet", "spu_chain_flowNone", "spu_chain_flowStopped", "spu_chain_bottleneck",
- "spu_chain_buy", "spu_chain_cycle", "spu_chain_fieldShort", "spu_chain_tight", "spu_chain_noField", "spu_chain_buySource",
+ "spu_chain_buy", "spu_chain_cycle", "spu_chain_fieldShort", "spu_chain_tight", "spu_chain_noField", "spu_chain_buySource", "spu_chain_fromFields",
"spu_chain_pause", "spu_chain_resume", "spu_chain_scanning", "spu_chain_rootOk", "spu_chain_rootError", "spu_chain_rootWaiting",
"spu_chain_rootPaused", "spu_chain_rootSummary", "spu_chain_free", "spu_chain_switches", "spu_chain_gone", "spu_chain_col_item",
"spu_chain_col_source", "spu_chain_col_perMonth", "spu_chain_col_status", "spu_chain_col_stock",
@@ -94,7 +94,14 @@ end
local function stockOf(last, fruit)
local stock = last.data ~= nil and last.data.stock or nil
- return stock ~= nil and stock[fruit] or nil
+ return stock ~= nil and fruit ~= nil and stock[fruit] or nil
+end
+
+-- Lager for en mark-node: afgrødens lager, eller varens eget lager for en markvare uden afgrøde (hø, hakkelse …).
+local function fieldStockOf(last, node)
+ if node.fruit ~= nil then return stockOf(last, node.fruit) end
+ local byFill = last.data ~= nil and last.data.stockByFill or nil
+ return byFill ~= nil and byFill[node.fillType] or nil
end
-- Mark-afgrøde uden mangel men med lager under TIGHT_MONTHS måneders behov.
@@ -187,6 +194,8 @@ local function sourceText(node, last, textOf)
elseif node.source == "husbandry" then
for _, herd in ipairs(node.herds or {}) do table.insert(names, tostring(herd.buildingName)) end
elseif node.source == "field" then
+ -- markvare uden egen afgrøde (hø, hakkelse …): ingen afgrødeplan, bare "fra marker"
+ if node.fruit == nil then return textOf("spu_chain_fromFields") end
for _, field in ipairs(last.fields or {}) do
if plannedFruit(field) == node.fruit then table.insert(names, "F" .. tostring(field.id)) end
end
@@ -294,7 +303,7 @@ local function rootRows(rows, root, last, ctx, isExpanded)
end
eachNode(root.children, function(node, depth)
local text, nodeLevel = nodeStatus(node, last, ctx.fmt, ctx.textOf, ctx.short)
- local stock = node.source == "field" and stockOf(last, node.fruit) or nil
+ local stock = node.source == "field" and fieldStockOf(last, node) or nil
local row = makeRow("node", depth, nodeLevel, {string.rep(ADChainView.INDENT, depth) .. ctx.titleOf(node.fillType),
sourceText(node, last, ctx.textOf), ctx.fmt(node.perMonth or 0), text, stock ~= nil and ctx.fmt(stock) or ""})
row.fillType = node.fillType
diff --git a/FS25_ADSmartPickup/l10n/l10n_da.xml b/FS25_ADSmartPickup/l10n/l10n_da.xml
index c0af30f..7304767 100644
--- a/FS25_ADSmartPickup/l10n/l10n_da.xml
+++ b/FS25_ADSmartPickup/l10n/l10n_da.xml
@@ -598,6 +598,7 @@
+
diff --git a/FS25_ADSmartPickup/l10n/l10n_en.xml b/FS25_ADSmartPickup/l10n/l10n_en.xml
index 9b0e6f9..0963905 100644
--- a/FS25_ADSmartPickup/l10n/l10n_en.xml
+++ b/FS25_ADSmartPickup/l10n/l10n_en.xml
@@ -598,6 +598,7 @@
+