feat(markarbejde): manuel transport af brede høstere — flueben pr. høster i markflåden; moden beder spilleren køre den til marken og montere skærebordet (dialog + påmindelse hvert 5. min), overtager når den står på marken med passende skærebord og spilleren er steget ud (eller ved Start nu), tømmevogne først når høsten kører, ingen AD-parkering bagefter (v1.38.0.0)
This commit is contained in:
@@ -16,7 +16,8 @@ ADFieldJobs.tickCount = 0
|
|||||||
ADFieldJobs.MAX_PASSES = 2
|
ADFieldJobs.MAX_PASSES = 2
|
||||||
-- fleetMode: "all" = alle ledige maskiner (standard, "vælg og glem"), "ticked" = kun med flueben
|
-- fleetMode: "all" = alle ledige maskiner (standard, "vælg og glem"), "ticked" = kun med flueben
|
||||||
-- courseRecords: vehicleId -> post i kursus-registret (ADCourseCache)
|
-- courseRecords: vehicleId -> post i kursus-registret (ADCourseCache)
|
||||||
ADFieldJobs.state = {fields = {}, fleet = {}, assignments = {}, fleetMode = "all", courseRecords = {}}
|
-- manual: {[vehicleId] = true} = høstere spilleren selv kører til marken (for brede til vejene)
|
||||||
|
ADFieldJobs.state = {fields = {}, fleet = {}, assignments = {}, fleetMode = "all", courseRecords = {}, manual = {}}
|
||||||
-- mark-id -> {mower = kursus, rake = kursus, <trin> = fælles multi-tool-kursus}: kopier (kun i hukommelsen;
|
-- mark-id -> {mower = kursus, rake = kursus, <trin> = fælles multi-tool-kursus}: kopier (kun i hukommelsen;
|
||||||
-- efter genindlæsning hentes slå-/rivekurset fra maskinen, som CP selv gemmer kurset på)
|
-- efter genindlæsning hentes slå-/rivekurset fra maskinen, som CP selv gemmer kurset på)
|
||||||
ADFieldJobs.courses = {}
|
ADFieldJobs.courses = {}
|
||||||
@@ -26,7 +27,8 @@ ADFieldJobs.timer = 500
|
|||||||
ADFieldJobs.now = 0
|
ADFieldJobs.now = 0
|
||||||
ADFieldJobs.loaded = false
|
ADFieldJobs.loaded = false
|
||||||
|
|
||||||
ADFieldJobs.ACTIVE_PHASES = {driving = true, starting = true, waitingCourse = true, working = true}
|
-- awaitingPlayer: høster med manuel transport, spilleren kører den til marken (tæller som i gang)
|
||||||
|
ADFieldJobs.ACTIVE_PHASES = {driving = true, starting = true, waitingCourse = true, working = true, awaitingPlayer = true}
|
||||||
|
|
||||||
-- Andel græs i mellemhøjde (høstbart, men halv ydelse) der får en afbrudt slåning til at vente.
|
-- Andel græs i mellemhøjde (høstbart, men halv ydelse) der får en afbrudt slåning til at vente.
|
||||||
ADFieldJobs.REGROW_RATIO = 0.1
|
ADFieldJobs.REGROW_RATIO = 0.1
|
||||||
@@ -45,7 +47,7 @@ local function cropGone(stage, info)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Ligger (x, z) inden for omridset? (lige-ulige-reglen; kanten tæller som inde)
|
-- Ligger (x, z) inden for omridset? (lige-ulige-reglen; kanten tæller som inde)
|
||||||
local function insidePolygon(x, z, verts)
|
function ADFieldJobs.insidePolygon(x, z, verts)
|
||||||
local inside, j = false, #verts
|
local inside, j = false, #verts
|
||||||
for i = 1, #verts do
|
for i = 1, #verts do
|
||||||
local a, b = verts[i], verts[j]
|
local a, b = verts[i], verts[j]
|
||||||
@@ -59,7 +61,7 @@ end
|
|||||||
-- fields = {{id, stage, verts = {{x, z}}}}
|
-- fields = {{id, stage, verts = {{x, z}}}}
|
||||||
function ADFieldJobs.resumeField(x, z, role, fields)
|
function ADFieldJobs.resumeField(x, z, role, fields)
|
||||||
for _, field in ipairs(fields or {}) do
|
for _, field in ipairs(fields or {}) do
|
||||||
if #(field.verts or {}) >= 3 and ADFieldModel.roleFor(field.stage) == role and insidePolygon(x, z, field.verts) then
|
if #(field.verts or {}) >= 3 and ADFieldModel.roleFor(field.stage) == role and ADFieldJobs.insidePolygon(x, z, field.verts) then
|
||||||
return field.id
|
return field.id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -104,7 +106,7 @@ function ADFieldJobs.decide(field, info, assignments, now, env)
|
|||||||
if not hasMarker then return {action = "wait", care = care} end
|
if not hasMarker then return {action = "wait", care = care} end
|
||||||
return {action = "care", stage = care}
|
return {action = "care", stage = care}
|
||||||
end
|
end
|
||||||
local active, finished, helpers = 0, 0, 0
|
local active, finished, helpers, awaiting = 0, 0, 0, 0
|
||||||
for _, assignment in ipairs(assignments) do
|
for _, assignment in ipairs(assignments) do
|
||||||
if assignment.stage == nil or assignment.stage == field.stage then
|
if assignment.stage == nil or assignment.stage == field.stage then
|
||||||
local isActive = ADFieldJobs.ACTIVE_PHASES[assignment.phase]
|
local isActive = ADFieldJobs.ACTIVE_PHASES[assignment.phase]
|
||||||
@@ -112,6 +114,7 @@ function ADFieldJobs.decide(field, info, assignments, now, env)
|
|||||||
if isActive then helpers = helpers + 1 end
|
if isActive then helpers = helpers + 1 end
|
||||||
else
|
else
|
||||||
if isActive then active = active + 1 end
|
if isActive then active = active + 1 end
|
||||||
|
if assignment.phase == "awaitingPlayer" then awaiting = awaiting + 1 end
|
||||||
if assignment.phase == "finished" then finished = finished + 1 end
|
if assignment.phase == "finished" then finished = finished + 1 end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -138,7 +141,8 @@ function ADFieldJobs.decide(field, info, assignments, now, env)
|
|||||||
end
|
end
|
||||||
-- hovedsættene arbejder: fyld op med hjælpere (aflæsningsvogne) en ad gangen
|
-- hovedsættene arbejder: fyld op med hjælpere (aflæsningsvogne) en ad gangen
|
||||||
local helperRole = ADFieldModel.helperFor(field.stage)
|
local helperRole = ADFieldModel.helperFor(field.stage)
|
||||||
if helperRole ~= nil and helpers < ADFieldModel.maxHelpers(field.stage, field.plan) and hasMarker and (field.retryAt or 0) <= now then
|
-- tømmevogne først når en høster faktisk er i gang (ikke mens spilleren kører den derud)
|
||||||
|
if helperRole ~= nil and active > awaiting and helpers < ADFieldModel.maxHelpers(field.stage, field.plan) and hasMarker and (field.retryAt or 0) <= now then
|
||||||
return {action = "dispatch", role = helperRole, count = 1, helper = true}
|
return {action = "dispatch", role = helperRole, count = 1, helper = true}
|
||||||
end
|
end
|
||||||
return {action = "none"}
|
return {action = "none"}
|
||||||
@@ -182,6 +186,7 @@ function ADFieldJobs.load()
|
|||||||
ADFieldJobs.state.fields, ADFieldJobs.state.fleet = loaded.fields, loaded.fleet
|
ADFieldJobs.state.fields, ADFieldJobs.state.fleet = loaded.fields, loaded.fleet
|
||||||
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 {}
|
||||||
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
|
||||||
@@ -193,6 +198,20 @@ function ADFieldJobs.setPlan(id, changes)
|
|||||||
ADFieldJobs.save()
|
ADFieldJobs.save()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- "Start nu" på en mark hvor moden venter på spilleren (manuel transport): overtag uden at vente
|
||||||
|
ADFieldJobs.takeoverRequested = {}
|
||||||
|
function ADFieldJobs.requestTakeover(id)
|
||||||
|
ADFieldJobs.takeoverRequested[id] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Venter moden på at spilleren kører en høster til marken? (assignment eller nil)
|
||||||
|
function ADFieldJobs.awaitingPlayer(fieldId)
|
||||||
|
for _, assignment in pairs(ADFieldJobs.state.assignments) do
|
||||||
|
if assignment.fieldId == fieldId and assignment.phase == "awaitingPlayer" then return assignment end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
function ADFieldJobs.requestStart(id)
|
function ADFieldJobs.requestStart(id)
|
||||||
ADFieldJobs.note(id, {startRequested = true})
|
ADFieldJobs.note(id, {startRequested = true})
|
||||||
end
|
end
|
||||||
@@ -212,6 +231,11 @@ function ADFieldJobs.setFleetMode(mode)
|
|||||||
ADFieldJobs.save()
|
ADFieldJobs.save()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function ADFieldJobs.toggleManual(vehicleId)
|
||||||
|
ADFieldJobs.state.manual = ADFieldFleet.toggle(ADFieldJobs.state.manual or {}, vehicleId)
|
||||||
|
ADFieldJobs.save()
|
||||||
|
end
|
||||||
|
|
||||||
function ADFieldJobs.toggleFleet(vehicleId)
|
function ADFieldJobs.toggleFleet(vehicleId)
|
||||||
ADFieldJobs.state.fleet = ADFieldFleet.toggle(ADFieldJobs.state.fleet, vehicleId)
|
ADFieldJobs.state.fleet = ADFieldFleet.toggle(ADFieldJobs.state.fleet, vehicleId)
|
||||||
ADFieldJobs.save()
|
ADFieldJobs.save()
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ function ADFieldStorage.save(state)
|
|||||||
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)
|
||||||
vehicleIndex = vehicleIndex + 1
|
vehicleIndex = vehicleIndex + 1
|
||||||
end
|
end
|
||||||
|
local manualIndex = 0
|
||||||
|
for vehicleId in pairs(state.manual or {}) do
|
||||||
|
xmlFile:setString(string.format("%s.manual.vehicle(%d)#id", ADFieldStorage.ROOT, manualIndex), vehicleId)
|
||||||
|
manualIndex = manualIndex + 1
|
||||||
|
end
|
||||||
local courseIndex = 0
|
local courseIndex = 0
|
||||||
for _, record in pairs(state.courseRecords or {}) do
|
for _, record in pairs(state.courseRecords or {}) do
|
||||||
ADFieldStorage.writeCourseRecord(xmlFile, string.format("%s.courses.course(%d)", ADFieldStorage.ROOT, courseIndex), record)
|
ADFieldStorage.writeCourseRecord(xmlFile, string.format("%s.courses.course(%d)", ADFieldStorage.ROOT, courseIndex), record)
|
||||||
@@ -84,7 +89,7 @@ function ADFieldStorage.save(state)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function ADFieldStorage.load()
|
function ADFieldStorage.load()
|
||||||
local result = {fields = {}, fleet = {}, fleetMode = "all", courseRecords = {}}
|
local result = {fields = {}, fleet = {}, fleetMode = "all", courseRecords = {}, manual = {}}
|
||||||
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)
|
||||||
@@ -98,6 +103,10 @@ function ADFieldStorage.load()
|
|||||||
local id = xmlFile:getString(key .. "#id")
|
local id = xmlFile:getString(key .. "#id")
|
||||||
if id ~= nil and id ~= "" then result.fleet[id] = true end
|
if id ~= nil and id ~= "" then result.fleet[id] = true end
|
||||||
end)
|
end)
|
||||||
|
xmlFile:iterate(ADFieldStorage.ROOT .. ".manual.vehicle", function(_, key)
|
||||||
|
local id = xmlFile:getString(key .. "#id")
|
||||||
|
if id ~= nil and id ~= "" then result.manual[id] = true end
|
||||||
|
end)
|
||||||
xmlFile:iterate(ADFieldStorage.ROOT .. ".courses.course", function(_, key)
|
xmlFile:iterate(ADFieldStorage.ROOT .. ".courses.course", function(_, key)
|
||||||
local record = ADCourseCache ~= nil and ADCourseCache.newRecord(ADFieldStorage.readCourseRecord(xmlFile, key)) or nil
|
local record = ADCourseCache ~= nil and ADCourseCache.newRecord(ADFieldStorage.readCourseRecord(xmlFile, key)) or nil
|
||||||
if record ~= nil then result.courseRecords[record.vehicle] = record end
|
if record ~= nil then result.courseRecords[record.vehicle] = record end
|
||||||
|
|||||||
@@ -138,6 +138,8 @@ function ADFieldWork.getRigs(adEnv)
|
|||||||
busy = state.assignments[id] ~= nil or isAdActive(vehicle) or ADCpBridge.isWorking(vehicle)
|
busy = state.assignments[id] ~= nil or isAdActive(vehicle) or ADCpBridge.isWorking(vehicle)
|
||||||
or (ADFieldSilos ~= nil and ADFieldSilos.isLoaned(vehicle)),
|
or (ADFieldSilos ~= nil and ADFieldSilos.isLoaned(vehicle)),
|
||||||
controlled = isControlledByPlayer(vehicle),
|
controlled = isControlledByPlayer(vehicle),
|
||||||
|
-- manuel transport: spilleren kører den til marken (for bred til vejene med skærebord)
|
||||||
|
manual = (state.manual or {})[id] == true,
|
||||||
width = ADCpBridge.getWorkWidth(vehicle), x = x, z = z,
|
width = ADCpBridge.getWorkWidth(vehicle), x = x, z = z,
|
||||||
-- tom spreder kan flere ting (gødning og kalk): alle dens roller
|
-- tom spreder kan flere ting (gødning og kalk): alle dens roller
|
||||||
roles = specs.sprayRoles, filledRole = specs.filledRole, dumpable = specs.dumpable,
|
roles = specs.sprayRoles, filledRole = specs.filledRole, dumpable = specs.dumpable,
|
||||||
@@ -300,7 +302,7 @@ end
|
|||||||
local function acceptFor(field, info, role)
|
local function acceptFor(field, info, role)
|
||||||
if role == "harvester" then
|
if role == "harvester" then
|
||||||
local fruit = info.fruitIndex
|
local fruit = info.fruitIndex
|
||||||
return function(candidate) return fruit ~= nil and candidate.fruits ~= nil and candidate.fruits[fruit] == true end
|
return function(candidate) return ADManualTransport.acceptsHarvester(candidate, fruit) end
|
||||||
elseif role == "seeder" then
|
elseif role == "seeder" then
|
||||||
local fruitIndex = ADFieldWork.sowFruitIndex(field)
|
local fruitIndex = ADFieldWork.sowFruitIndex(field)
|
||||||
return function(candidate) return candidate.hasSeeds and fruitIndex ~= nil and candidate.seedFruits[fruitIndex] == true end
|
return function(candidate) return candidate.hasSeeds and fruitIndex ~= nil and candidate.seedFruits[fruitIndex] == true end
|
||||||
@@ -351,6 +353,19 @@ local function refillPlan(adEnv, fieldId, vehicle, role, x, z)
|
|||||||
return {fillType = fillType, empty = empty, refillId = refillId}
|
return {fillType = fillType, empty = empty, refillId = refillId}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Manuel transport: bed spilleren køre høsteren til marken (dialog første gang, ellers besked i hjørnet).
|
||||||
|
local function askPlayer(field, info, assignment, withDialog)
|
||||||
|
local text = string.format("F%s skal høstes: kør '%s' til %s, montér skærebordet og stig ud — så overtager Smart Pickup",
|
||||||
|
tostring(field.id), ADRuns.vehicleLabel(assignment.vehicle), tostring(info.markerName or ("F" .. tostring(field.id))))
|
||||||
|
assignment.remindedAt = now()
|
||||||
|
log(field.id, "venter på spilleren: %s", text)
|
||||||
|
if withDialog and InfoDialog ~= nil and InfoDialog.show ~= nil then
|
||||||
|
pcall(InfoDialog.show, "Smart Pickup: " .. text)
|
||||||
|
else
|
||||||
|
ADFieldJobs.notify(text, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function ADFieldWork.dispatch(adEnv, field, info, decision)
|
function ADFieldWork.dispatch(adEnv, field, info, decision)
|
||||||
local role = decision.role
|
local role = decision.role
|
||||||
local ok, reason = preflight(field, role)
|
local ok, reason = preflight(field, role)
|
||||||
@@ -409,26 +424,34 @@ function ADFieldWork.dispatch(adEnv, field, info, decision)
|
|||||||
groupSize = decision.helper and 1 or count, lane = count > 1 and lanes[index] or nil, leader = index == 1,
|
groupSize = decision.helper and 1 or count, lane = count > 1 and lanes[index] or nil, leader = index == 1,
|
||||||
fillType = decision.helper and info.harvestFillType or nil,
|
fillType = decision.helper and info.harvestFillType or nil,
|
||||||
}
|
}
|
||||||
local refill = refillPlan(adEnv, field.id, rig.vehicle, role, info.x, info.z)
|
if role == "harvester" and rig.manual and not assignment.helper then
|
||||||
if refill ~= nil and refill.empty and refill.refillId == nil then
|
-- for bred til vejene: spilleren kører den selv til marken og monterer skærebordet
|
||||||
-- tom og intet sted at fylde op: ud på marken ville den bare køre kurset uden at sprede
|
assignment.phase, assignment.manual = "awaitingPlayer", true
|
||||||
fail(field.id, string.format("'%s' er tom for %s og der er ingen påfyldning med AutoDrive-markør — fyld den op", rig.label, fillTypeName(refill.fillType)))
|
assignment.startX, assignment.startZ = rig.x, rig.z
|
||||||
return
|
ADFieldJobs.state.assignments[rig.id] = assignment
|
||||||
end
|
askPlayer(field, info, assignment, true)
|
||||||
assignment.startX, assignment.startZ = rig.x, rig.z
|
|
||||||
ADFieldJobs.state.assignments[rig.id] = assignment
|
|
||||||
if refill ~= nil and refill.empty then
|
|
||||||
-- AutoDrive LOAD: påfyldningen (2. markør), fyld op, videre til F-markøren (1.) — så Courseplay
|
|
||||||
startAd(adEnv, rig.vehicle, adEnv.AutoDrive.MODE_LOAD, info.markerId, refill.refillId, refill.fillType)
|
|
||||||
assignment.drive = {mode = adEnv.AutoDrive.MODE_LOAD, first = info.markerId, second = refill.refillId, fillType = refill.fillType}
|
|
||||||
local marker = adEnv.ADGraphManager:getMapMarkerByWayPointId(refill.refillId)
|
|
||||||
log(field.id, "%s '%s' er tom — fyldes med %s ved %s og kører så til %s", role, rig.label, fillTypeName(refill.fillType),
|
|
||||||
tostring(marker ~= nil and marker.name or refill.refillId), tostring(info.markerName))
|
|
||||||
else
|
else
|
||||||
startAd(adEnv, rig.vehicle, adEnv.AutoDrive.MODE_DRIVETO, info.markerId, nil)
|
local refill = refillPlan(adEnv, field.id, rig.vehicle, role, info.x, info.z)
|
||||||
assignment.drive = {mode = adEnv.AutoDrive.MODE_DRIVETO, first = info.markerId}
|
if refill ~= nil and refill.empty and refill.refillId == nil then
|
||||||
log(field.id, "%s '%s' sendt til %s (%.1f m%s)", role, rig.label, tostring(info.markerName), rig.width or 0,
|
-- tom og intet sted at fylde op: ud på marken ville den bare køre kurset uden at sprede
|
||||||
assignment.lane ~= nil and string.format(", bane %d", assignment.lane) or "")
|
fail(field.id, string.format("'%s' er tom for %s og der er ingen påfyldning med AutoDrive-markør — fyld den op", rig.label, fillTypeName(refill.fillType)))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
assignment.startX, assignment.startZ = rig.x, rig.z
|
||||||
|
ADFieldJobs.state.assignments[rig.id] = assignment
|
||||||
|
if refill ~= nil and refill.empty then
|
||||||
|
-- AutoDrive LOAD: påfyldningen (2. markør), fyld op, videre til F-markøren (1.) — så Courseplay
|
||||||
|
startAd(adEnv, rig.vehicle, adEnv.AutoDrive.MODE_LOAD, info.markerId, refill.refillId, refill.fillType)
|
||||||
|
assignment.drive = {mode = adEnv.AutoDrive.MODE_LOAD, first = info.markerId, second = refill.refillId, fillType = refill.fillType}
|
||||||
|
local marker = adEnv.ADGraphManager:getMapMarkerByWayPointId(refill.refillId)
|
||||||
|
log(field.id, "%s '%s' er tom — fyldes med %s ved %s og kører så til %s", role, rig.label, fillTypeName(refill.fillType),
|
||||||
|
tostring(marker ~= nil and marker.name or refill.refillId), tostring(info.markerName))
|
||||||
|
else
|
||||||
|
startAd(adEnv, rig.vehicle, adEnv.AutoDrive.MODE_DRIVETO, info.markerId, nil)
|
||||||
|
assignment.drive = {mode = adEnv.AutoDrive.MODE_DRIVETO, first = info.markerId}
|
||||||
|
log(field.id, "%s '%s' sendt til %s (%.1f m%s)", role, rig.label, tostring(info.markerName), rig.width or 0,
|
||||||
|
assignment.lane ~= nil and string.format(", bane %d", assignment.lane) or "")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
note(field.id, {reason = false})
|
note(field.id, {reason = false})
|
||||||
@@ -790,14 +813,53 @@ local function finishAssignment(adEnv, assignment)
|
|||||||
end
|
end
|
||||||
log(assignment.fieldId, "%s '%s' færdig", assignment.role, ADRuns.vehicleLabel(vehicle))
|
log(assignment.fieldId, "%s '%s' færdig", assignment.role, ADRuns.vehicleLabel(vehicle))
|
||||||
-- læssevogn/påfyldte sæt parkeres af AutoDrive selv (onCpFinished med parkering sat)
|
-- læssevogn/påfyldte sæt parkeres af AutoDrive selv (onCpFinished med parkering sat)
|
||||||
local park = not assignment.adHandlesEnd and parkMarkerId(adEnv, vehicle) or nil
|
-- manuel transport: ALDRIG ud på vejen med AutoDrive (skærebordet sidder på) — spilleren henter den
|
||||||
|
local park = not assignment.adHandlesEnd and not assignment.manual and parkMarkerId(adEnv, vehicle) or nil
|
||||||
if park ~= nil then startAd(adEnv, vehicle, adEnv.AutoDrive.MODE_DRIVETO, park, nil) end
|
if park ~= nil then startAd(adEnv, vehicle, adEnv.AutoDrive.MODE_DRIVETO, park, nil) end
|
||||||
|
if assignment.manual then
|
||||||
|
ADFieldJobs.notify(string.format("F%s høstet — afmontér skærebordet og kør '%s' hjem", tostring(assignment.fieldId), ADRuns.vehicleLabel(vehicle)), true)
|
||||||
|
end
|
||||||
restoreToolOffset(assignment)
|
restoreToolOffset(assignment)
|
||||||
assignment.phase = "finished"
|
assignment.phase = "finished"
|
||||||
table.insert(ADFieldJobs.finished, assignment)
|
table.insert(ADFieldJobs.finished, assignment)
|
||||||
ADFieldJobs.state.assignments[assignment.vehicleId] = nil
|
ADFieldJobs.state.assignments[assignment.vehicleId] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local MANUAL_REASON_TEXT = {
|
||||||
|
notThere = "kør den til marken",
|
||||||
|
noHeader = "montér skærebordet",
|
||||||
|
wrongHeader = "skærebordet kan ikke høste afgrøden — montér det rigtige",
|
||||||
|
playerInside = "stig ud, så overtager Smart Pickup",
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Manuel transport: overtag når høsteren står på marken med passende skærebord og spilleren er steget ud
|
||||||
|
-- (eller når spilleren trykker "Start nu"); påmind hvert 5. minut indtil da.
|
||||||
|
local function followManual(adEnv, field, info, assignment)
|
||||||
|
if field == nil or info == nil then return ADFieldWork.release(assignment) end
|
||||||
|
local vehicle = assignment.vehicle
|
||||||
|
local x, z = vehiclePosition(vehicle)
|
||||||
|
local atField = #(info.verts or {}) >= 3 and ADFieldJobs.insidePolygon(x, z, info.verts)
|
||||||
|
if not atField and info.markerId ~= nil then
|
||||||
|
local wayPoint = adEnv.ADGraphManager:getWayPointById(info.markerId)
|
||||||
|
atField = wayPoint ~= nil and math.sqrt((wayPoint.x - x) ^ 2 + (wayPoint.z - z) ^ 2) <= ADFieldWork.ARRIVE_DISTANCE
|
||||||
|
end
|
||||||
|
local forced = ADFieldJobs.takeoverRequested[field.id] == true
|
||||||
|
ADFieldJobs.takeoverRequested[field.id] = nil
|
||||||
|
local ok, why = ADManualTransport.readiness({atField = atField, fruits = ADCpBridge.getHarvestFruits(vehicle) or {},
|
||||||
|
fruit = info.fruitIndex, controlled = isControlledByPlayer(vehicle), forced = forced})
|
||||||
|
if ok then
|
||||||
|
log(field.id, "overtager '%s'%s", ADRuns.vehicleLabel(vehicle), forced and " (Start nu)" or "")
|
||||||
|
return beginWork(adEnv, field, info, assignment)
|
||||||
|
end
|
||||||
|
local reason = MANUAL_REASON_TEXT[why] or tostring(why)
|
||||||
|
note(field.id, {reason = {text = string.format("venter på dig: '%s' — %s", ADRuns.vehicleLabel(vehicle), reason)}})
|
||||||
|
if forced then
|
||||||
|
ADFieldJobs.notify(string.format("F%s: kan ikke starte '%s' endnu — %s", tostring(field.id), ADRuns.vehicleLabel(vehicle), reason), true)
|
||||||
|
elseif ADManualTransport.shouldRemind(assignment.remindedAt, now()) then
|
||||||
|
askPlayer(field, info, assignment, false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function followWorking(adEnv, field, assignment)
|
local function followWorking(adEnv, field, assignment)
|
||||||
local vehicle = assignment.vehicle
|
local vehicle = assignment.vehicle
|
||||||
if assignment.role == "rake" and field.windrowOffset == nil and now() - assignment.since >= ADFieldWork.WINDROW_MEASURE_MS
|
if assignment.role == "rake" and field.windrowOffset == nil and now() - assignment.since >= ADFieldWork.WINDROW_MEASURE_MS
|
||||||
@@ -859,7 +921,7 @@ function ADFieldWork.resumeAfterLoad(adEnv)
|
|||||||
if fieldId ~= nil then
|
if fieldId ~= nil then
|
||||||
ADFieldJobs.state.assignments[rig.id] = {vehicleId = rig.id, vehicle = vehicle, fieldId = fieldId, role = rig.role,
|
ADFieldJobs.state.assignments[rig.id] = {vehicleId = rig.id, vehicle = vehicle, fieldId = fieldId, role = rig.role,
|
||||||
stage = stageById[fieldId], helper = false, phase = "working", since = now(), width = rig.width,
|
stage = stageById[fieldId], helper = false, phase = "working", since = now(), width = rig.width,
|
||||||
groupSize = 1, leader = true, resumed = true}
|
groupSize = 1, leader = true, resumed = true, manual = rig.manual == true}
|
||||||
-- lager til læssevognens rest, som ved en normal start
|
-- lager til læssevognens rest, som ved en normal start
|
||||||
local assignment = ADFieldJobs.state.assignments[rig.id]
|
local assignment = ADFieldJobs.state.assignments[rig.id]
|
||||||
local field, info = ADFieldJobs.getField(fieldId), ADFields.getInfo(fieldId)
|
local field, info = ADFieldJobs.getField(fieldId), ADFields.getInfo(fieldId)
|
||||||
@@ -886,7 +948,7 @@ function ADFieldWork.follow(adEnv, assignment)
|
|||||||
-- førersædet og kigge må ikke slippe det (in-game 25/9).
|
-- førersædet og kigge må ikke slippe det (in-game 25/9).
|
||||||
local steeredByAi = ADCpBridge.isWorking(vehicle) or isAdActive(vehicle) or assignment.phase == "starting"
|
local steeredByAi = ADCpBridge.isWorking(vehicle) or isAdActive(vehicle) or assignment.phase == "starting"
|
||||||
local speed = vehicle.getLastSpeed ~= nil and vehicle:getLastSpeed() or 0
|
local speed = vehicle.getLastSpeed ~= nil and vehicle:getLastSpeed() or 0
|
||||||
if isControlledByPlayer(vehicle) and not steeredByAi and speed > ADFieldWork.PLAYER_DRIVING_KMH then
|
if assignment.phase ~= "awaitingPlayer" and isControlledByPlayer(vehicle) and not steeredByAi and speed > ADFieldWork.PLAYER_DRIVING_KMH then
|
||||||
log(assignment.fieldId, "'%s' frigivet — spilleren kører det", ADRuns.vehicleLabel(vehicle))
|
log(assignment.fieldId, "'%s' frigivet — spilleren kører det", ADRuns.vehicleLabel(vehicle))
|
||||||
return ADFieldWork.release(assignment)
|
return ADFieldWork.release(assignment)
|
||||||
end
|
end
|
||||||
@@ -935,6 +997,8 @@ function ADFieldWork.follow(adEnv, assignment)
|
|||||||
end
|
end
|
||||||
elseif assignment.phase == "working" then
|
elseif assignment.phase == "working" then
|
||||||
followWorking(adEnv, field, assignment)
|
followWorking(adEnv, field, assignment)
|
||||||
|
elseif assignment.phase == "awaitingPlayer" then
|
||||||
|
followManual(adEnv, field, info, assignment)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
-- AD Manual Transport
|
||||||
|
-- Brede høstere (mejetærsker med skærebord) kan ikke køre på vejene: spilleren kører dem til marken, monterer
|
||||||
|
-- skærebordet og stiger ud; moden overtager derfra. Rene regler (testbare uden spillet); spil-delen ligger i
|
||||||
|
-- adFieldWork.
|
||||||
|
|
||||||
|
ADManualTransport = {}
|
||||||
|
|
||||||
|
ADManualTransport.REMIND_MS = 300000 -- påmindelse hvert 5. minut, mens moden venter på spilleren
|
||||||
|
|
||||||
|
-- Må høsteren vælges til marken? Manuel: ja — skærebordet monteres først på marken (tjekkes ved overtagelse).
|
||||||
|
-- Ellers skal det monterede skærebord kunne tage afgrøden.
|
||||||
|
function ADManualTransport.acceptsHarvester(candidate, fruit)
|
||||||
|
if fruit == nil then return false end
|
||||||
|
if candidate.manual then return true end
|
||||||
|
return candidate.fruits ~= nil and candidate.fruits[fruit] == true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Klar til overtagelse? s = {atField, fruits = {[fruit] = true}, fruit, controlled, forced}.
|
||||||
|
-- Returnerer true, eller false + grund: "notThere" | "noHeader" | "wrongHeader" | "playerInside".
|
||||||
|
-- forced ("Start nu"): sted og spiller springes over, skærebordet tjekkes stadig.
|
||||||
|
function ADManualTransport.readiness(s)
|
||||||
|
if not s.forced and not s.atField then return false, "notThere" end
|
||||||
|
local fruits = s.fruits or {}
|
||||||
|
if next(fruits) == nil then return false, "noHeader" end
|
||||||
|
if s.fruit == nil or not fruits[s.fruit] then return false, "wrongHeader" end
|
||||||
|
if not s.forced and s.controlled then return false, "playerInside" end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function ADManualTransport.shouldRemind(lastAt, now)
|
||||||
|
return lastAt == nil or now - lastAt >= ADManualTransport.REMIND_MS
|
||||||
|
end
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
-- Funktionerne lægges på SmartPickupFrame (indlæses efter SmartPickupFrame.lua).
|
-- Funktionerne lægges på SmartPickupFrame (indlæses efter SmartPickupFrame.lua).
|
||||||
|
|
||||||
-- Markflådens rækker (vehiclePrefab/ingredientPrefab) routes til onClickFieldRow.
|
-- Markflådens rækker (vehiclePrefab/ingredientPrefab) routes til onClickFieldRow.
|
||||||
SmartPickupFrame.FIELD_ROW_KINDS = {fleetVehicle = true, fleetMode = true}
|
SmartPickupFrame.FIELD_ROW_KINDS = {fleetVehicle = true, fleetMode = true, fleetManual = true}
|
||||||
SmartPickupFrame.ROLE_KEYS = {
|
SmartPickupFrame.ROLE_KEYS = {
|
||||||
mower = "spu_field_role_mower", tedder = "spu_field_role_tedder", rake = "spu_field_role_rake",
|
mower = "spu_field_role_mower", tedder = "spu_field_role_tedder", rake = "spu_field_role_rake",
|
||||||
collector = "spu_field_role_collector", harvester = "spu_field_role_harvester", unloader = "spu_field_role_unloader",
|
collector = "spu_field_role_collector", harvester = "spu_field_role_harvester", unloader = "spu_field_role_unloader",
|
||||||
@@ -238,6 +238,12 @@ function SmartPickupFrame:fillFleetRows(adEnv)
|
|||||||
local title = string.format(" %s — %s, %.1f m%s", tostring(rig.label), self:roleText(rig.role), rig.width or 0, self:rigDetails(rig))
|
local title = string.format(" %s — %s, %.1f m%s", tostring(rig.label), self:roleText(rig.role), rig.width or 0, self:rigDetails(rig))
|
||||||
row:getDescendantByName("title"):setText(title)
|
row:getDescendantByName("title"):setText(title)
|
||||||
row:getDescendantByName("option"):setState(rig.enabled and SmartPickupFrame.STATE_ON or SmartPickupFrame.STATE_OFF, false)
|
row:getDescendantByName("option"):setState(rig.enabled and SmartPickupFrame.STATE_ON or SmartPickupFrame.STATE_OFF, false)
|
||||||
|
if rig.role == "harvester" then
|
||||||
|
-- for bred til vejene med skærebord: spilleren kører den til marken, moden overtager derfra
|
||||||
|
local option = self:addToggleRow("fleetManual", string.format(i18n:getText("spu_field_manualTransport"), tostring(rig.label)),
|
||||||
|
{i18n:getText("ui_no"), i18n:getText("ui_yes")}, rig.manual)
|
||||||
|
self.rowData[option] = {kind = "fleetManual", vehicleId = rig.id}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if #rigs == 0 then
|
if #rigs == 0 then
|
||||||
self:addTextRow(" " .. i18n:getText("spu_field_noRigs"))
|
self:addTextRow(" " .. i18n:getText("spu_field_noRigs"))
|
||||||
@@ -266,7 +272,9 @@ function SmartPickupFrame:refreshFieldRows(adEnv)
|
|||||||
local selected = self.selectedFieldId ~= nil and ADFieldJobs.getField(self.selectedFieldId) or nil
|
local selected = self.selectedFieldId ~= nil and ADFieldJobs.getField(self.selectedFieldId) or nil
|
||||||
local info = self.selectedFieldId ~= nil and ADFields.getInfo(self.selectedFieldId) or nil
|
local info = self.selectedFieldId ~= nil and ADFields.getInfo(self.selectedFieldId) or nil
|
||||||
local isWorking = selected ~= nil and ADFieldModel.isWorking(selected)
|
local isWorking = selected ~= nil and ADFieldModel.isWorking(selected)
|
||||||
self.fieldStartButtonInfo.text = self.i18n:getText(isWorking and "spu_field_button_stop" or "spu_field_button_start")
|
local awaiting = self.selectedFieldId ~= nil and ADFieldJobs.awaitingPlayer(self.selectedFieldId) ~= nil
|
||||||
|
self.fieldStartButtonInfo.text = self.i18n:getText(awaiting and "spu_field_button_takeover"
|
||||||
|
or (isWorking and "spu_field_button_stop" or "spu_field_button_start"))
|
||||||
self.fieldStartButtonInfo.disabled = selected == nil or info == nil or (not isWorking and info.markerId == nil)
|
self.fieldStartButtonInfo.disabled = selected == nil or info == nil or (not isWorking and info.markerId == nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -279,6 +287,8 @@ function SmartPickupFrame:onClickFieldRow(state, data)
|
|||||||
ADFieldJobs.toggleFleet(data.vehicleId)
|
ADFieldJobs.toggleFleet(data.vehicleId)
|
||||||
elseif data.kind == "fleetMode" then
|
elseif data.kind == "fleetMode" then
|
||||||
ADFieldJobs.setFleetMode(isOn and "all" or "ticked")
|
ADFieldJobs.setFleetMode(isOn and "all" or "ticked")
|
||||||
|
elseif data.kind == "fleetManual" then
|
||||||
|
if ((ADFieldJobs.state.manual or {})[data.vehicleId] == true) ~= isOn then ADFieldJobs.toggleManual(data.vehicleId) end
|
||||||
end
|
end
|
||||||
frame:requestRebuild()
|
frame:requestRebuild()
|
||||||
end)
|
end)
|
||||||
@@ -290,7 +300,12 @@ function SmartPickupFrame:onClickFieldStartStop()
|
|||||||
local id = frame.selectedFieldId
|
local id = frame.selectedFieldId
|
||||||
if id == nil then return end
|
if id == nil then return end
|
||||||
local field = ADFieldJobs.getField(id)
|
local field = ADFieldJobs.getField(id)
|
||||||
if ADFieldModel.isWorking(field) then
|
if ADFieldJobs.awaitingPlayer(id) ~= nil then
|
||||||
|
-- manuel transport: overtag nu (skærebordet tjekkes stadig)
|
||||||
|
ADFieldJobs.requestTakeover(id)
|
||||||
|
frame.statusOverride = string.format(frame.i18n:getText("spu_field_takeoverRequested"), id)
|
||||||
|
frame.statusOverrideTicks = SmartPickupFrame.STATUS_OVERRIDE_TICKS
|
||||||
|
elseif ADFieldModel.isWorking(field) then
|
||||||
ADFieldJobs.stopField(frame.getAdEnv(), id)
|
ADFieldJobs.stopField(frame.getAdEnv(), id)
|
||||||
else
|
else
|
||||||
local decision = ADFieldJobs.lastDecision[id]
|
local decision = ADFieldJobs.lastDecision[id]
|
||||||
|
|||||||
@@ -59,6 +59,9 @@
|
|||||||
<text name="spu_month_upcomingOpen" text="F%d: %s — kan også sås næste måned"/>
|
<text name="spu_month_upcomingOpen" text="F%d: %s — kan også sås næste måned"/>
|
||||||
<text name="spu_month_upcomingLast" text="F%d: %s — OBS: sidste såmåned"/>
|
<text name="spu_month_upcomingLast" text="F%d: %s — OBS: sidste såmåned"/>
|
||||||
<text name="spu_field_button_start" text="Start nu"/>
|
<text name="spu_field_button_start" text="Start nu"/>
|
||||||
|
<text name="spu_field_manualTransport" text=" Manuel transport af %s (for bred til vejene)"/>
|
||||||
|
<text name="spu_field_button_takeover" text="Start nu"/>
|
||||||
|
<text name="spu_field_takeoverRequested" text="F%d: overtager høsteren nu, hvis skærebordet passer"/>
|
||||||
<text name="spu_field_button_stop" text="Stop mark"/>
|
<text name="spu_field_button_stop" text="Stop mark"/>
|
||||||
<text name="spu_field_noMarker" text="! mangler markør F%d"/>
|
<text name="spu_field_noMarker" text="! mangler markør F%d"/>
|
||||||
<text name="spu_field_stage_idle" text="Venter"/>
|
<text name="spu_field_stage_idle" text="Venter"/>
|
||||||
|
|||||||
@@ -59,6 +59,9 @@
|
|||||||
<text name="spu_month_upcomingOpen" text="F%d: %s — can also be sown next month"/>
|
<text name="spu_month_upcomingOpen" text="F%d: %s — can also be sown next month"/>
|
||||||
<text name="spu_month_upcomingLast" text="F%d: %s — NOTE: last sowing month"/>
|
<text name="spu_month_upcomingLast" text="F%d: %s — NOTE: last sowing month"/>
|
||||||
<text name="spu_field_button_start" text="Start now"/>
|
<text name="spu_field_button_start" text="Start now"/>
|
||||||
|
<text name="spu_field_manualTransport" text=" Manual transport of %s (too wide for roads)"/>
|
||||||
|
<text name="spu_field_button_takeover" text="Start now"/>
|
||||||
|
<text name="spu_field_takeoverRequested" text="F%d: taking over the harvester now if the header fits"/>
|
||||||
<text name="spu_field_button_stop" text="Stop field"/>
|
<text name="spu_field_button_stop" text="Stop field"/>
|
||||||
<text name="spu_field_noMarker" text="! missing marker F%d"/>
|
<text name="spu_field_noMarker" text="! missing marker F%d"/>
|
||||||
<text name="spu_field_stage_idle" text="Waiting"/>
|
<text name="spu_field_stage_idle" text="Waiting"/>
|
||||||
|
|||||||
@@ -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.37.2.0</version>
|
<version>1.38.0.0</version>
|
||||||
<title>
|
<title>
|
||||||
<en>AD Smart Pickup</en>
|
<en>AD Smart Pickup</en>
|
||||||
</title>
|
</title>
|
||||||
@@ -38,6 +38,7 @@
|
|||||||
<sourceFile filename="adCpBridge.lua"/>
|
<sourceFile filename="adCpBridge.lua"/>
|
||||||
<sourceFile filename="adCourseCache.lua"/>
|
<sourceFile filename="adCourseCache.lua"/>
|
||||||
<sourceFile filename="adFieldStorage.lua"/>
|
<sourceFile filename="adFieldStorage.lua"/>
|
||||||
|
<sourceFile filename="adManualTransport.lua"/>
|
||||||
<sourceFile filename="adFieldWork.lua"/>
|
<sourceFile filename="adFieldWork.lua"/>
|
||||||
<sourceFile filename="adFieldSiloPlanner.lua"/>
|
<sourceFile filename="adFieldSiloPlanner.lua"/>
|
||||||
<sourceFile filename="adFieldSiloConfig.lua"/>
|
<sourceFile filename="adFieldSiloConfig.lua"/>
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ local withHarvester = {{phase = "working", stage = "harvesting", helper = false}
|
|||||||
local dHelper = J.decide(harvesting, harvestInfo, withHarvester, 0)
|
local dHelper = J.decide(harvesting, harvestInfo, withHarvester, 0)
|
||||||
check("J8 så aflæsningsvogn", dHelper.role, "unloader"); check("J8 hjælper", dHelper.helper, true)
|
check("J8 så aflæsningsvogn", dHelper.role, "unloader"); check("J8 hjælper", dHelper.helper, true)
|
||||||
check("J8 vogn på plads -> intet", J.decide(harvesting, harvestInfo, {withHarvester[1], {phase = "working", stage = "harvesting", helper = true}}, 0).action, "none")
|
check("J8 vogn på plads -> intet", J.decide(harvesting, harvestInfo, {withHarvester[1], {phase = "working", stage = "harvesting", helper = true}}, 0).action, "none")
|
||||||
|
-- manuel transport: høsteren venter på spilleren -> ingen høster mere og endnu ingen tømmevogn
|
||||||
|
local awaiting = {{phase = "awaitingPlayer", stage = "harvesting", helper = false}}
|
||||||
|
check("J8b venter på spilleren -> intet (ingen ny høster, ingen tømmevogn)", J.decide(harvesting, harvestInfo, awaiting, 0).action, "none")
|
||||||
-- høsteren færdig, afgrøden væk (marken er nu bar) -> videre, selv om vognen stadig kører
|
-- høsteren færdig, afgrøden væk (marken er nu bar) -> videre, selv om vognen stadig kører
|
||||||
local afterInfo = {id = 50, markerId = 7, kind = "bare", readyRatio = 0}
|
local afterInfo = {id = 50, markerId = 7, kind = "bare", readyRatio = 0}
|
||||||
check("J8 høst færdig -> videre", J.decide(harvesting, afterInfo, {{phase = "finished", stage = "harvesting"}, {phase = "working", stage = "harvesting", helper = true}}, 0).action, "advance")
|
check("J8 høst færdig -> videre", J.decide(harvesting, afterInfo, {{phase = "finished", stage = "harvesting"}, {phase = "working", stage = "harvesting", helper = true}}, 0).action, "advance")
|
||||||
|
|||||||
@@ -92,5 +92,11 @@ ADFieldStorage.save({fields = {}, fleet = {}, fleetMode = "all"})
|
|||||||
local old = ADFieldStorage.load()
|
local old = ADFieldStorage.load()
|
||||||
check("ST7 gammel fil: tomt register", next(old.courseRecords), nil)
|
check("ST7 gammel fil: tomt register", next(old.courseRecords), nil)
|
||||||
|
|
||||||
|
-- ST8: manuel transport pr. maskine gemmes og indlæses; gammel fil uden -> tom
|
||||||
|
disk = {}
|
||||||
|
ADFieldStorage.save({fields = {}, fleet = {}, fleetMode = "all", 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)
|
||||||
|
|
||||||
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)
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
-- Kør: luajit tests/test_adManualTransport.lua (fra repo-roden)
|
||||||
|
-- Manuel transport af brede høstere (in-game 27/9: mejetærskere med skærebord er for brede til vejene).
|
||||||
|
dofile("FS25_ADSmartPickup/adManualTransport.lua")
|
||||||
|
local M = ADManualTransport
|
||||||
|
local failures = 0
|
||||||
|
local function check(name, actual, expected)
|
||||||
|
if actual == expected then print("OK " .. name) else
|
||||||
|
failures = failures + 1
|
||||||
|
print(string.format("FAIL %s: forventede %s, fik %s", name, tostring(expected), tostring(actual)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local WHEAT, BARLEY = 1, 2
|
||||||
|
|
||||||
|
-- valg af høster
|
||||||
|
check("manuel høster uden skærebord kan vælges", M.acceptsHarvester({manual = true, fruits = {}}, WHEAT), true)
|
||||||
|
check("automatisk høster uden skærebord kan ikke", M.acceptsHarvester({fruits = {}}, WHEAT), false)
|
||||||
|
check("automatisk høster med passende skærebord", M.acceptsHarvester({fruits = {[WHEAT] = true}}, WHEAT), true)
|
||||||
|
check("ukendt afgrøde -> ingen", M.acceptsHarvester({manual = true}, nil), false)
|
||||||
|
|
||||||
|
-- klar til overtagelse
|
||||||
|
local header = {[WHEAT] = true}
|
||||||
|
local function ready(s) local ok, why = M.readiness(s); return ok and "ok" or why end
|
||||||
|
check("hjemme -> notThere", ready({atField = false, fruits = {}, fruit = WHEAT}), "notThere")
|
||||||
|
check("på marken uden skærebord -> noHeader", ready({atField = true, fruits = {}, fruit = WHEAT}), "noHeader")
|
||||||
|
check("forkert skærebord -> wrongHeader", ready({atField = true, fruits = {[BARLEY] = true}, fruit = WHEAT}), "wrongHeader")
|
||||||
|
check("spilleren sidder i -> playerInside", ready({atField = true, fruits = header, fruit = WHEAT, controlled = true}), "playerInside")
|
||||||
|
check("klar", ready({atField = true, fruits = header, fruit = WHEAT}), "ok")
|
||||||
|
check("Start nu: spiller i og ikke på marken -> ok", ready({atField = false, fruits = header, fruit = WHEAT, controlled = true, forced = true}), "ok")
|
||||||
|
check("Start nu tjekker stadig skærebordet", ready({atField = false, fruits = {}, fruit = WHEAT, forced = true}), "noHeader")
|
||||||
|
|
||||||
|
-- påmindelser
|
||||||
|
check("første gang -> påmind", M.shouldRemind(nil, 1000), true)
|
||||||
|
check("for tidligt", M.shouldRemind(1000, 1000 + M.REMIND_MS - 1), false)
|
||||||
|
check("efter 5 min", M.shouldRemind(1000, 1000 + M.REMIND_MS), true)
|
||||||
|
|
||||||
|
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
||||||
|
os.exit(failures == 0 and 0 or 1)
|
||||||
Reference in New Issue
Block a user