feat(kæde): ét flow pr. bygning, slutprodukter sælges straks (Sælg/Behold), tomme kædeflows foldes sammen; såmaskine ikke gødningsspreder (v1.61.4.0)
This commit is contained in:
@@ -17,7 +17,7 @@ ADChain.LOG_PREFIX = "ADSmartPickup: kæde: "
|
||||
-- Et afvist forslag vises igen, når manglen for afgrøden har ændret sig mere end dette.
|
||||
ADChain.DISMISS_CHANGE = 0.25
|
||||
|
||||
ADChain.state = {byChain = {}, paused = {}, dismissed = {}, userOff = {}}
|
||||
ADChain.state = {byChain = {}, paused = {}, dismissed = {}, userOff = {}, finalKeep = {}, soldByChain = {}}
|
||||
ADChain.last = nil
|
||||
-- {[nøgle] = true}: produktioner (ikke kædens) der var tændt ved sidste tick — til at se spillerens slukninger
|
||||
ADChain.prevEnabled = nil
|
||||
@@ -53,12 +53,14 @@ end
|
||||
-- userOff = {[recipeKey] = true}: produktioner spilleren slukkede selv — kæden tænder dem ikke igen.
|
||||
-- roots = {[recipeKey] = true} rødderne ved sidste tick (nil = ukendt, fx gem fra en ældre version).
|
||||
function ADChain.newState()
|
||||
return {byChain = {}, paused = {}, dismissed = {}, userOff = {}, roots = nil}
|
||||
-- finalKeep = {[rodnøgle] = true}: slutproduktet beholdes (standard: sælg straks); soldByChain = {["rod|vare"] = true}
|
||||
return {byChain = {}, paused = {}, dismissed = {}, userOff = {}, roots = nil, finalKeep = {}, soldByChain = {}}
|
||||
end
|
||||
|
||||
function ADChain.stateToRecords(state)
|
||||
local records = {byChain = sortedKeys(state.byChain), paused = sortedKeys(state.paused), userOff = sortedKeys(state.userOff), dismissed = {},
|
||||
roots = state.roots ~= nil and sortedKeys(state.roots) or nil}
|
||||
roots = state.roots ~= nil and sortedKeys(state.roots) or nil,
|
||||
finalKeep = sortedKeys(state.finalKeep or {}), soldByChain = sortedKeys(state.soldByChain or {})}
|
||||
local ids = {}
|
||||
for id in pairs(state.dismissed or {}) do table.insert(ids, id) end
|
||||
table.sort(ids)
|
||||
@@ -75,6 +77,8 @@ function ADChain.stateFromRecords(records)
|
||||
for _, key in ipairs(records.byChain or {}) do state.byChain[key] = true end
|
||||
for _, key in ipairs(records.paused or {}) do state.paused[key] = true end
|
||||
for _, key in ipairs(records.userOff or {}) do state.userOff[key] = true end
|
||||
for _, key in ipairs(records.finalKeep or {}) do state.finalKeep[key] = true end
|
||||
for _, key in ipairs(records.soldByChain or {}) do state.soldByChain[key] = true end
|
||||
if records.roots ~= nil then
|
||||
state.roots = {}
|
||||
for _, key in ipairs(records.roots) do state.roots[key] = true end
|
||||
@@ -378,7 +382,7 @@ function ADChain.evaluate(adEnv, act)
|
||||
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), finalKeep = copySet(state.finalKeep or {}), data = data, fields = data.fields, fieldsIncomplete = data.fieldsIncomplete == true, titles = data.fillTitles, at = ADChain.now, switchCount = ADChain.switchCount,
|
||||
dependency = dependency}
|
||||
return ADChain.last
|
||||
end
|
||||
@@ -491,6 +495,13 @@ function ADChain.dismiss(fieldId)
|
||||
return true
|
||||
end
|
||||
|
||||
-- Slutprodukt for en kæde: keep = true -> "Behold", ellers "Sælg straks" (standard). Anvendes ved næste tick.
|
||||
function ADChain.setFinalKeep(rootKey, keep)
|
||||
if rootKey == nil then return end
|
||||
ADChain.state.finalKeep[rootKey] = keep and true or nil
|
||||
Logging.info(ADChain.LOG_PREFIX .. "%s: slutprodukt %s", tostring(rootKey), keep and "beholdes" or "sælges straks")
|
||||
end
|
||||
|
||||
function ADChain.setPaused(rootKey, isPaused)
|
||||
if rootKey == nil then return end
|
||||
ADChain.state.paused[rootKey] = isPaused and true or nil
|
||||
@@ -520,6 +531,12 @@ function ADChain.save()
|
||||
for index, key in ipairs(records.userOff) do
|
||||
xmlFile:setString(string.format("%s.userOff.recipe(%d)#key", ADChain.ROOT, index - 1), key)
|
||||
end
|
||||
for index, key in ipairs(records.finalKeep) do
|
||||
xmlFile:setString(string.format("%s.finalKeep.root(%d)#key", ADChain.ROOT, index - 1), key)
|
||||
end
|
||||
for index, key in ipairs(records.soldByChain) do
|
||||
xmlFile:setString(string.format("%s.soldByChain.output(%d)#key", ADChain.ROOT, index - 1), key)
|
||||
end
|
||||
if records.roots ~= nil then
|
||||
xmlFile:setBool(ADChain.ROOT .. ".roots#known", true)
|
||||
for index, key in ipairs(records.roots) do
|
||||
@@ -547,7 +564,13 @@ function ADChain.load()
|
||||
if path == nil or not fileExists(path) then return end
|
||||
local xmlFile = XMLFile.load("ADSmartPickupChain", path)
|
||||
if xmlFile == nil then return end
|
||||
local records = {byChain = {}, paused = {}, userOff = {}, dismissed = {}}
|
||||
local records = {byChain = {}, paused = {}, userOff = {}, dismissed = {}, finalKeep = {}, soldByChain = {}}
|
||||
xmlFile:iterate(ADChain.ROOT .. ".finalKeep.root", function(_, key)
|
||||
table.insert(records.finalKeep, xmlFile:getString(key .. "#key"))
|
||||
end)
|
||||
xmlFile:iterate(ADChain.ROOT .. ".soldByChain.output", function(_, key)
|
||||
table.insert(records.soldByChain, xmlFile:getString(key .. "#key"))
|
||||
end)
|
||||
xmlFile:iterate(ADChain.ROOT .. ".byChain.recipe", function(_, key)
|
||||
table.insert(records.byChain, xmlFile:getString(key .. "#key"))
|
||||
end)
|
||||
|
||||
@@ -65,3 +65,80 @@ function ADChainActions.flowsToStop(runs, activeRootKeys)
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
-- ---- ét kædeflow pr. bygning (in-game 30/9: ét flow pr. vare og bygning gav mange stoppede flows) ----
|
||||
|
||||
-- Manglende kanter samlet pr. modtagerbygning: {consumer, consumerName, rootKey, fillTypes} i fundet rækkefølge.
|
||||
function ADChainActions.groupMissing(missing)
|
||||
local groups, byConsumer = {}, {}
|
||||
for _, edge in ipairs(missing or {}) do
|
||||
local group = byConsumer[edge.consumer]
|
||||
if group == nil then
|
||||
group = {consumer = edge.consumer, consumerName = edge.consumerName, rootKey = edge.rootKey, fillTypes = {}}
|
||||
byConsumer[edge.consumer] = group
|
||||
table.insert(groups, group)
|
||||
end
|
||||
if not contains(group.fillTypes, edge.fillType) then table.insert(group.fillTypes, edge.fillType) end
|
||||
end
|
||||
return groups
|
||||
end
|
||||
|
||||
local function isChainRun(run)
|
||||
return run.chain ~= nil and run.chain ~= "" and run.kind == "supply" and run.ingredientMode == "manual"
|
||||
end
|
||||
|
||||
-- Kædens eget flow (manuelle varer) til bygningen -> run-id, så nye varer lægges i det i stedet for et nyt flow.
|
||||
function ADChainActions.chainRunFor(runs, consumer)
|
||||
for _, run in ipairs(runs or {}) do
|
||||
if isChainRun(run) and contains(run.targetBuildingIds, consumer) then return run.id end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Flere tomme kædeflows (uden traktorer) til samme bygning: det første beholdes med alle varerne, resten slettes.
|
||||
-- -> {{keepId, add = {varer}, deleteIds = {id}}}
|
||||
function ADChainActions.mergeIdle(runs)
|
||||
local byConsumer, order = {}, {}
|
||||
for _, run in ipairs(runs or {}) do
|
||||
local target = (run.targetBuildingIds or {})[1]
|
||||
if isChainRun(run) and target ~= nil and #(run.targetBuildingIds or {}) == 1 and #(run.vehicleIds or {}) == 0 then
|
||||
if byConsumer[target] == nil then byConsumer[target] = {}; table.insert(order, target) end
|
||||
table.insert(byConsumer[target], run)
|
||||
end
|
||||
end
|
||||
local merges = {}
|
||||
for _, target in ipairs(order) do
|
||||
local list = byConsumer[target]
|
||||
if #list > 1 then
|
||||
local keep, add, deleteIds = list[1], {}, {}
|
||||
for index = 2, #list do
|
||||
for _, name in ipairs(list[index].ingredients or {}) do
|
||||
if not contains(keep.ingredients, name) and not contains(add, name) then table.insert(add, name) end
|
||||
end
|
||||
table.insert(deleteIds, list[index].id)
|
||||
end
|
||||
table.insert(merges, {keepId = keep.id, add = add, deleteIds = deleteIds})
|
||||
end
|
||||
end
|
||||
return merges
|
||||
end
|
||||
|
||||
-- Slutprodukter der skal sælges straks: aktive rødders udgange, som ikke selv er en kant i kæden (mellemvare).
|
||||
-- keep = {[rodnøgle] = true} for rødder spilleren har sat til "Behold". -> {{key, fillType}}
|
||||
function ADChainActions.finalSales(chain, recipes, edges, keep)
|
||||
local intermediate, byKey, list = {}, {}, {}
|
||||
for _, edge in ipairs(edges or {}) do intermediate[edge.fillType] = true end
|
||||
for _, recipe in ipairs(recipes or {}) do byKey[recipe.key] = recipe end
|
||||
for _, root in ipairs((chain or {}).roots or {}) do
|
||||
local recipe = byKey[root.key]
|
||||
if recipe ~= nil and not (keep or {})[root.key] then
|
||||
local names = {}
|
||||
for name in pairs(recipe.outputs or {}) do table.insert(names, name) end
|
||||
table.sort(names)
|
||||
for _, name in ipairs(names) do
|
||||
if not intermediate[name] then table.insert(list, {key = root.key, fillType = name}) end
|
||||
end
|
||||
end
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
@@ -125,26 +125,15 @@ local function createStopped(run, kind, reason, ...)
|
||||
log("flow '%s' oprettet stoppet: " .. reason, tostring(run.name), ...)
|
||||
end
|
||||
|
||||
local function createFlow(adEnv, data, edge, pool, used)
|
||||
local title = data.fillTitles[edge.fillType] or edge.fillType
|
||||
local created = ADRunsController.createRun(ADChain.flowName(title, edge.consumerName or edge.consumer), "supply")
|
||||
local runId = created.id
|
||||
ADRunsController.updateRun(runId, {targetBuildingIds = {edge.consumer}, ingredientMode = "manual", ingredients = {edge.fillType},
|
||||
waitPoolGroup = ADChain.waitPoolFor(ADRunsController.store.runs, edge.consumer), chain = edge.rootKey})
|
||||
-- updateRun erstatter store'en: slå altid run'et op igen
|
||||
local run = ADRuns.getRun(ADRunsController.store, runId)
|
||||
local fillIndex = data.fillIndex[edge.fillType]
|
||||
if fillIndex ~= nil and ADSources.isPalletFillType(fillIndex) then
|
||||
createStopped(run, "pallet", "palle-vare: vælg vogn med Universal Autoload (%s)", tostring(title))
|
||||
return
|
||||
end
|
||||
if pool.implements == nil then pool.implements, pool.tractors = collectPool(adEnv) end
|
||||
if pool.blocked == nil then pool.blocked = ADPool.blocked(ADFieldJobs.now or 0) end
|
||||
local pair = ADChainRun.choosePair(pool.implements, pool.tractors, fillIndex, used, pool.blocked)
|
||||
if pair == nil then
|
||||
createStopped(run, "noVehicle", "ingen ledig traktor/vogn til %s", tostring(title))
|
||||
return
|
||||
end
|
||||
-- Ét flow pr. modtagerbygning med alle dens manglende bulkvarer (manuelle varer); palle-varer får hver sit
|
||||
-- stoppede flow. group = {consumer, consumerName, rootKey, fillTypes}.
|
||||
local function flowTitle(data, fillTypes)
|
||||
local first = data.fillTitles[fillTypes[1]] or fillTypes[1]
|
||||
if #fillTypes == 1 then return first end
|
||||
return string.format("%s +%d", tostring(first), #fillTypes - 1)
|
||||
end
|
||||
|
||||
local function startWithPair(adEnv, run, runId, pair, used)
|
||||
used[pair.tractor.id], used[pair.implement.id] = true, true
|
||||
ADRunsController.assignVehicle(runId, pair.tractor.vehicle)
|
||||
run = ADRuns.getRun(ADRunsController.store, runId)
|
||||
@@ -159,18 +148,137 @@ local function createFlow(adEnv, data, edge, pool, used)
|
||||
tostring(pair.implement.name), started)
|
||||
end
|
||||
|
||||
local function createGroupFlow(adEnv, data, group, fillTypes, pool, used)
|
||||
local title = flowTitle(data, fillTypes)
|
||||
local created = ADRunsController.createRun(ADChain.flowName(title, group.consumerName or group.consumer), "supply")
|
||||
local runId = created.id
|
||||
ADRunsController.updateRun(runId, {targetBuildingIds = {group.consumer}, ingredientMode = "manual", ingredients = fillTypes,
|
||||
waitPoolGroup = ADChain.waitPoolFor(ADRunsController.store.runs, group.consumer), chain = group.rootKey})
|
||||
-- updateRun erstatter store'en: slå altid run'et op igen
|
||||
local run = ADRuns.getRun(ADRunsController.store, runId)
|
||||
local fillIndex = data.fillIndex[fillTypes[1]]
|
||||
if fillIndex ~= nil and ADSources.isPalletFillType(fillIndex) then
|
||||
createStopped(run, "pallet", "palle-vare: vælg vogn med Universal Autoload (%s)", tostring(title))
|
||||
return
|
||||
end
|
||||
if pool.implements == nil then pool.implements, pool.tractors = collectPool(adEnv) end
|
||||
if pool.blocked == nil then pool.blocked = ADPool.blocked(ADFieldJobs.now or 0) end
|
||||
local pair = ADChainRun.choosePair(pool.implements, pool.tractors, fillIndex, used, pool.blocked)
|
||||
if pair == nil then
|
||||
createStopped(run, "noVehicle", "ingen ledig traktor/vogn til %s", tostring(title))
|
||||
return
|
||||
end
|
||||
startWithPair(adEnv, run, runId, pair, used)
|
||||
end
|
||||
|
||||
-- Nye varer til en bygning, der allerede har et kædeflow: lægges i det flow.
|
||||
local function extendFlow(runId, fillTypes)
|
||||
local run = ADRuns.getRun(ADRunsController.store, runId)
|
||||
if run == nil then return false end
|
||||
local ingredients = {}
|
||||
for _, name in ipairs(run.ingredients or {}) do table.insert(ingredients, name) end
|
||||
local added = {}
|
||||
for _, name in ipairs(fillTypes) do
|
||||
local present = false
|
||||
for _, have in ipairs(ingredients) do if have == name then present = true end end
|
||||
if not present then table.insert(ingredients, name); table.insert(added, name) end
|
||||
end
|
||||
if #added == 0 then return false end
|
||||
ADRunsController.updateRun(runId, {ingredients = ingredients})
|
||||
log("flow '%s' får også %s", tostring(run.name), table.concat(added, ", "))
|
||||
return true
|
||||
end
|
||||
|
||||
-- Tidligere kædeflows (ét pr. vare) til samme bygning uden traktorer lægges sammen i ét.
|
||||
function ADChainRun.mergeIdleFlows(adEnv)
|
||||
local merged = 0
|
||||
for _, merge in ipairs(ADChainActions.mergeIdle(ADChain.runsView(ADRunsController.store.runs))) do
|
||||
if #merge.add > 0 then extendFlow(merge.keepId, merge.add) end
|
||||
for _, id in ipairs(merge.deleteIds) do
|
||||
local ok, err = pcall(ADRunsController.deleteRun, id, adEnv)
|
||||
if ok then
|
||||
ADChain.noVehicle[id] = nil
|
||||
merged = merged + 1
|
||||
else
|
||||
warn("kædeflow %s kunne ikke lægges sammen: %s", tostring(id), tostring(err))
|
||||
end
|
||||
end
|
||||
end
|
||||
if merged > 0 then log("%d tomme kædeflows lagt sammen (ét flow pr. bygning)", merged) end
|
||||
return merged
|
||||
end
|
||||
|
||||
function ADChainRun.createFlows(adEnv, data, edges)
|
||||
local missing = ADChainActions.missingFlows(edges, ADChain.runsView(ADRunsController.store.runs))
|
||||
local runs = ADChain.runsView(ADRunsController.store.runs)
|
||||
local missing = ADChainActions.missingFlows(edges, runs)
|
||||
local pool, used, count = {}, {}, 0
|
||||
for _, edge in ipairs(missing) do
|
||||
for _, group in ipairs(ADChainActions.groupMissing(missing)) do
|
||||
if count >= ADChain.MAX_NEW_FLOWS then break end
|
||||
count = count + 1
|
||||
local ok, err = pcall(createFlow, adEnv, data, edge, pool, used)
|
||||
if not ok then warn("flow til %s (%s) kunne ikke oprettes: %s", tostring(edge.consumerName), tostring(edge.fillType), tostring(err)) end
|
||||
local bulk, pallets = {}, {}
|
||||
for _, name in ipairs(group.fillTypes) do
|
||||
local index = data.fillIndex[name]
|
||||
table.insert((index ~= nil and ADSources.isPalletFillType(index)) and pallets or bulk, name)
|
||||
end
|
||||
local ok, err = pcall(function()
|
||||
if #bulk > 0 then
|
||||
local existing = ADChainActions.chainRunFor(runs, group.consumer)
|
||||
if existing ~= nil then
|
||||
if extendFlow(existing, bulk) then count = count + 1 end
|
||||
else
|
||||
createGroupFlow(adEnv, data, group, bulk, pool, used)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
for _, name in ipairs(pallets) do
|
||||
createGroupFlow(adEnv, data, group, {name}, pool, used)
|
||||
count = count + 1
|
||||
end
|
||||
end)
|
||||
if not ok then warn("flow til %s kunne ikke oprettes: %s", tostring(group.consumerName), tostring(err)) end
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
-- Slutprodukter: sælg straks (fabrikkens udgang -> "Sælg direkte"), medmindre kæden står på "Behold". Varer kæden
|
||||
-- selv satte til salg, sættes tilbage til "Behold", når spilleren vælger det.
|
||||
local function outputMode(point, fillIndex)
|
||||
if point.getOutputDistributionMode == nil then return nil end
|
||||
local ok, mode = pcall(point.getOutputDistributionMode, point, fillIndex)
|
||||
return ok and mode or nil
|
||||
end
|
||||
|
||||
function ADChainRun.applyFinalSales(data, chain, edges)
|
||||
if ProductionPoint == nil or ProductionPoint.OUTPUT_MODE == nil then return 0 end
|
||||
local state, changed = ADChain.state, 0
|
||||
local wanted = {}
|
||||
for _, sale in ipairs(ADChainActions.finalSales(chain, data.recipes, edges, state.finalKeep)) do
|
||||
local id = sale.key .. "|" .. sale.fillType
|
||||
wanted[id] = true
|
||||
local entry, fillIndex = (data.points or {})[sale.key], data.fillIndex[sale.fillType]
|
||||
if entry ~= nil and entry.point ~= nil and fillIndex ~= nil and entry.point.setOutputDistributionMode ~= nil
|
||||
and outputMode(entry.point, fillIndex) ~= ProductionPoint.OUTPUT_MODE.DIRECT_SELL then
|
||||
entry.point:setOutputDistributionMode(fillIndex, ProductionPoint.OUTPUT_MODE.DIRECT_SELL)
|
||||
state.soldByChain[id] = true
|
||||
changed = changed + 1
|
||||
log("slutprodukt %s i %s sælges straks", tostring(sale.fillType), tostring(entry.buildingName or sale.key))
|
||||
end
|
||||
end
|
||||
for id in pairs(state.soldByChain) do
|
||||
local key, fillType = id:match("^(.*)|([^|]+)$")
|
||||
if key ~= nil and state.finalKeep[key] and not wanted[id] then
|
||||
local entry, fillIndex = (data.points or {})[key], data.fillIndex[fillType]
|
||||
if entry ~= nil and entry.point ~= nil and fillIndex ~= nil
|
||||
and outputMode(entry.point, fillIndex) == ProductionPoint.OUTPUT_MODE.DIRECT_SELL then
|
||||
entry.point:setOutputDistributionMode(fillIndex, ProductionPoint.OUTPUT_MODE.KEEP)
|
||||
changed = changed + 1
|
||||
log("slutprodukt %s beholdes igen", tostring(fillType))
|
||||
end
|
||||
state.soldByChain[id] = nil
|
||||
end
|
||||
end
|
||||
return changed
|
||||
end
|
||||
|
||||
-- Flows for rødder der er slået fra: flyt til en anden rod der stadig bruger kanten, ellers stop og slip (chain
|
||||
-- ryddes, så spilleren kan starte flowet igen uden at kæden stopper det næste minut; det slettes ikke).
|
||||
function ADChainRun.stopFlows(adEnv, chain, edges)
|
||||
@@ -202,7 +310,12 @@ function ADChainRun.apply(adEnv, data, result)
|
||||
if not okFields then warn("markskift fejlede: %s", tostring(errFields)) end
|
||||
local okProd, errProd = pcall(ADChainRun.toggleProductions, data, result.prod)
|
||||
if not okProd then warn("mellemled fejlede: %s", tostring(errProd)) end
|
||||
local okMerge, mergedCount = pcall(ADChainRun.mergeIdleFlows, adEnv)
|
||||
if not okMerge then warn("sammenlægning af kædeflows fejlede: %s", tostring(mergedCount)) end
|
||||
local okNew, created = pcall(ADChainRun.createFlows, adEnv, data, result.edges)
|
||||
local okSell, sellErr = pcall(ADChainRun.applyFinalSales, data, result.chain, result.edges)
|
||||
if not okSell then warn("slutprodukter fejlede: %s", tostring(sellErr)) end
|
||||
if okMerge and mergedCount > 0 then created = (okNew and created or 0) + mergedCount end
|
||||
if not okNew then warn("nye flows fejlede: %s", tostring(created)) end
|
||||
-- delvise data: en rod der ikke kunne læses, må ikke få sine flows stoppet
|
||||
local okStop, stopped = true, 0
|
||||
|
||||
@@ -20,7 +20,7 @@ ADChainView.TEXT_ROW_CHARS = 70
|
||||
-- "stramt": lager for en mark-afgrøde under så mange måneders behov -> gul
|
||||
ADChainView.TIGHT_MONTHS = 3
|
||||
-- nøgler rækkerne bruger (til l10n-testen)
|
||||
ADChainView.TEXT_KEYS = {"spu_chain_suggestHeader", "spu_chain_empty", "spu_chain_approve", "spu_chain_dismiss", "spu_chain_auto",
|
||||
ADChainView.TEXT_KEYS = {"spu_chain_finalSell", "spu_chain_finalKeep", "spu_chain_suggestHeader", "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_fromFields",
|
||||
"spu_chain_pause", "spu_chain_resume", "spu_chain_scanning", "spu_chain_rootOk", "spu_chain_rootError", "spu_chain_rootWaiting",
|
||||
@@ -313,9 +313,12 @@ local function rootRows(rows, root, last, ctx, isExpanded)
|
||||
local status = ctx.textOf(ROOT_STATUS[level])
|
||||
if #suggestions > 0 then status = string.format(ctx.textOf("spu_chain_rootSummary"), status, #suggestions) end
|
||||
local marker = (#(root.children or {}) > 0) and (isExpanded and "– " or "+ ") or ""
|
||||
table.insert(rows, makeRow("root", 0, level, {marker .. ctx.titleOf(root.name), tostring(root.buildingName or ""), "", status,
|
||||
-- slutproduktet: "Sælg straks" (standard) eller "Behold" — klik på feltet skifter
|
||||
local keep = (last.finalKeep or {})[root.key] == true
|
||||
table.insert(rows, makeRow("root", 0, level, {marker .. ctx.titleOf(root.name), tostring(root.buildingName or ""),
|
||||
ctx.textOf(keep and "spu_chain_finalKeep" or "spu_chain_finalSell"), status,
|
||||
ctx.textOf(paused and "spu_chain_resume" or "spu_chain_pause")},
|
||||
{[5] = {kind = paused and "resume" or "pause", rootKey = root.key}}, root.key))
|
||||
{[3] = {kind = "finalMode", rootKey = root.key, keep = not keep}, [5] = {kind = paused and "resume" or "pause", rootKey = root.key}}, root.key))
|
||||
if not isExpanded then return end
|
||||
local shown, problems, told = {}, {}, {}
|
||||
for _, problem in ipairs((last.chain or {}).problems or {}) do
|
||||
|
||||
@@ -166,7 +166,7 @@ function ADFieldWork.getRigs(adEnv)
|
||||
manual = (state.manual or {})[id] == true,
|
||||
width = ADCpBridge.getWorkWidth(vehicle), x = x, z = z,
|
||||
-- tom spreder kan flere ting (gødning og kalk): alle dens roller
|
||||
roles = specs.sprayRoles or ADFieldFleet.rolesFor(role), filledRole = specs.filledRole, dumpable = specs.dumpable,
|
||||
roles = ADPool.rolesOf(role, specs.sprayRoles), filledRole = specs.filledRole, dumpable = specs.dumpable,
|
||||
}
|
||||
if role == "harvester" then rig.fruits = ADCpBridge.getHarvestFruits(vehicle) or {} end
|
||||
if role == "seeder" then
|
||||
|
||||
@@ -74,6 +74,15 @@ function ADFlowView.boardGroups(runs)
|
||||
return groups
|
||||
end
|
||||
|
||||
-- Kædeflows uden traktor foldes sammen i listen (de venter på en ledig traktor/vogn). -> active, idle
|
||||
function ADFlowView.splitIdle(runs)
|
||||
local active, idle = {}, {}
|
||||
for _, run in ipairs(runs or {}) do
|
||||
table.insert(#(run.vehicleIds or {}) > 0 and active or idle, run)
|
||||
end
|
||||
return active, idle
|
||||
end
|
||||
|
||||
-- Navn i listen: kædeflows står under overskriften "Kædernes egne flows", så "Kæde: " fjernes (ellers skjuler
|
||||
-- afkortningen hvilken bygning det gælder).
|
||||
function ADFlowView.listName(run)
|
||||
|
||||
@@ -18,6 +18,13 @@ function ADPool.roleOf(specs)
|
||||
return role
|
||||
end
|
||||
|
||||
-- Ekstra roller for et redskab: sprøjtens roller (gødning/kalk/ukrudt) — men ikke for en såmaskine med
|
||||
-- gødningstank (Kinze 4905), den er kun såmaskine (in-game 30/9: hentet til ren gødning).
|
||||
function ADPool.rolesOf(role, sprayRoles)
|
||||
if role ~= "seeder" and sprayRoles ~= nil then return sprayRoles end
|
||||
return ADFieldFleet.rolesFor(role)
|
||||
end
|
||||
|
||||
-- Butiksdata er enten et tal eller en tabel pr. konfiguration: største tal, ellers nil.
|
||||
function ADPool.numberOf(value)
|
||||
if type(value) == "number" then return value end
|
||||
@@ -402,7 +409,7 @@ function ADPool.collect(adEnv, isBusy)
|
||||
local carries, capacity = ADPool.cargoOf(vehicle)
|
||||
table.insert(implements, {carries = carries, capacity = capacity,
|
||||
id = ADRunsController.getVehicleId(vehicle), vehicle = vehicle, name = ADRuns.vehicleLabel(vehicle),
|
||||
role = role, roles = specs.sprayRoles or ADFieldFleet.rolesFor(role), x = x, z = z, width = ADCpBridge.getWorkWidth(vehicle),
|
||||
role = role, roles = ADPool.rolesOf(role, specs.sprayRoles), x = x, z = z, width = ADCpBridge.getWorkWidth(vehicle),
|
||||
neededHp = neededHpOf(vehicle), connectId = connect.id, parkId = park.id,
|
||||
})
|
||||
end
|
||||
|
||||
@@ -27,6 +27,8 @@ function SmartPickupFrame:onChainAction(action)
|
||||
ok = ADChain.approve(action.fieldId)
|
||||
elseif action.kind == "dismiss" then
|
||||
ok = ADChain.dismiss(action.fieldId)
|
||||
elseif action.kind == "finalMode" then
|
||||
ADChain.setFinalKeep(action.rootKey, action.keep)
|
||||
elseif action.kind == "pause" or action.kind == "resume" then
|
||||
ADChain.setPaused(action.rootKey, action.kind == "pause")
|
||||
end
|
||||
|
||||
@@ -232,10 +232,8 @@ function SmartPickupFrame:fillFlowTabRows(adEnv)
|
||||
return
|
||||
end
|
||||
self:addTextRow(i18n:getText("spu_flowList_hint"))
|
||||
for _, group in ipairs(ADFlowView.boardGroups(ADRunsController.store.runs)) do
|
||||
self:addTextRow(i18n:getText(group.chain and "spu_board_chain" or group.kind == "outbound" and "spu_board_outbound" or "spu_board_supply"))
|
||||
for _, run in ipairs(group.runs) do
|
||||
local row = self:addRow(self.flowListPrefab, {kind = "flowList"})
|
||||
local function addFlowRow(run)
|
||||
local row = self:addRow(self.flowListPrefab, {kind = "flowList"})
|
||||
local entry = {runId = run.id, row = row, dot = row:getDescendantByName("dot"),
|
||||
cells = {row:getDescendantByName("c1"), row:getDescendantByName("c2"), row:getDescendantByName("c3"),
|
||||
row:getDescendantByName("c4"), row:getDescendantByName("c5")}}
|
||||
@@ -252,6 +250,22 @@ function SmartPickupFrame:fillFlowTabRows(adEnv)
|
||||
end
|
||||
end)
|
||||
table.insert(self.flowListRows, entry)
|
||||
end
|
||||
for _, group in ipairs(ADFlowView.boardGroups(ADRunsController.store.runs)) do
|
||||
self:addTextRow(i18n:getText(group.chain and "spu_board_chain" or group.kind == "outbound" and "spu_board_outbound" or "spu_board_supply"))
|
||||
local runs, idle = group.runs, {}
|
||||
-- kædeflows uden traktor (venter på en ledig traktor/vogn) foldes sammen (in-game 30/9)
|
||||
if group.chain then runs, idle = ADFlowView.splitIdle(group.runs) end
|
||||
for _, run in ipairs(runs) do addFlowRow(run) end
|
||||
if #idle > 0 then
|
||||
local key = self.showIdleChainFlows and "spu_board_chainIdleHide" or "spu_board_chainIdleShow"
|
||||
self:addLinkRow(" " .. string.format(i18n:getText(key), #idle), function(frame)
|
||||
frame.showIdleChainFlows = not frame.showIdleChainFlows
|
||||
frame:requestRebuild()
|
||||
end)
|
||||
if self.showIdleChainFlows then
|
||||
for _, run in ipairs(idle) do addFlowRow(run) end
|
||||
end
|
||||
end
|
||||
end
|
||||
self:refreshFlowListRows(adEnv)
|
||||
|
||||
@@ -377,6 +377,8 @@
|
||||
<text name="spu_col_to" text="Til"/>
|
||||
<text name="spu_col_tractors" text="Kører"/>
|
||||
<text name="spu_col_status" text="Status"/>
|
||||
<text name="spu_board_chainIdleShow" text="%d kædeflows venter på en ledig traktor/vogn — klik for at vise"/>
|
||||
<text name="spu_board_chainIdleHide" text="%d kædeflows uden traktor — klik for at skjule"/>
|
||||
<text name="spu_board_chain" text="· Kædernes egne flows (oprettes af fanen Kæder) ·"/>
|
||||
<text name="spu_board_supply" text="· Ind til bygning ·"/>
|
||||
<text name="spu_board_outbound" text="· Ud fra bygning ·"/>
|
||||
@@ -577,6 +579,8 @@
|
||||
<text name="spu_item_balanced" text="i balance"/>
|
||||
<text name="spu_item_share" text="%d %% af varen"/>
|
||||
<text name="spu_tab_chains" text="Kæder"/>
|
||||
<text name="spu_chain_finalSell" text="Sælg"/>
|
||||
<text name="spu_chain_finalKeep" text="Behold"/>
|
||||
<text name="spu_chain_suggestHeader" text="Forslag til ny afgrøde"/>
|
||||
<text name="spu_chain_empty" text="Ingen kæder: slå et produkt til i en fabrik"/>
|
||||
<text name="spu_chain_col_item" text="Vare"/>
|
||||
|
||||
@@ -377,6 +377,8 @@
|
||||
<text name="spu_col_to" text="To"/>
|
||||
<text name="spu_col_tractors" text="Running"/>
|
||||
<text name="spu_col_status" text="Status"/>
|
||||
<text name="spu_board_chainIdleShow" text="%d chain flows are waiting for a free tractor/trailer — click to show"/>
|
||||
<text name="spu_board_chainIdleHide" text="%d chain flows without a tractor — click to hide"/>
|
||||
<text name="spu_board_chain" text="· Flows created by chains (Chains tab) ·"/>
|
||||
<text name="spu_board_supply" text="· Into building ·"/>
|
||||
<text name="spu_board_outbound" text="· Out of building ·"/>
|
||||
@@ -577,6 +579,8 @@
|
||||
<text name="spu_item_balanced" text="balanced"/>
|
||||
<text name="spu_item_share" text="%d %% of the good"/>
|
||||
<text name="spu_tab_chains" text="Chains"/>
|
||||
<text name="spu_chain_finalSell" text="Sell"/>
|
||||
<text name="spu_chain_finalKeep" text="Keep"/>
|
||||
<text name="spu_chain_suggestHeader" text="Crop change suggestions"/>
|
||||
<text name="spu_chain_empty" text="No chains: enable a product in a factory"/>
|
||||
<text name="spu_chain_col_item" text="Goods"/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<modDesc descVersion="107">
|
||||
<author>masterdraco</author>
|
||||
<version>1.61.3.0</version>
|
||||
<version>1.61.4.0</version>
|
||||
<title>
|
||||
<en>AD Smart Pickup</en>
|
||||
</title>
|
||||
|
||||
Reference in New Issue
Block a user