diff --git a/FS25_ADSmartPickup/adChainView.lua b/FS25_ADSmartPickup/adChainView.lua
new file mode 100644
index 0000000..6c24a41
--- /dev/null
+++ b/FS25_ADSmartPickup/adChainView.lua
@@ -0,0 +1,187 @@
+-- AD Chain View (ren logik)
+-- Rækkerne til fanen Kæder ud fra ADChain.last: rod -> noder rekursivt (kilde, behov pr. måned, flowstatus),
+-- forslag/auto-skift under afgrøden, og nederst frie marker + antal automatiske skift. Ingen spiladgang:
+-- titleOf(navn) -> visningstitel, fmt(liter) -> kompakt tal, textOf(l10n-nøgle) -> tekst gives udefra.
+-- Række: {kind="root"|"node"|"suggest"|"dismiss"|"auto"|"info"|"empty", indent, text, level, cells={c1..c5},
+-- action={kind="approve"|"dismiss"|"pause"|"resume", fieldId|rootKey}, fillType}
+
+ADChainView = {}
+ADChainView.INDENT = " "
+-- nøgler ud over spu_tab_chains/spu_chain_empty/... som rækkerne bruger (til l10n-testen)
+ADChainView.TEXT_KEYS = {"spu_chain_perMonth", "spu_chain_noField", "spu_chain_buySource", "spu_chain_cycle",
+ "spu_chain_fieldShort", "spu_chain_flowOk", "spu_chain_flowNone", "spu_chain_flowStopped", "spu_chain_approve",
+ "spu_chain_dismiss", "spu_chain_switches", "spu_chain_rootOk", "spu_chain_rootError", "spu_chain_rootWaiting",
+ "spu_chain_rootPaused"}
+
+local FLOW_KEYS = {ok = "spu_chain_flowOk", missing = "spu_chain_flowNone", stopped = "spu_chain_flowStopped", noVehicle = "spu_chain_flowMissing"}
+
+local function identity(value) return tostring(value) end
+
+local function plannedFruit(field)
+ if field.targetFruit ~= nil and field.targetFruit ~= "" then return field.targetFruit end
+ return field.fruit
+end
+
+local function haText(ha)
+ return string.format("%.0f", ha or 0)
+end
+
+local function edgeKey(node)
+ return tostring(node.consumer) .. "|" .. tostring(node.fillType)
+end
+
+local function shortageByFruit(last)
+ local result = {}
+ for _, shortage in ipairs(last.shortages or {}) do result[shortage.fruit] = shortage end
+ return result
+end
+
+-- Alle noder under roden (dybde først).
+local function eachNode(nodes, fn, depth)
+ for _, node in ipairs(nodes or {}) do
+ fn(node, depth or 1)
+ eachNode(node.children, fn, (depth or 1) + 1)
+ end
+end
+
+function ADChainView.rootLevel(root, last)
+ last = last or {}
+ if (last.paused or {})[root.key] then return "stopped" end
+ for _, problem in ipairs((last.chain or {}).problems or {}) do
+ if problem.rootKey == root.key then return "error" end
+ end
+ local short, flowStatus = shortageByFruit(last), last.flowStatus or {}
+ local hasShortage, hasWaiting = false, false
+ eachNode(root.children, function(node)
+ if node.fruit ~= nil and short[node.fruit] ~= nil then hasShortage = true end
+ if (node.shortPerMonth or 0) > 0 then hasShortage = true end
+ local status = node.consumer ~= nil and flowStatus[edgeKey(node)] or nil
+ if status ~= nil and status ~= "ok" then hasWaiting = true end
+ end)
+ if hasShortage then return "error" end
+ if hasWaiting then return "waiting" end
+ return "running"
+end
+
+-- Kilden som tekst: fabrikker / stalde / marker med planlagt afgrøde / køb.
+local function sourceText(node, last, textOf)
+ local names = {}
+ if node.source == "production" then
+ for _, producer in ipairs(node.producers or {}) do table.insert(names, tostring(producer.buildingName)) end
+ 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
+ for _, field in ipairs(last.fields or {}) do
+ if plannedFruit(field) == node.fruit then
+ table.insert(names, string.format("F%s (%s ha)", tostring(field.id), haText(field.areaHa)))
+ end
+ end
+ if #names == 0 then return textOf("spu_chain_noField") end
+ elseif node.source == "buy" then
+ return textOf("spu_chain_buySource")
+ else
+ return "-"
+ end
+ return table.concat(names, ", ")
+end
+
+-- Nodens status (tekst, niveau): mangel/flaskehals/køb/kredsløb først, ellers flowets status.
+local function nodeStatus(node, last, titleOf, fmt, textOf, short)
+ local title = titleOf(node.fillType)
+ if node.source == "cycle" then return textOf("spu_chain_cycle"), "error" end
+ if (node.shortPerMonth or 0) > 0 then
+ if node.source == "production" then
+ return string.format(textOf("spu_chain_bottleneck"), title, fmt(node.shortPerMonth)), "error"
+ end
+ return string.format(textOf("spu_chain_buy"), title, fmt(node.shortPerMonth)), "error"
+ end
+ local shortage = node.fruit ~= nil and short[node.fruit] or nil
+ if shortage ~= nil then
+ return string.format(textOf("spu_chain_fieldShort"), haText(shortage.missingHa)), "error"
+ end
+ local status = node.consumer ~= nil and (last.flowStatus or {})[edgeKey(node)] or nil
+ if status == nil then return "", "running" end
+ return textOf(FLOW_KEYS[status] or "spu_chain_flowNone"), status == "ok" and "running" or "waiting"
+end
+
+local function joinCells(cells)
+ local parts = {}
+ for _, cell in ipairs(cells) do
+ if cell ~= nil and cell ~= "" then table.insert(parts, cell) end
+ end
+ return table.concat(parts, " · ")
+end
+
+local function makeRow(kind, indent, level, cells, action)
+ return {kind = kind, indent = indent, level = level, cells = cells, action = action, text = joinCells(cells)}
+end
+
+-- Forslag (godkend + afvis) og auto-skift for afgrøden, lige under dens node.
+local function actionRows(rows, fruit, indent, last, titleOf, textOf, shown)
+ if fruit == nil or shown[fruit] then return end
+ shown[fruit] = true
+ local pad = string.rep(ADChainView.INDENT, indent)
+ for _, action in ipairs(last.actions or {}) do
+ if action.to == fruit then
+ local fromTitle = (action.from ~= nil and action.from ~= "") and titleOf(action.from) or "-"
+ if action.mode == "suggest" then
+ local text = string.format(textOf("spu_chain_suggest"), action.fieldId, fromTitle, titleOf(action.to), action.hectares or 0)
+ table.insert(rows, makeRow("suggest", indent, "waiting", {pad, "", "", text, textOf("spu_chain_approve")},
+ {kind = "approve", fieldId = action.fieldId}))
+ table.insert(rows, makeRow("dismiss", indent, "waiting", {pad, "", "", "", textOf("spu_chain_dismiss")},
+ {kind = "dismiss", fieldId = action.fieldId}))
+ else
+ local text = string.format(textOf("spu_chain_auto"), action.fieldId, titleOf(action.to))
+ table.insert(rows, makeRow("auto", indent, "running", {pad, "", "", text, ""}, nil))
+ end
+ end
+ end
+end
+
+local ROOT_STATUS = {running = "spu_chain_rootOk", error = "spu_chain_rootError", waiting = "spu_chain_rootWaiting", stopped = "spu_chain_rootPaused"}
+
+local function rootRows(rows, root, last, titleOf, fmt, textOf, short)
+ local level = ADChainView.rootLevel(root, last)
+ local paused = (last.paused or {})[root.key] == true
+ table.insert(rows, makeRow("root", 0, level, {titleOf(root.name), tostring(root.buildingName or ""), "",
+ textOf(ROOT_STATUS[level]), textOf(paused and "spu_chain_resume" or "spu_chain_pause")},
+ {kind = paused and "resume" or "pause", rootKey = root.key}))
+ local shown = {}
+ eachNode(root.children, function(node, depth)
+ local status, nodeLevel = nodeStatus(node, last, titleOf, fmt, textOf, short)
+ local row = makeRow("node", depth, nodeLevel, {string.rep(ADChainView.INDENT, depth) .. titleOf(node.fillType),
+ sourceText(node, last, textOf), string.format(textOf("spu_chain_perMonth"), fmt(node.perMonth or 0)), status, ""}, nil)
+ row.fillType = node.fillType
+ table.insert(rows, row)
+ if node.source == "field" then actionRows(rows, node.fruit, depth + 1, last, titleOf, textOf, shown) end
+ end)
+end
+
+local function footerRows(rows, last, textOf)
+ local free = {}
+ for _, field in ipairs(last.fields or {}) do
+ if field.chainFree then table.insert(free, field.id) end
+ end
+ table.sort(free)
+ local names = {}
+ for _, id in ipairs(free) do table.insert(names, "F" .. tostring(id)) end
+ local freeText = string.format(textOf("spu_chain_free"), #names > 0 and table.concat(names, ", ") or "-")
+ table.insert(rows, {kind = "info", indent = 0, text = freeText})
+ table.insert(rows, {kind = "info", indent = 0, text = string.format(textOf("spu_chain_switches"), last.switchCount or 0)})
+end
+
+function ADChainView.rows(last, titleOf, fmt, textOf)
+ textOf, fmt = textOf or identity, fmt or identity
+ local titles = last ~= nil and last.titles or {}
+ titleOf = titleOf or function(name) return (titles or {})[name] or tostring(name) end
+ local rows = {}
+ local roots = last ~= nil and last.chain ~= nil and last.chain.roots or {}
+ if #roots == 0 then
+ table.insert(rows, {kind = "empty", indent = 0, text = textOf("spu_chain_empty")})
+ end
+ if last == nil then return rows end
+ local short = shortageByFruit(last)
+ for _, root in ipairs(roots) do rootRows(rows, root, last, titleOf, fmt, textOf, short) end
+ footerRows(rows, last, textOf)
+ return rows
+end
diff --git a/FS25_ADSmartPickup/adSmartPickup.lua b/FS25_ADSmartPickup/adSmartPickup.lua
index fb27cb9..8034482 100644
--- a/FS25_ADSmartPickup/adSmartPickup.lua
+++ b/FS25_ADSmartPickup/adSmartPickup.lua
@@ -28,6 +28,7 @@ if ADSmartPickup.dir ~= nil and source ~= nil then
source(ADSmartPickup.dir .. "gui/SmartPickupFieldTab.lua")
source(ADSmartPickup.dir .. "gui/SmartPickupMonthTab.lua")
source(ADSmartPickup.dir .. "gui/SmartPickupFieldSiloTab.lua")
+ source(ADSmartPickup.dir .. "gui/SmartPickupChainTab.lua")
source(ADSmartPickup.dir .. "gui/SmartPickupGuide.lua")
source(ADSmartPickup.dir .. "gui/SmartPickupFieldGuide.lua")
source(ADSmartPickup.dir .. "gui/SmartPickupFlowGuide.lua")
diff --git a/FS25_ADSmartPickup/adStorageStats.lua b/FS25_ADSmartPickup/adStorageStats.lua
index a4fe73f..522a6c4 100644
--- a/FS25_ADSmartPickup/adStorageStats.lua
+++ b/FS25_ADSmartPickup/adStorageStats.lua
@@ -258,15 +258,51 @@ function ADStorageStats.attentionList(stats, max)
for _, stat in ipairs(stats or {}) do
for _, entry in ipairs(attentionEntries(stat)) do table.insert(list, entry) end
end
+ return ADStorageStats.rankAttention(list, max)
+end
+
+-- Kæde-forslag ligger ikke på en vare (ingen stat): navnet til den stabile rækkefølge tages fra teksten.
+local function entryName(entry)
+ return tostring(entry.stat ~= nil and entry.stat.title or entry.text)
+end
+
+function ADStorageStats.rankAttention(list, max)
table.sort(list, function(a, b)
if a.score ~= b.score then return a.score > b.score end
- return tostring(a.stat.title) < tostring(b.stat.title)
+ return entryName(a) < entryName(b)
end)
local result = {}
for index = 1, math.min(#list, max or #list) do result[index] = list[index] end
return result
end
+-- "Kræver handling" fra kæden (ADChain.last): ét gult punkt pr. afgrødeforslag spilleren skal tage stilling til.
+-- Rangeres over "sælg nu" (score < 1000) og under røde punkter (>= 3000).
+ADStorageStats.CHAIN_SCORE = 1000
+
+function ADStorageStats.chainEntries(last)
+ local entries = {}
+ local titles = last ~= nil and last.titles or {}
+ local function title(name) return tostring((titles or {})[name] or name) end
+ for _, action in ipairs(last ~= nil and last.actions or {}) do
+ if action.mode == "suggest" then
+ local from = (action.from ~= nil and action.from ~= "") and title(action.from) or "-"
+ table.insert(entries, {kind = "chainSuggest", level = "yellow", score = ADStorageStats.CHAIN_SCORE, fieldId = action.fieldId,
+ from = from, to = title(action.to), hectares = action.hectares,
+ text = string.format("F%s %s → %s", tostring(action.fieldId), from, title(action.to))})
+ end
+ end
+ return entries
+end
+
+-- Varepunkterne (allerede rangeret) + kædens punkter, samme loft.
+function ADStorageStats.mergeAttention(attention, chainEntries, max)
+ local list = {}
+ for _, entry in ipairs(attention or {}) do table.insert(list, entry) end
+ for _, entry in ipairs(chainEntries or {}) do table.insert(list, entry) end
+ return ADStorageStats.rankAttention(list, max)
+end
+
function ADStorageStats.kpis(stats)
local kpi = {valueNow = 0, gain = 0, emptyCount = 0, fullCount = 0}
for _, stat in ipairs(stats or {}) do
diff --git a/FS25_ADSmartPickup/gui/SmartPickupAttentionFlow.lua b/FS25_ADSmartPickup/gui/SmartPickupAttentionFlow.lua
index a058e4e..99e635d 100644
--- a/FS25_ADSmartPickup/gui/SmartPickupAttentionFlow.lua
+++ b/FS25_ADSmartPickup/gui/SmartPickupAttentionFlow.lua
@@ -62,6 +62,8 @@ end
-- entry fra ADStorageStats.attentionList -> advice ("open"|"flow"|"produce"|"none"), info
function SmartPickupFrame:attentionAdvice(entry)
+ -- kæde-forslag har ingen vare (stat): klik fører til fanen Kæder
+ if entry ~= nil and entry.kind == "chainSuggest" then return "chain", 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
@@ -83,6 +85,7 @@ function SmartPickupFrame:attentionAdvice(entry)
end
function SmartPickupFrame:attentionHint(advice, info)
+ if advice == "chain" then return self.i18n:getText("spu_attention_hintChain") 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
@@ -91,6 +94,10 @@ end
function SmartPickupFrame:onAttentionClick(entry)
self:safe(function(frame)
+ if entry ~= nil and entry.kind == "chainSuggest" then
+ frame:switchTab(SmartPickupFrame.TAB_CHAINS)
+ return
+ end
local adEnv = frame.getAdEnv()
local advice, info = frame:attentionAdvice(entry)
if adEnv == nil or advice == "none" then return end
diff --git a/FS25_ADSmartPickup/gui/SmartPickupChainTab.lua b/FS25_ADSmartPickup/gui/SmartPickupChainTab.lua
new file mode 100644
index 0000000..e50e871
--- /dev/null
+++ b/FS25_ADSmartPickup/gui/SmartPickupChainTab.lua
@@ -0,0 +1,83 @@
+-- Smart Pickup — fanen Kæder
+-- Produktionskæderne som træ: rod (produktion spilleren har tændt) -> varer -> råvarer, med kilde, behov pr.
+-- måned og flowstatus; afgrødeforslag kan godkendes/afvises og en rod sættes på pause. Rækkerne bygges af
+-- ADChainView (testet); her kun kloning, farve og klik. Evaluering højst hvert CHAIN_EVALUATE_MS (visning, handler ikke).
+
+SmartPickupFrame.CHAIN_EVALUATE_MS = 5000
+
+-- Spillets ur i ms; uden g_time evalueres ved hver opbygning (der kun sker hvert CHAIN_REBUILD_TICKS s).
+local function nowMs()
+ return type(g_time) == "number" and g_time or nil
+end
+
+function SmartPickupFrame:chainLast(adEnv, force)
+ local now = nowMs()
+ local due = force or ADChain.last == nil or now == nil or self.chainEvaluatedAt == nil
+ or now - self.chainEvaluatedAt >= SmartPickupFrame.CHAIN_EVALUATE_MS
+ if due then
+ ADChain.evaluate(adEnv)
+ self.chainEvaluatedAt = now
+ end
+ return ADChain.last
+end
+
+function SmartPickupFrame:chainTitle(last, name)
+ local title = last ~= nil and last.titles ~= nil and last.titles[name] or nil
+ return title or self:fruitTitle(name)
+end
+
+-- Klik på en kæde-knap: udfør, evaluér straks (ny visning) og genopbyg.
+function SmartPickupFrame:onChainAction(action)
+ if action.kind == "approve" then
+ ADChain.approve(action.fieldId)
+ elseif action.kind == "dismiss" then
+ ADChain.dismiss(action.fieldId)
+ elseif action.kind == "pause" or action.kind == "resume" then
+ ADChain.setPaused(action.rootKey, action.kind == "pause")
+ end
+ local adEnv = self.getAdEnv()
+ if adEnv ~= nil then self:chainLast(adEnv, true) end
+ self:requestRebuild()
+end
+
+-- Række med prik + c1..c5 (flowListPrefab); knappen er c5 (klik i c5 = handling, som Flows-listen).
+function SmartPickupFrame:addChainRow(entry)
+ local unpackFn = table.unpack or unpack
+ local row = self:addRow(self.flowListPrefab, {kind = "chainRow"})
+ local cells = {}
+ for index = 1, 5 do cells[index] = row:getDescendantByName("c" .. index) end
+ SmartPickupFrame.setCells(cells, entry.cells)
+ local dot = row:getDescendantByName("dot")
+ local color = ADFlowView.LEVEL_COLORS[entry.level or "running"]
+ if dot ~= nil and dot.setImageColor ~= nil and color ~= nil then
+ dot:setImageColor(nil, unpackFn(color))
+ -- rækker uden egen status (forslag/afvis/auto) får ingen prik — kun rod og noder har status
+ if entry.kind ~= "root" and entry.kind ~= "node" and dot.setVisible ~= nil then dot:setVisible(false) end
+ end
+ if cells[4] ~= nil and cells[4].setTextColor ~= nil and color ~= nil and entry.level ~= "running" then
+ cells[4]:setTextColor(unpackFn(color))
+ end
+ if entry.action ~= nil then
+ local action, actionCell = entry.action, cells[5]
+ self:makeRowClickable(row, function(frame)
+ local onButton = frame.lastClickX == nil or actionCell == nil or actionCell.absPosition == nil
+ or frame.lastClickX >= actionCell.absPosition[1]
+ if onButton then frame:onChainAction(action) end
+ end)
+ end
+ return row
+end
+
+function SmartPickupFrame:fillChainRows(adEnv)
+ local i18n = self.i18n
+ local last = self:chainLast(adEnv, false)
+ local rows = ADChainView.rows(last, function(name) return self:chainTitle(last, name) end,
+ SmartPickupFrame.formatCompact, function(key) return i18n:getText(key) end)
+ for _, entry in ipairs(rows) do
+ if entry.kind == "info" or entry.kind == "empty" then
+ self:addTextRow(entry.text)
+ else
+ self:addChainRow(entry)
+ end
+ end
+end
diff --git a/FS25_ADSmartPickup/gui/SmartPickupFrame.lua b/FS25_ADSmartPickup/gui/SmartPickupFrame.lua
index 34d68c5..148d0b8 100644
--- a/FS25_ADSmartPickup/gui/SmartPickupFrame.lua
+++ b/FS25_ADSmartPickup/gui/SmartPickupFrame.lua
@@ -16,8 +16,11 @@ SmartPickupFrame.TAB_OVERVIEW, SmartPickupFrame.TAB_FLOWS, SmartPickupFrame.TAB_
SmartPickupFrame.MONTH_REBUILD_TICKS = 5
-- Marksilo-fanen har klikbare valg: genopbygges sjældnere, så fokus ikke rykker midt i et valg
SmartPickupFrame.FIELDSILO_REBUILD_TICKS = 30
+-- Kæder-fanen (gui/SmartPickupChainTab.lua): klikbare forslag/pause, så genopbygning sjældent (som Marksiloer)
+SmartPickupFrame.TAB_CHAINS = 10
+SmartPickupFrame.CHAIN_REBUILD_TICKS = 30
-- Lagerfaner: én pr. bygningstype (indeks -> kind i ADSources.getFarmInventory)
-SmartPickupFrame.TAB_NAMES = {"spu_tab_overview", "spu_tab_flows", "spu_tab_fields", "spu_tab_month", "spu_tab_fieldsilos", "spu_tab_factories", "spu_tab_silos", "spu_tab_barns", "spu_tab_sheds"}
+SmartPickupFrame.TAB_NAMES = {"spu_tab_overview", "spu_tab_flows", "spu_tab_fields", "spu_tab_month", "spu_tab_fieldsilos", "spu_tab_factories", "spu_tab_silos", "spu_tab_barns", "spu_tab_sheds", "spu_tab_chains"}
SmartPickupFrame.TAB_KINDS = {[6] = "factory", [7] = "silo", [8] = "husbandry", [9] = "objectStorage"}
function SmartPickupFrame.getTabKind(tab)
@@ -466,6 +469,17 @@ function SmartPickupFrame:rebuild()
self:restoreFocusIfLost()
return
end
+ if self.currentTab == SmartPickupFrame.TAB_CHAINS then
+ if adEnv ~= nil then
+ self:fillChainRows(adEnv)
+ end
+ self.monthRebuildTicks = SmartPickupFrame.CHAIN_REBUILD_TICKS
+ self:colorRows()
+ self.boxLayout:invalidateLayout()
+ self:refreshButtons()
+ self:restoreFocusIfLost()
+ return
+ end
if self.currentTab == SmartPickupFrame.TAB_MONTH then
if adEnv ~= nil then
self:fillMonthRows(adEnv)
@@ -611,7 +625,8 @@ function SmartPickupFrame:refreshButtons()
wanted = self.overviewButtons
elseif self.currentTab == SmartPickupFrame.TAB_FIELDS then
wanted = self:getFieldButtons()
- elseif self.currentTab == SmartPickupFrame.TAB_MONTH or self.currentTab == SmartPickupFrame.TAB_FIELDSILOS then
+ elseif self.currentTab == SmartPickupFrame.TAB_MONTH or self.currentTab == SmartPickupFrame.TAB_FIELDSILOS
+ or self.currentTab == SmartPickupFrame.TAB_CHAINS then
wanted = self.monthButtons
elseif SmartPickupFrame.getTabKind(self.currentTab) ~= nil then
wanted = self.storageButtons
@@ -636,7 +651,8 @@ function SmartPickupFrame:refreshLive()
self:setStatusText(self.i18n:getText("spu_status_noAd"))
return
end
- if self.currentTab == SmartPickupFrame.TAB_MONTH or self.currentTab == SmartPickupFrame.TAB_FIELDSILOS then
+ if self.currentTab == SmartPickupFrame.TAB_MONTH or self.currentTab == SmartPickupFrame.TAB_FIELDSILOS
+ or self.currentTab == SmartPickupFrame.TAB_CHAINS then
self.monthRebuildTicks = (self.monthRebuildTicks or 0) - 1
if self.monthRebuildTicks <= 0 then self:requestRebuild() end
self:refreshButtons()
diff --git a/FS25_ADSmartPickup/gui/SmartPickupStorageView.lua b/FS25_ADSmartPickup/gui/SmartPickupStorageView.lua
index 38129c3..8bcf4c1 100644
--- a/FS25_ADSmartPickup/gui/SmartPickupStorageView.lua
+++ b/FS25_ADSmartPickup/gui/SmartPickupStorageView.lua
@@ -183,8 +183,18 @@ function SmartPickupFrame:addKpiRow(stats)
return row
end
+-- Varepunkterne + kædens afgrødeforslag (ADChain.last; ingen evaluering her), samme loft MAX_ATTENTION.
+function SmartPickupFrame:attentionFor(stats)
+ local attention = ADStorageStats.attentionList(stats, SmartPickupFrame.MAX_ATTENTION)
+ if ADChain == nil or ADChain.last == nil then return attention end
+ return ADStorageStats.mergeAttention(attention, ADStorageStats.chainEntries(ADChain.last), SmartPickupFrame.MAX_ATTENTION)
+end
+
function SmartPickupFrame:alertText(entry)
local stat, fc, i18n = entry.stat, SmartPickupFrame.formatCompact, self.i18n
+ if entry.kind == "chainSuggest" then
+ return string.format(i18n:getText("spu_attention_chainSuggest"), entry.fieldId or 0, tostring(entry.from), tostring(entry.to))
+ 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
@@ -263,7 +273,7 @@ end
function SmartPickupFrame:fillItemOverview(adEnv, inventory, fullInventory)
local i18n = self.i18n
local stats = self:computeItemStats(adEnv, inventory, fullInventory)
- local attention = ADStorageStats.attentionList(stats, SmartPickupFrame.MAX_ATTENTION)
+ local attention = self:attentionFor(stats)
self.itemView = {kpiRow = self:addKpiRow(stats), alertRows = {}, itemRows = {}, key = self:itemStructureKey(stats, attention)}
self.itemRebuildTicks = SmartPickupFrame.ITEM_REBUILD_TICKS
self:addTextRow(i18n:getText("spu_attention"))
@@ -307,7 +317,7 @@ function SmartPickupFrame:refreshItemOverview(adEnv, inventory, fullInventory)
local view = self.itemView
if view == nil then return end
local stats = self:computeItemStats(adEnv, inventory, fullInventory)
- local attention = ADStorageStats.attentionList(stats, SmartPickupFrame.MAX_ATTENTION)
+ local attention = self:attentionFor(stats)
if self:itemStructureKey(stats, attention) ~= view.key then
self.itemRebuildTicks = (self.itemRebuildTicks or 0) - 1
if self.itemRebuildTicks <= 0 then self:requestRebuild() end
diff --git a/FS25_ADSmartPickup/l10n/l10n_da.xml b/FS25_ADSmartPickup/l10n/l10n_da.xml
index 7a1f33f..75a72ad 100644
--- a/FS25_ADSmartPickup/l10n/l10n_da.xml
+++ b/FS25_ADSmartPickup/l10n/l10n_da.xml
@@ -575,5 +575,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FS25_ADSmartPickup/l10n/l10n_en.xml b/FS25_ADSmartPickup/l10n/l10n_en.xml
index afe75ac..f6a8c9b 100644
--- a/FS25_ADSmartPickup/l10n/l10n_en.xml
+++ b/FS25_ADSmartPickup/l10n/l10n_en.xml
@@ -575,5 +575,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FS25_ADSmartPickup/modDesc.xml b/FS25_ADSmartPickup/modDesc.xml
index f65dcd7..ad85ac3 100644
--- a/FS25_ADSmartPickup/modDesc.xml
+++ b/FS25_ADSmartPickup/modDesc.xml
@@ -61,6 +61,7 @@
+