Files
fs25-adsmartpickup/FS25_ADSmartPickup/gui/SmartPickupAttentionFlow.lua
T
masterdraco b33f2a3b01 fix(kæde): højst 3 beskeder og samlede poster i Kræver handling
notifyProblems sender højst 3 beskeder pr. tick og samler resten i én
("+N manglende led — se fanen Kæder"). Alle kædeproblemer står i én rød post
("Kæder: N manglende led", scoret under rød fuld; klik folder kæderne ud) og
slukkede nødvendige fabrikker i højst én post ("Slukket men nødvendig: X +k").
2026-09-30 15:27:08 +02:00

158 lines
7.9 KiB
Lua

-- Smart Pickup — "Kræver handling" -> flow (v1.60)
-- En "løber tør"-linje i lagerfanerne kan klikkes: findes der et flow der leverer varen til forbrugerne, åbnes
-- det; ligger varen andre steder på gården, åbnes "Nyt flow" udfyldt (ind til forbrugerne, varen valgt); ellers
-- 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
-- Forsyningsflow der allerede leverer varen til en af forbrugerne -> run eller nil.
local function existingSupplyRun(consumerIds, name)
for _, run in ipairs(ADRunsController.store.runs) do
if run.kind ~= "outbound" then
local carries = run.ingredientMode ~= "manual"
for _, ingredient in ipairs(run.ingredients or {}) do
if ingredient == name then carries = true end
end
if carries then
for _, id in ipairs(run.targetBuildingIds or {}) do
if consumerIds[id] then return run end
end
end
end
end
return nil
end
-- Udkørselsflow der allerede sælger varen fra en af bygningerne -> run eller nil.
local function existingSellRun(sourceIds, name)
for _, run in ipairs(ADRunsController.store.runs) do
if run.kind == "outbound" then
local sells = false
for _, product in ipairs(run.products or {}) do
if product.fillType == name and (product.policy == "sell" or product.policy == "sellElseStore") then sells = true end
end
if sells then
for _, id in ipairs(run.sourceBuildingIds or {}) do
if sourceIds[id] then return run end
end
end
end
end
return nil
end
-- "Sælg nu": kilder = fanens bygninger med varen.
local function sellAdviceFor(stat)
local sourceIds, ids = {}, {}
for _, building in ipairs(stat.buildings or {}) do
local id = building.placeable ~= nil and ADBuildings.getId(building.placeable) or nil
if id ~= nil and not sourceIds[id] then
sourceIds[id] = true
table.insert(ids, id)
end
end
local name = fillTypeName(stat.fillType)
local run = existingSellRun(sourceIds, name)
local advice = ADStorageStats.sellAdvice({sourceCount = #ids, existingRunId = run ~= nil and run.id or nil})
return advice, {buildingIds = ids, run = run, name = name, stat = stat, sell = true}
end
-- entry fra ADStorageStats.attentionList -> advice ("open"|"flow"|"produce"|"none"), info
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
local consumers = ADStorageStats.consumersOf(self.lastFullInventory, stat.fillType)
local consumerIds, consumerLevel, ids = {}, 0, {}
for _, consumer in ipairs(consumers) do
consumerLevel = consumerLevel + consumer.level
local id = consumer.placeable ~= nil and ADBuildings.getId(consumer.placeable) or nil
if id ~= nil and not consumerIds[id] then
consumerIds[id] = true
table.insert(ids, id)
end
end
local name = fillTypeName(stat.fillType)
local run = existingSupplyRun(consumerIds, name)
local advice = ADStorageStats.flowAdvice({farmLevel = stat.farmLevel or stat.level, consumerLevel = consumerLevel,
perDay = stat.consumption, consumerCount = #ids, existingRunId = run ~= nil and run.id or nil})
return advice, {consumers = consumers, buildingIds = ids, run = run, name = name, stat = stat}
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
return ""
end
function SmartPickupFrame:onAttentionClick(entry)
self:safe(function(frame)
if entry ~= nil and (entry.kind == "chainSuggest" or entry.kind == "chainProblem") then
-- manglende led: kæderne med problemer foldes ud, så problemteksten står under den røde linje
if entry.kind == "chainProblem" then
frame.chainExpanded = frame.chainExpanded or {}
for _, rootKey in ipairs(entry.rootKeys or {}) do frame.chainExpanded[rootKey] = true end
end
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
if advice == "open" then
frame.selectedRunId = info.run.id
frame:switchTab(SmartPickupFrame.TAB_FLOWS)
frame:openEditPanel("flow", info.run.id)
return
end
if advice == "produce" then
local text = string.format(frame.i18n:getText("spu_attention_produce"), tostring(info.stat.title),
SmartPickupFrame.formatCompact(info.stat.farmLevel or 0))
frame.statusOverride, frame.statusOverrideTicks = text, SmartPickupFrame.STATUS_OVERRIDE_TICKS
if ADFieldJobs ~= nil and ADFieldJobs.notify ~= nil then ADFieldJobs.notify(text, false) end
return
end
local guide
if info.sell then
-- udfyldt "Nyt flow": ud af bygningerne med varen, varen til salg
local name = string.format(frame.i18n:getText("spu_attention_sellFlowName"), tostring(info.stat.title))
guide = ADFlowGuide.openNew(name, {})
guide.draft.kind = "outbound"
guide.draft.sourceBuildingIds = info.buildingIds
guide.draft.products = {{fillType = info.name, policy = "sell"}}
else
-- udfyldt "Nyt flow": ind til forbrugerne, kun denne vare; guiden åbnes på oversigten (Gem/Start eller [Ret])
local name = string.format(frame.i18n:getText("spu_attention_flowName"), tostring(info.stat.title), tostring(info.consumers[1].name))
guide = ADFlowGuide.openNew(name, {})
guide.draft.targetBuildingIds = info.buildingIds
guide.draft.ingredientMode = "manual"
guide.draft.ingredients = {info.name}
end
guide = ADGuide.new(ADFlowGuide.DEF, guide.draft, frame:flowGuideContext(adEnv, guide.draft), {step = "summary"})
frame:switchTab(SmartPickupFrame.TAB_FLOWS)
frame:openGuide("flow", guide)
end)
end