304 lines
14 KiB
Lua
304 lines
14 KiB
Lua
-- Smart Pickup — fanen Flows: tavle + resumé, og guiden "Opsæt flow"
|
|
-- Tavlen øverst (én række pr. flow), det valgte flows resumé (klik på en linje = ret ét trin; Navn = omdøb)
|
|
-- og status. [Opsæt flow] / [Nyt flow] åbner guiden på den fælles trin-skærm (gui/SmartPickupGuide.lua).
|
|
-- Henter det spil-afhængige som `context` til ADFlowGuide og gemmer via ADRunsController.
|
|
-- Funktionerne lægges på SmartPickupFrame (indlæses efter SmartPickupFrame.lua).
|
|
|
|
function SmartPickupFrame:initFlowButtons(i18n)
|
|
self.flowSetupButtonInfo = {inputAction = InputAction.MENU_EXTRA_1, text = i18n:getText("spu_guide_flow_open"), callback = function() self:onClickFlowSetup() end}
|
|
self.flowNewButtonInfo = {inputAction = InputAction.MENU_EXTRA_2, text = i18n:getText("spu_button_new"), callback = function() self:onClickFlowNew() end}
|
|
-- Flows-fanen: [Start/Stop] [Opsæt flow] [Nyt flow] [Slet]; omdøb ligger på resuméets Navn-linje
|
|
self.flowButtons = {self.backButtonInfo, self.startButtonInfo, self.flowSetupButtonInfo, self.flowNewButtonInfo, self.deleteButtonInfo}
|
|
end
|
|
|
|
-- ---- traktor-tekst (også til guidens traktorliste) ----
|
|
|
|
-- "Fastrac 2135 4WS (#1) — 1.000.000 l — kan bære: Halm, TMR — OK" / "… — X ingen vogn".
|
|
function SmartPickupFrame:describeVehicle(adEnv, run, vehicle, isInRun)
|
|
local label = ADRunsController.getVehicleLabel(adEnv, vehicle)
|
|
local validation = ADRunsController.validateVehicle(adEnv, run, vehicle)
|
|
local parts = {label}
|
|
if validation.isAutoload and validation.capacity == nil then
|
|
table.insert(parts, self.i18n:getText("spu_capacity_pallets"))
|
|
elseif validation.capacity ~= nil then
|
|
table.insert(parts, string.format(self.i18n:getText("spu_capacity"), g_i18n:formatNumber(validation.capacity, 0)))
|
|
local carriable = self:describeCarriable(adEnv, run, vehicle, validation.carriable)
|
|
if carriable ~= nil then
|
|
table.insert(parts, carriable)
|
|
end
|
|
end
|
|
if validation.ok then
|
|
table.insert(parts, "OK")
|
|
else
|
|
local reason = self.i18n:getText("spu_reason_" .. tostring(validation.reason))
|
|
if validation.reason == "noMarker" and validation.missingBuilding ~= nil then
|
|
reason = string.format(reason, tostring(validation.missingBuilding))
|
|
end
|
|
table.insert(parts, "X " .. reason)
|
|
end
|
|
return table.concat(parts, " — ")
|
|
end
|
|
|
|
-- Hvilke af run'ets varer vognen kan bære (titler); nil når ingen.
|
|
function SmartPickupFrame:describeCarriable(adEnv, run, vehicle, carriable)
|
|
local canCarry = {}
|
|
for _, fillType in ipairs(carriable or {}) do
|
|
canCarry[fillType] = true
|
|
end
|
|
local titles = {}
|
|
for _, fillType in ipairs(ADRunsController.getRunIngredients(adEnv, run, vehicle)) do
|
|
if canCarry[fillType] then
|
|
local title = g_fillTypeManager.getFillTypeTitleByIndex ~= nil and g_fillTypeManager:getFillTypeTitleByIndex(fillType) or nil
|
|
table.insert(titles, tostring(title or g_fillTypeManager:getFillTypeNameByIndex(fillType)))
|
|
end
|
|
end
|
|
if #titles == 0 then
|
|
return nil
|
|
end
|
|
return string.format(self.i18n:getText("spu_canCarry"), table.concat(titles, ", "))
|
|
end
|
|
|
|
-- ---- context til ADFlowGuide ----
|
|
|
|
local function trim(text)
|
|
return (string.gsub(tostring(text or ""), "^%s+", ""))
|
|
end
|
|
|
|
local function idSet(list)
|
|
local set = {}
|
|
for _, id in ipairs(list or {}) do set[id] = true end
|
|
return set
|
|
end
|
|
|
|
function SmartPickupFrame:flowBuildingContext(adEnv, draft, farmId)
|
|
local isOut = draft.kind == "outbound"
|
|
local role = isOut and "load" or "unload"
|
|
local chosen = idSet(isOut and draft.sourceBuildingIds or draft.targetBuildingIds)
|
|
local buildings, found = {}, {}
|
|
for _, building in ipairs(ADBuildings.list(adEnv, farmId)) do
|
|
local fits = (isOut and building.canBeSource) or (not isOut and building.canBeTarget)
|
|
if fits or chosen[building.id] then
|
|
local markers = ADBuildings.getMarkers ~= nil and ADBuildings.getMarkers(building, role) or {}
|
|
found[building.id] = true
|
|
table.insert(buildings, {id = building.id, name = tostring(building.name), label = markers[1] ~= nil and tostring(markers[1].name) or nil,
|
|
hasMarker = markers[1] ~= nil, text = trim(self:describeBuilding(building, role))})
|
|
end
|
|
end
|
|
-- valgte bygninger der ikke længere findes (solgt): kan fravælges
|
|
for id in pairs(chosen) do
|
|
if not found[id] then
|
|
local gone = self.i18n:getText("spu_buildingGone")
|
|
table.insert(buildings, {id = id, name = gone, hasMarker = false, text = gone})
|
|
end
|
|
end
|
|
return buildings
|
|
end
|
|
|
|
function SmartPickupFrame:flowStoreContext(adEnv, preview, farmId)
|
|
local goods = ADRunsController.getStoreGoods(adEnv, preview)
|
|
local chosen = idSet(preview.storeBuildingIds)
|
|
local result = {}
|
|
for _, building in ipairs(ADBuildings.list(adEnv, farmId)) do
|
|
local isStoreKind = building.kind == "silo" or building.kind == "factory" or building.kind == "objectStorage"
|
|
if isStoreKind and (chosen[building.id] or ADRunsController.canStoreAt(adEnv, building, goods)) then
|
|
table.insert(result, {id = building.id, name = tostring(building.name), text = trim(self:describeBuilding(building, "unload"))})
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
function SmartPickupFrame:flowVehicleContext(adEnv, preview)
|
|
local result = {}
|
|
for _, vehicle in ipairs(ADRunsController.getFarmVehicles(adEnv)) do
|
|
local ok, entry = pcall(function()
|
|
local text = self:describeVehicle(adEnv, preview, vehicle, false)
|
|
local validation = ADRunsController.validateVehicle(adEnv, preview, vehicle)
|
|
local other = ADRunsController.getRunForVehicle(vehicle)
|
|
return {id = ADRunsController.getVehicleId(vehicle), text = text, label = ADRunsController.getVehicleLabel(adEnv, vehicle), otherRunId = other ~= nil and other.id or nil,
|
|
otherRunName = other ~= nil and other.name or nil, blocked = SmartPickupFrame.VEHICLE_BLOCKING_REASONS[validation.reason] == true}
|
|
end)
|
|
if ok and entry.id ~= nil then table.insert(result, entry) end
|
|
end
|
|
return result
|
|
end
|
|
|
|
-- draft: kladden (eller selve run'et — samme feltnavne).
|
|
function SmartPickupFrame:flowGuideContext(adEnv, draft)
|
|
local farmId = g_currentMission:getFarmId()
|
|
local preview = ADFlowGuide.previewRun(draft, function(buildingId, role)
|
|
local building = ADBuildings.find(adEnv, farmId, buildingId)
|
|
local ids = {}
|
|
for _, marker in ipairs(building ~= nil and ADBuildings.getMarkers ~= nil and ADBuildings.getMarkers(building, role) or {}) do
|
|
table.insert(ids, marker.id)
|
|
end
|
|
return ids
|
|
end)
|
|
local context = {buildings = self:flowBuildingContext(adEnv, draft, farmId), fillTypes = {}, products = {}, storeBuildings = {},
|
|
waitPools = ADRunsController.getWaitPools(adEnv), vehicles = self:flowVehicleContext(adEnv, preview)}
|
|
if draft.kind == "outbound" then
|
|
for _, product in ipairs(ADRunsController.getRunProducts(adEnv, preview)) do
|
|
local title = tostring(product.title)
|
|
table.insert(context.products, {name = product.name, title = title,
|
|
text = string.format("%s — %s l", title, SmartPickupFrame.formatCompact(product.available or 0))})
|
|
end
|
|
context.storeBuildings = self:flowStoreContext(adEnv, preview, farmId)
|
|
else
|
|
for _, fillType in ipairs(ADRunsController.getTargetAcceptedFillTypes(adEnv, preview)) do
|
|
table.insert(context.fillTypes, {name = fillType.name, title = tostring(fillType.title)})
|
|
end
|
|
end
|
|
return context
|
|
end
|
|
|
|
-- ---- fanen: tavle + resumé ----
|
|
|
|
function SmartPickupFrame:fillFlowTabRows(adEnv)
|
|
if self:hasGuideOn(SmartPickupFrame.TAB_FLOWS) and self:fillGuideRows(adEnv) then return end
|
|
self:fillOverviewRows(adEnv)
|
|
local run = self:getRun()
|
|
if run ~= nil then self:fillFlowSummary(adEnv, run) end
|
|
end
|
|
|
|
function SmartPickupFrame:fillFlowSummary(adEnv, run)
|
|
local i18n = self.i18n
|
|
self:addTextRow(string.format(i18n:getText("spu_guide_flow_section"), tostring(run.name)))
|
|
self:addTextRow(" " .. i18n:getText("spu_guide_sum_hint"))
|
|
local guide = ADFlowGuide.open(run, self:flowGuideContext(adEnv, run))
|
|
local getText = function(key) return i18n:getText(key) end
|
|
local runId = run.id
|
|
for _, line in ipairs(ADFlowGuide.summary(guide)) do
|
|
local step = line.step
|
|
self:addLinkRow(" " .. ADGuide.lineText(line, getText) .. i18n:getText("spu_guide_editSuffix"), function(frame)
|
|
if step == "name" then frame:onClickRename() else frame:openFlowStep(runId, step) end
|
|
end)
|
|
end
|
|
local cells = self:flowCells(adEnv, run)
|
|
self:addTextRow(" " .. string.format(i18n:getText("spu_field_statusFull"), tostring(cells[6])))
|
|
end
|
|
|
|
-- Hvert sekund: tavlens celler, statuslinje og knapper.
|
|
function SmartPickupFrame:refreshFlowTab(adEnv)
|
|
local run = self:getRun()
|
|
local isRunning = false
|
|
if self:hasGuideOn(SmartPickupFrame.TAB_FLOWS) then
|
|
self:setStatusText(self.statusOverride or "")
|
|
else
|
|
self:refreshOverview(adEnv)
|
|
if run ~= nil then
|
|
local status = ADRunsController.getRunStatus(adEnv, run)
|
|
isRunning = status.isRunning == true
|
|
local text = status.running > 0 and string.format(self.i18n:getText("spu_status_running"), status.running, status.total)
|
|
or string.format(self.i18n:getText("spu_status_stopped"), status.total)
|
|
self:setStatusText(self.statusOverride or text)
|
|
else
|
|
-- tavlen siger allerede "Ingen flows"
|
|
self:setStatusText(self.statusOverride or "")
|
|
end
|
|
end
|
|
self.startButtonInfo.text = self.i18n:getText(isRunning and "spu_button_stop" or "spu_button_start")
|
|
self.startButtonInfo.disabled = run == nil
|
|
self.flowSetupButtonInfo.disabled = run == nil
|
|
self.deleteButtonInfo.disabled = run == nil
|
|
end
|
|
|
|
-- ---- hooks til den fælles guide-skærm ----
|
|
|
|
SmartPickupFrame.GUIDE_HOOKS = SmartPickupFrame.GUIDE_HOOKS or {}
|
|
SmartPickupFrame.GUIDE_HOOKS.flow = {
|
|
model = ADFlowGuide,
|
|
tab = SmartPickupFrame.TAB_FLOWS,
|
|
heading = function(frame, guide)
|
|
return string.format(frame.i18n:getText("spu_guide_flow_title"), tostring(guide.draft.name))
|
|
end,
|
|
context = function(frame, adEnv, guide)
|
|
-- flowet er slettet mens guiden var åben
|
|
if not guide.draft.isNew and ADRuns.getRun(ADRunsController.store, guide.draft.id) == nil then return nil end
|
|
return frame:flowGuideContext(adEnv, guide.draft)
|
|
end,
|
|
choose = function(frame, id)
|
|
if id ~= "rename" then return false end
|
|
TextInputDialog.show(SmartPickupFrame.onGuideNameResult, frame, frame.guide.draft.name, frame.i18n:getText("spu_renameTitle"), nil, 30, g_i18n:getText("button_ok"))
|
|
return true
|
|
end,
|
|
startKey = function() return "spu_guide_flow_start" end,
|
|
save = function(frame, guide, start) frame:saveFlowGuide(guide, start) end,
|
|
}
|
|
|
|
function SmartPickupFrame:onGuideNameResult(value, clickOk)
|
|
self:safe(function(frame)
|
|
if not clickOk or frame.guide == nil or frame.guideKind ~= "flow" then return end
|
|
frame.guide = ADFlowGuide.choose(frame.guide, "name", value)
|
|
frame:requestRebuild()
|
|
end)
|
|
end
|
|
|
|
-- Gem: nyt flow oprettes først nu; felterne via updateRun; traktorer tildeles/fjernes; markører findes.
|
|
-- start = true: flowet startes bagefter ([Start flow]).
|
|
function SmartPickupFrame:saveFlowGuide(guide, start)
|
|
local adEnv = self.getAdEnv()
|
|
local result = ADFlowGuide.result(guide)
|
|
local runId = result.runId
|
|
local oldIds = {}
|
|
if result.isNew then
|
|
runId = ADRunsController.createRun(result.name, result.kind).id
|
|
else
|
|
local existing = ADRuns.getRun(ADRunsController.store, runId)
|
|
if existing == nil then return end
|
|
oldIds = existing.vehicleIds
|
|
end
|
|
ADRunsController.updateRun(runId, result.changes)
|
|
local added, removed = ADFlowGuide.vehicleChanges(oldIds, result.vehicleIds)
|
|
for _, id in ipairs(removed) do
|
|
local vehicle = adEnv ~= nil and ADRunsController.findVehicleById(adEnv, id) or nil
|
|
if vehicle ~= nil then
|
|
ADRunsController.unassignVehicle(vehicle)
|
|
else
|
|
ADRunsController.store = ADRuns.unassignVehicle(ADRunsController.store, id)
|
|
end
|
|
end
|
|
for _, id in ipairs(added) do
|
|
local vehicle = adEnv ~= nil and ADRunsController.findVehicleById(adEnv, id) or nil
|
|
if vehicle ~= nil then ADRunsController.assignVehicle(runId, vehicle) end
|
|
end
|
|
ADRunsController.resolveMarkers(adEnv, ADRuns.getRun(ADRunsController.store, runId))
|
|
self.selectedRunId = runId
|
|
local saved = string.format(self.i18n:getText("spu_guide_flow_saved"), tostring(result.name))
|
|
if start and adEnv ~= nil and not ADRunsController.getRunStatus(adEnv, ADRuns.getRun(ADRunsController.store, runId)).isRunning then
|
|
local started, skipped, reasons = self:summarizeStartResults(ADRunsController.startRun(adEnv, runId))
|
|
self:showOverride(saved .. " — " .. string.format(self.i18n:getText("spu_status_started"), started, skipped), reasons)
|
|
else
|
|
self:showOverride(saved)
|
|
end
|
|
ADRunsController.save()
|
|
end
|
|
|
|
-- ---- knapper og [Ret] ----
|
|
|
|
function SmartPickupFrame:onClickFlowSetup()
|
|
self:safe(function(frame)
|
|
local adEnv, run = frame.getAdEnv(), frame:getRun()
|
|
if adEnv == nil or run == nil then return end
|
|
frame:openGuide("flow", ADFlowGuide.open(run, frame:flowGuideContext(adEnv, run)))
|
|
end)
|
|
end
|
|
|
|
-- [Nyt flow] (også fra fanen Oversigt): guiden på Flows-fanen; intet oprettes før [Gem].
|
|
function SmartPickupFrame:onClickFlowNew()
|
|
self:safe(function(frame)
|
|
local adEnv = frame.getAdEnv()
|
|
if adEnv == nil then return end
|
|
local name = string.format(frame.i18n:getText("spu_newRunName"), #ADRunsController.store.runs + 1)
|
|
local guide = ADFlowGuide.openNew(name, {})
|
|
guide = ADGuide.withContext(guide, frame:flowGuideContext(adEnv, guide.draft))
|
|
if frame.currentTab ~= SmartPickupFrame.TAB_FLOWS then frame:switchTab(SmartPickupFrame.TAB_FLOWS) end
|
|
frame:openGuide("flow", guide)
|
|
end)
|
|
end
|
|
|
|
function SmartPickupFrame:openFlowStep(runId, step)
|
|
local adEnv = self.getAdEnv()
|
|
local run = ADRuns.getRun(ADRunsController.store, runId)
|
|
if adEnv == nil or run == nil then return end
|
|
self:openGuide("flow", ADFlowGuide.open(run, self:flowGuideContext(adEnv, run), {step = step, single = true, returnTo = "close"}))
|
|
end
|