feat(oversigt): 'Stop alt og parkér' — flows, markarbejde og marksilo-lån stoppes, køretøjer til AD-parkering (manuelle høstere nævnes), pause der gemmes; 'Start alle' ophæver pausen og starter traktorerne én ad gangen hvert 10. sekund (v1.42.0.0)

This commit is contained in:
2026-09-27 15:20:41 +02:00
parent 9348443f61
commit 9c1c87b8dd
12 changed files with 173 additions and 10 deletions
+10
View File
@@ -208,6 +208,7 @@ function ADFieldJobs.load()
ADFieldJobs.state.fleetMode = loaded.fleetMode or "all" ADFieldJobs.state.fleetMode = loaded.fleetMode or "all"
ADFieldJobs.state.courseRecords = loaded.courseRecords or {} ADFieldJobs.state.courseRecords = loaded.courseRecords or {}
ADFieldJobs.state.manual = loaded.manual or {} ADFieldJobs.state.manual = loaded.manual or {}
ADFieldJobs.state.paused = loaded.paused == true
else else
Logging.warning(ADFieldJobs.LOG_PREFIX .. "marker kunne ikke indlæses: %s", tostring(loaded)) Logging.warning(ADFieldJobs.LOG_PREFIX .. "marker kunne ikke indlæses: %s", tostring(loaded))
end end
@@ -252,6 +253,13 @@ function ADFieldJobs.setFleetMode(mode)
ADFieldJobs.save() ADFieldJobs.save()
end end
-- Pause (Stop alt og parkér): intet nyt sendes ud, ingen genstart efter indlæsning. Gemmes.
function ADFieldJobs.setPaused(value)
ADFieldJobs.state.paused = value == true
ADFieldJobs.save()
Logging.info(ADFieldJobs.LOG_PREFIX .. "markarbejde %s", value and "på pause" or "genoptaget")
end
function ADFieldJobs.toggleManual(vehicleId) function ADFieldJobs.toggleManual(vehicleId)
ADFieldJobs.state.manual = ADFieldFleet.toggle(ADFieldJobs.state.manual or {}, vehicleId) ADFieldJobs.state.manual = ADFieldFleet.toggle(ADFieldJobs.state.manual or {}, vehicleId)
ADFieldJobs.save() ADFieldJobs.save()
@@ -407,6 +415,8 @@ function ADFieldJobs.tick(adEnv, dt)
-- lidt efter start, og indtil da ligner de maskiner ledige (in-game 26/9: kultivatoren blev taget midt -- lidt efter start, og indtil da ligner de maskiner ledige (in-game 26/9: kultivatoren blev taget midt
-- i spillerens eget CP-job 45 s efter indlæsning) -- i spillerens eget CP-job 45 s efter indlæsning)
if ADFieldJobs.now < ADFieldJobs.STARTUP_GRACE_MS then return end if ADFieldJobs.now < ADFieldJobs.STARTUP_GRACE_MS then return end
-- Stop alt og parkér: intet sendes ud og intet genstartes, før spilleren trykker Start alle
if ADFieldJobs.state.paused then return end
if not ADFieldJobs.resumedAfterLoad then if not ADFieldJobs.resumedAfterLoad then
-- én gang, før noget nyt sendes ud: CP-maskiner der var midt i et job, fortsætter (og tæller som aktive) -- én gang, før noget nyt sendes ud: CP-maskiner der var midt i et job, fortsætter (og tæller som aktive)
ADFieldJobs.resumedAfterLoad = true ADFieldJobs.resumedAfterLoad = true
+2 -1
View File
@@ -337,7 +337,8 @@ function ADFieldSilos.planNow(adEnv)
local plan = ADFieldSiloPlanner.plan({silos = silos, stores = stores, loans = loanList(), vehicles = vehicles, local plan = ADFieldSiloPlanner.plan({silos = silos, stores = stores, loans = loanList(), vehicles = vehicles,
paused = currentPaused(), maxVehicles = cfg.maxVehicles, minLiters = cfg.minLiters}) paused = currentPaused(), maxVehicles = cfg.maxVehicles, minLiters = cfg.minLiters})
ADFieldSilos.lastPlan = plan ADFieldSilos.lastPlan = plan
if not cfg.enabled then return plan end local paused = ADFieldJobs ~= nil and ADFieldJobs.state ~= nil and ADFieldJobs.state.paused
if not cfg.enabled or paused then return plan end
local silosById, storesById = {}, {} local silosById, storesById = {}, {}
for _, silo in ipairs(silos) do silosById[silo.id] = silo end for _, silo in ipairs(silos) do silosById[silo.id] = silo end
for _, store in ipairs(stores) do storesById[store.id] = store end for _, store in ipairs(stores) do storesById[store.id] = store end
+3 -1
View File
@@ -68,6 +68,7 @@ function ADFieldStorage.save(state)
index = index + 1 index = index + 1
end end
xmlFile:setString(ADFieldStorage.ROOT .. "#fleetMode", state.fleetMode or "all") xmlFile:setString(ADFieldStorage.ROOT .. "#fleetMode", state.fleetMode or "all")
xmlFile:setInt(ADFieldStorage.ROOT .. "#paused", state.paused == true and 1 or 0)
local vehicleIndex = 0 local vehicleIndex = 0
for vehicleId in pairs(state.fleet) do for vehicleId in pairs(state.fleet) do
xmlFile:setString(string.format("%s.fleet.vehicle(%d)#id", ADFieldStorage.ROOT, vehicleIndex), vehicleId) xmlFile:setString(string.format("%s.fleet.vehicle(%d)#id", ADFieldStorage.ROOT, vehicleIndex), vehicleId)
@@ -89,12 +90,13 @@ function ADFieldStorage.save(state)
end end
function ADFieldStorage.load() function ADFieldStorage.load()
local result = {fields = {}, fleet = {}, fleetMode = "all", courseRecords = {}, manual = {}} local result = {fields = {}, fleet = {}, fleetMode = "all", courseRecords = {}, manual = {}, paused = false}
local path = ADFieldStorage.getPath() local path = ADFieldStorage.getPath()
if path == nil or not fileExists(path) then return result end if path == nil or not fileExists(path) then return result end
local xmlFile = XMLFile.load("ADSmartPickupFields", path) local xmlFile = XMLFile.load("ADSmartPickupFields", path)
if xmlFile == nil then return result end if xmlFile == nil then return result end
result.fleetMode = xmlFile:getString(ADFieldStorage.ROOT .. "#fleetMode") == "ticked" and "ticked" or "all" result.fleetMode = xmlFile:getString(ADFieldStorage.ROOT .. "#fleetMode") == "ticked" and "ticked" or "all"
result.paused = xmlFile:getInt(ADFieldStorage.ROOT .. "#paused") == 1
xmlFile:iterate(ADFieldStorage.ROOT .. ".field", function(_, key) xmlFile:iterate(ADFieldStorage.ROOT .. ".field", function(_, key)
local field = ADFieldModel.fromRecord(ADFieldStorage.readRecord(xmlFile, key)) local field = ADFieldModel.fromRecord(ADFieldStorage.readRecord(xmlFile, key))
if field.id ~= nil then result.fields[field.id] = field end if field.id ~= nil then result.fields[field.id] = field end
+15
View File
@@ -1083,6 +1083,21 @@ function ADFieldWork.windDownHelpers(adEnv, fieldId, stage)
end end
end end
-- Stop alle markarbejdets opgaver (Stop alt og parkér). Returnerer {{vehicle, manual}}; markernes trin bevares,
-- så arbejdet fortsætter efter pausen.
function ADFieldWork.stopAllAssignments(adEnv)
local stopped = {}
local list = {}
for _, assignment in pairs(ADFieldJobs.state.assignments) do table.insert(list, assignment) end
for _, assignment in ipairs(list) do
pcall(stopAd, assignment.vehicle)
pcall(ADCpBridge.stop, assignment.vehicle)
table.insert(stopped, {vehicle = assignment.vehicle, manual = assignment.manual == true})
ADFieldWork.release(assignment)
end
return stopped
end
function ADFieldWork.stopAll(adEnv, fieldId) function ADFieldWork.stopAll(adEnv, fieldId)
for _, assignment in ipairs(ADFieldJobs.assignmentsFor(fieldId)) do for _, assignment in ipairs(ADFieldJobs.assignmentsFor(fieldId)) do
pcall(stopAd, assignment.vehicle) pcall(stopAd, assignment.vehicle)
+50
View File
@@ -1153,6 +1153,56 @@ function ADRunsController.queueStartAll(adEnv)
return summary return summary
end end
-- Stop alt og parkér (Oversigt): flows, markarbejde og marksilo-lån stoppes, køretøjerne sendes til deres
-- AD-parkeringspunkt, og moden sættes på pause (gemmes), så intet starter igen før "Start alle".
-- Høstere med manuel transport parkeres ikke (må ikke køre på vejen med skærebord). Returnerer
-- {stopped, parked, noPark = {navne}, manual = {navne}}.
function ADRunsController.stopAllAndPark(adEnv)
local summary = {stopped = 0, parked = 0, noPark = {}, manual = {}}
ADRunsController.clearStartQueue()
local toPark, seen = {}, {}
local vehiclesById = getFarmVehiclesById(adEnv)
for _, run in ipairs(ADRunsController.store.runs) do
for _, vehicleId in ipairs(run.vehicleIds) do
local vehicle = vehiclesById[vehicleId]
if vehicle ~= nil and not seen[vehicle] then
seen[vehicle] = true
if isVehicleActive(vehicle) then
stopVehicle(vehicle)
summary.stopped = summary.stopped + 1
end
table.insert(toPark, vehicle)
end
end
ADRunsController.runningRuns[run.id] = nil
end
if ADFieldWork ~= nil and ADFieldWork.stopAllAssignments ~= nil then
for _, stopped in ipairs(ADFieldWork.stopAllAssignments(adEnv) or {}) do
summary.stopped = summary.stopped + 1
if stopped.manual then
table.insert(summary.manual, tostring(ADRuns.vehicleLabel(stopped.vehicle)))
elseif not seen[stopped.vehicle] then
seen[stopped.vehicle] = true
table.insert(toPark, stopped.vehicle)
end
end
end
if ADFieldSilos ~= nil and ADFieldSilos.stopAll ~= nil then pcall(ADFieldSilos.stopAll, adEnv) end
if ADFieldJobs ~= nil and ADFieldJobs.setPaused ~= nil then ADFieldJobs.setPaused(true) end
for _, vehicle in ipairs(toPark) do
local park = ADFieldWork ~= nil and ADFieldWork.parkMarkerId ~= nil and ADFieldWork.parkMarkerId(adEnv, vehicle) or nil
if park ~= nil then
local ok = pcall(ADFieldWork.startAd, adEnv, vehicle, adEnv.AutoDrive.MODE_DRIVETO, park, nil)
if ok then summary.parked = summary.parked + 1 end
else
table.insert(summary.noPark, tostring(ADRuns.vehicleLabel(vehicle)))
end
end
Logging.info(ADRunsController.LOG_PREFIX .. "Stop alt og parkér: %d stoppet, %d til parkering, %d uden parkeringspunkt, %d høstere hentes manuelt — pause",
summary.stopped, summary.parked, #summary.noPark, #summary.manual)
return summary
end
-- Starter næste traktor i køen, når der er gået STAGGER_MS siden forrige. -- Starter næste traktor i køen, når der er gået STAGGER_MS siden forrige.
function ADRunsController.processStartQueue(adEnv, dt) function ADRunsController.processStartQueue(adEnv, dt)
if #ADRunsController.startQueue == 0 then return end if #ADRunsController.startQueue == 0 then return end
+3
View File
@@ -1254,6 +1254,9 @@ function ADSmartPickup:update(dt)
if ADOutbound ~= nil and ADOutbound.releaseInactive ~= nil then if ADOutbound ~= nil and ADOutbound.releaseInactive ~= nil then
pcall(ADOutbound.releaseInactive) pcall(ADOutbound.releaseInactive)
end end
if ADRunsController ~= nil and ADRunsController.processStartQueue ~= nil then
pcall(ADRunsController.processStartQueue, getAutoDriveEnv(), dt)
end
if ADRunsController ~= nil and ADRunsController.applyVehicleNamesThrottled ~= nil then if ADRunsController ~= nil and ADRunsController.applyVehicleNamesThrottled ~= nil then
pcall(ADRunsController.applyVehicleNamesThrottled, getAutoDriveEnv(), dt) pcall(ADRunsController.applyVehicleNamesThrottled, getAutoDriveEnv(), dt)
end end
+34 -7
View File
@@ -58,7 +58,9 @@ function SmartPickupFrame.new(i18n, getAdEnv)
self.renameBuildingButtonInfo = {inputAction = InputAction.MENU_EXTRA_2, text = i18n:getText("spu_button_renameBuilding"), callback = function() self:onClickRenameBuilding() end} self.renameBuildingButtonInfo = {inputAction = InputAction.MENU_EXTRA_2, text = i18n:getText("spu_button_renameBuilding"), callback = function() self:onClickRenameBuilding() end}
self.storageButtons = {self.backButtonInfo, self.renameBuildingButtonInfo} self.storageButtons = {self.backButtonInfo, self.renameBuildingButtonInfo}
self.flowButtons = {self.backButtonInfo, self.startButtonInfo, self.newButtonInfo, self.renameButtonInfo, self.deleteButtonInfo} self.flowButtons = {self.backButtonInfo, self.startButtonInfo, self.newButtonInfo, self.renameButtonInfo, self.deleteButtonInfo}
self.overviewButtons = {self.backButtonInfo, self.startAllButtonInfo, self.stopAllButtonInfo, self.newButtonInfo} -- Stop alt og parkér: flows + markarbejde + marksilo stoppes, køretøjer til parkering, pause til Start alle
self.stopParkButtonInfo = {inputAction = InputAction.MENU_CANCEL, text = i18n:getText("spu_button_stopPark"), callback = function() self:onClickStopAndPark() end}
self.overviewButtons = {self.backButtonInfo, self.startAllButtonInfo, self.stopAllButtonInfo, self.stopParkButtonInfo, self.newButtonInfo}
-- Marker: Start nu / Stop for den valgte mark -- Marker: Start nu / Stop for den valgte mark
-- Marker: [Start nu/Stop], [Opsæt mark], [Markflåde] (gui/SmartPickupFieldGuide.lua); guidens knapper -- Marker: [Start nu/Stop], [Opsæt mark], [Markflåde] (gui/SmartPickupFieldGuide.lua); guidens knapper
self:initFieldButtons(i18n) self:initFieldButtons(i18n)
@@ -628,7 +630,15 @@ function SmartPickupFrame:refreshLive()
running, total = running + status.running, total + status.total running, total = running + status.running, total + status.total
if status.running > 0 then activeRuns = activeRuns + 1 end if status.running > 0 then activeRuns = activeRuns + 1 end
end end
self:setStatusText(self.statusOverride or string.format(self.i18n:getText("spu_status_overview"), running, total, activeRuns, #ADRunsController.store.runs)) local statusText = string.format(self.i18n:getText("spu_status_overview"), running, total, activeRuns, #ADRunsController.store.runs)
local queued = #(ADRunsController.startQueue or {})
if queued > 0 then
local totalQueued = ADRunsController.startQueueTotal or queued
statusText = string.format(self.i18n:getText("spu_status_starting"), totalQueued - queued, totalQueued)
elseif ADFieldJobs ~= nil and ADFieldJobs.state ~= nil and ADFieldJobs.state.paused then
statusText = self.i18n:getText("spu_status_paused")
end
self:setStatusText(self.statusOverride or statusText)
self.stopAllButtonInfo.disabled = running == 0 self.stopAllButtonInfo.disabled = running == 0
elseif run ~= nil then elseif run ~= nil then
self:syncOptionsFromModel(adEnv, run) self:syncOptionsFromModel(adEnv, run)
@@ -786,11 +796,28 @@ function SmartPickupFrame:onClickStartAll()
self:safe(function(frame) self:safe(function(frame)
local adEnv = frame.getAdEnv() local adEnv = frame.getAdEnv()
if adEnv == nil then return end if adEnv == nil then return end
local summary = ADRunsController.startAllRuns(adEnv) -- pausen (Stop alt og parkér) ophæves; traktorerne startes én ad gangen med mellemrum
local _, skipped, reasons = frame:summarizeStartResults(summary.results) if ADFieldJobs ~= nil and ADFieldJobs.state ~= nil and ADFieldJobs.state.paused then ADFieldJobs.setPaused(false) end
Logging.info(SmartPickupFrame.LOG_PREFIX .. "Start alle: %d flows startet (%d traktorer), %d kørte allerede, %d sprunget over", local summary = ADRunsController.queueStartAll(adEnv)
summary.runsStarted, summary.vehiclesStarted, summary.alreadyRunning, skipped) local _, skipped, reasons = frame:summarizeStartResults(summary.skipped)
frame:showOverride(string.format(frame.i18n:getText("spu_status_startedAll"), summary.runsStarted, summary.vehiclesStarted, summary.alreadyRunning, skipped), reasons) Logging.info(SmartPickupFrame.LOG_PREFIX .. "Start alle: %d traktorer i kø (én hvert %d. sekund), %d flows kørte allerede, %d sprunget over",
summary.queued, math.floor(ADRunsController.STAGGER_MS / 1000), summary.alreadyRunning, skipped)
frame:showOverride(string.format(frame.i18n:getText("spu_status_queuedAll"), summary.queued, math.floor(ADRunsController.STAGGER_MS / 1000), summary.alreadyRunning, skipped), reasons)
ADRunsController.save()
frame:requestRebuild()
end)
end
function SmartPickupFrame:onClickStopAndPark()
self:safe(function(frame)
local adEnv = frame.getAdEnv()
if adEnv == nil then return end
local summary = ADRunsController.stopAllAndPark(adEnv)
local text = string.format(frame.i18n:getText("spu_status_stopParked"), summary.stopped, summary.parked)
local notes = {}
if #summary.noPark > 0 then table.insert(notes, string.format(frame.i18n:getText("spu_status_noPark"), table.concat(summary.noPark, ", "))) end
if #summary.manual > 0 then table.insert(notes, string.format(frame.i18n:getText("spu_status_fetchManual"), table.concat(summary.manual, ", "))) end
frame:showOverride(text, notes)
ADRunsController.save() ADRunsController.save()
frame:requestRebuild() frame:requestRebuild()
end) end)
+7
View File
@@ -218,6 +218,13 @@
<text name="spu_button_new" text="Nyt flow"/> <text name="spu_button_new" text="Nyt flow"/>
<text name="spu_button_renameBuilding" text="Omdøb bygning"/> <text name="spu_button_renameBuilding" text="Omdøb bygning"/>
<text name="spu_renameBuildingTitle" text="Nyt navn på bygningen (tomt = butiksnavnet)"/> <text name="spu_renameBuildingTitle" text="Nyt navn på bygningen (tomt = butiksnavnet)"/>
<text name="spu_button_stopPark" text="Stop alt og parkér"/>
<text name="spu_status_queuedAll" text="Start alle: %d traktorer startes én ad gangen (hvert %d. sekund), %d flows kørte allerede, %d sprunget over"/>
<text name="spu_status_stopParked" text="Stop alt: %d stoppet, %d på vej til parkering — pause til Start alle"/>
<text name="spu_status_noPark" text="uden parkeringspunkt: %s"/>
<text name="spu_status_fetchManual" text="hent selv (for brede): %s"/>
<text name="spu_status_starting" text="Starter traktorer: %d af %d …"/>
<text name="spu_status_paused" text="Pause — tryk Start alle for at fortsætte"/>
<text name="spu_button_rename" text="Omdøb"/> <text name="spu_button_rename" text="Omdøb"/>
<text name="spu_button_delete" text="Slet flow"/> <text name="spu_button_delete" text="Slet flow"/>
<text name="spu_newRunName" text="Flow %d"/> <text name="spu_newRunName" text="Flow %d"/>
+7
View File
@@ -218,6 +218,13 @@
<text name="spu_button_new" text="New flow"/> <text name="spu_button_new" text="New flow"/>
<text name="spu_button_renameBuilding" text="Rename building"/> <text name="spu_button_renameBuilding" text="Rename building"/>
<text name="spu_renameBuildingTitle" text="New name for the building (empty = shop name)"/> <text name="spu_renameBuildingTitle" text="New name for the building (empty = shop name)"/>
<text name="spu_button_stopPark" text="Stop all and park"/>
<text name="spu_status_queuedAll" text="Start all: %d tractors start one at a time (every %d seconds), %d flows already running, %d skipped"/>
<text name="spu_status_stopParked" text="Stop all: %d stopped, %d driving to parking — paused until Start all"/>
<text name="spu_status_noPark" text="no park destination: %s"/>
<text name="spu_status_fetchManual" text="fetch yourself (too wide): %s"/>
<text name="spu_status_starting" text="Starting tractors: %d of %d …"/>
<text name="spu_status_paused" text="Paused — press Start all to continue"/>
<text name="spu_button_rename" text="Rename"/> <text name="spu_button_rename" text="Rename"/>
<text name="spu_button_delete" text="Delete flow"/> <text name="spu_button_delete" text="Delete flow"/>
<text name="spu_newRunName" text="Flow %d"/> <text name="spu_newRunName" text="Flow %d"/>
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?> <?xml version="1.0" encoding="utf-8" standalone="no"?>
<modDesc descVersion="107"> <modDesc descVersion="107">
<author>masterdraco</author> <author>masterdraco</author>
<version>1.41.1.0</version> <version>1.42.0.0</version>
<title> <title>
<en>AD Smart Pickup</en> <en>AD Smart Pickup</en>
</title> </title>
+8
View File
@@ -98,5 +98,13 @@ ADFieldStorage.save({fields = {}, fleet = {}, fleetMode = "all", manual = {vehic
check("ST8 manuel transport indlæst", ADFieldStorage.load().manual.vehicleCombine, true) check("ST8 manuel transport indlæst", ADFieldStorage.load().manual.vehicleCombine, true)
check("ST8 gammel fil: ingen manuelle", next(old.manual or {}), nil) check("ST8 gammel fil: ingen manuelle", next(old.manual or {}), nil)
-- ST9: pause ("Stop alt og parkér") gemmes, så intet starter af sig selv efter indlæsning
disk = {}
ADFieldStorage.save({fields = {}, fleet = {}, fleetMode = "all", paused = true})
check("ST9 pause indlæst", ADFieldStorage.load().paused, true)
disk = {}
ADFieldStorage.save({fields = {}, fleet = {}, fleetMode = "all"})
check("ST9 ingen pause", ADFieldStorage.load().paused, false)
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1) os.exit(failures == 0 and 0 or 1)
+33
View File
@@ -863,5 +863,38 @@ do
check("C20 run markeret kørende", ADRunsController.runningRuns[qrun.id], true) check("C20 run markeret kørende", ADRunsController.runningRuns[qrun.id], true)
end end
-- C21: Stop alt og parkér — stopper flow-traktorerne, sender dem til AD-parkering, sætter pause
do
buildWorld()
local p1 = makeVehicle("vehicleP1", "P1", {STRAW, TMR}, 1000000, 100, 0)
local p2 = makeVehicle("vehicleP2", "P2", {STRAW, TMR}, 1000000, 110, 0)
local prun = ADRunsController.createRun("Park")
ADRunsController.updateRun(prun.id, {targetWayPointIds = {94}})
ADRunsController.assignVehicle(prun.id, p1)
ADRunsController.assignVehicle(prun.id, p2)
ADRunsController.startRun(adEnv, prun.id)
local parked, paused = {}, nil
local oldWork, oldJobs, oldSilos = ADFieldWork, ADFieldJobs, ADFieldSilos
ADFieldWork = {
parkMarkerId = function(_, v) return v == p1 and 700 or nil end,
startAd = function(_, v, mode, first) parked[v] = first end,
stopAllAssignments = function() return {} end,
}
ADFieldJobs = {setPaused = function(value) paused = value end}
ADFieldSilos = {stopAll = function() end}
ADRunsController.queueStartAll(adEnv)
local summary = ADRunsController.stopAllAndPark(adEnv)
check("C21 begge stoppet", (p1.stopped or 0) >= 1 and (p2.stopped or 0) >= 1, true)
check("C21 P1 kører til parkering", parked[p1], 700)
check("C21 P2 uden parkering bliver stående", parked[p2], nil)
check("C21 tæller parkerede", summary.parked, 1)
check("C21 nævner dem uden parkering", summary.noPark[1], "P2")
check("C21 pause sat", paused, true)
check("C21 startkø tømt", #ADRunsController.startQueue, 0)
check("C21 run ikke længere kørende", ADRunsController.runningRuns[prun.id], nil)
ADFieldWork, ADFieldJobs, ADFieldSilos = oldWork, oldJobs, oldSilos
end
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1) os.exit(failures == 0 and 0 or 1)