feat(marker): vejr (vent på tørvejr), påfyldning via AutoDrive LOAD+CP, beskeder i spillet; Start nu virker på bare marker

This commit is contained in:
2026-09-26 00:04:37 +02:00
parent 65986b1793
commit ae1362d164
8 changed files with 126 additions and 7 deletions
+17
View File
@@ -159,6 +159,23 @@ function ADCpBridge.isPlantableNow(fruitIndex)
return ADCpBridge.isPlantableIn(fruit, environment ~= nil and environment.currentPeriod or 0)
end
-- Hvilken vare sættet bruger og kan få fyldt på af AutoDrive: frø (såmaskine) eller sprøjtens/sprederens
-- nuværende fyld (gødning, kalk, sprøjtemiddel). nil = intet at fylde på (strigle, plov ...).
function ADCpBridge.getRefillFillType(vehicle)
for _, object in ipairs(collect(vehicle)) do
if object.spec_sowingMachine ~= nil and g_fillTypeManager ~= nil then
return g_fillTypeManager:getFillTypeIndexByName("SEEDS")
end
end
for _, object in ipairs(collect(vehicle)) do
if object.spec_sprayer ~= nil and object.getSprayerFillUnitIndex ~= nil then
local ok, fillType = pcall(function() return object:getFillUnitFillType(object:getSprayerFillUnitIndex()) end)
if ok and fillType ~= nil and fillType ~= 0 then return fillType end
end
end
return nil
end
-- Stop køretøjets AI-job (Courseplay/hjælper).
function ADCpBridge.stop(vehicle)
pcall(function()
+39 -3
View File
@@ -31,12 +31,19 @@ end
-- Beslutning for én mark. assignments = sæt på marken ({phase, stage, helper}); kun sæt på det aktuelle
-- trin tæller (en aflæsningsvogn på vej hjem fra høsten forstyrrer ikke kultiveringen).
-- Svar: {action = "start"|"care"|"advance"|"dispatch"|"wait"|"none", role, count, helper, stage, care}.
function ADFieldJobs.decide(field, info, assignments, now)
-- env = {raining = bool}: vejrfølsomme trin (høst/slå/vend/riv/hø) sendes ikke ud i regn.
-- Svar: {action = "start"|"care"|"advance"|"dispatch"|"wait"|"none", role, count, helper, stage, care, reason}.
function ADFieldJobs.decide(field, info, assignments, now, env)
local hasMarker = info ~= nil and info.markerId ~= nil
local raining = env ~= nil and env.raining == true
local kind = field.kind or (info ~= nil and info.kind) or "mowable"
if field.stage == "ready" then
if not ADFieldModel.shouldStart(field) then return {action = "none"} end
if not hasMarker then return {action = "wait"} end
local first = ADFieldModel.workStages(field.plan, info.kind, info.needs)[1]
if raining and first ~= nil and ADFieldModel.isWeatherSensitive(first, field.plan, info.kind) then
return {action = "wait", reason = "rain"}
end
return {action = "start"}
end
if not ADFieldModel.isWorking(field) then
@@ -68,6 +75,9 @@ function ADFieldJobs.decide(field, info, assignments, now)
end
if not hasMarker then return {action = "wait"} end
if (field.retryAt or 0) > now then return {action = "none"} end
if raining and ADFieldModel.isWeatherSensitive(field.stage, field.plan, kind) then
return {action = "wait", reason = "rain"}
end
return {action = "dispatch", role = ADFieldModel.roleFor(field.stage), count = ADFieldModel.maxRigs(field.stage, field.plan), helper = false}
end
-- hovedsættene arbejder: fyld op med hjælpere (aflæsningsvogne) en ad gangen
@@ -166,6 +176,25 @@ function ADFieldJobs.stopField(adEnv, id)
ADFieldJobs.log(id, "stoppet fra menuen")
end
-- Besked i spillet (højre side). critical = rød. Samme tekst vises kun én gang i træk.
function ADFieldJobs.notify(text, critical)
if ADFieldJobs.lastNotice == text then return end
ADFieldJobs.lastNotice = text
pcall(function()
local kind = critical and FSBaseMission.INGAME_NOTIFICATION_CRITICAL or FSBaseMission.INGAME_NOTIFICATION_OK
g_currentMission:addIngameNotification(kind, "Smart Pickup: " .. text)
end)
end
-- Vejret lige nu (regn), læst en gang pr. tick.
function ADFieldJobs.environment()
local ok, raining = pcall(function()
local weather = g_currentMission.environment.weather
return weather ~= nil and weather.getIsRaining ~= nil and weather:getIsRaining() or false
end)
return {raining = ok and raining == true}
end
-- Seneste beslutning pr. mark (GUI viser pleje-behov og grunde).
ADFieldJobs.lastDecision = {}
@@ -174,7 +203,7 @@ local function stepField(adEnv, info)
ADFieldJobs.setField(field)
local assignments = ADFieldJobs.assignmentsFor(info.id)
for _, done in ipairs(finishedFor(info.id)) do table.insert(assignments, done) end
local decision = ADFieldJobs.decide(field, info, assignments, ADFieldJobs.now)
local decision = ADFieldJobs.decide(field, info, assignments, ADFieldJobs.now, ADFieldJobs.environment())
ADFieldJobs.lastDecision[info.id] = decision
if decision.action == "start" then
local started = ADFieldModel.start(field, info.kind, info.needs)
@@ -192,7 +221,14 @@ local function stepField(adEnv, info)
ADFieldJobs.forgetFinished(info.id)
ADFieldWork.windDownHelpers(adEnv, info.id, field.stage)
ADFieldJobs.log(info.id, "%s -> %s", field.stage, nextField.stage)
if nextField.stage == "done" or (ADFieldModel.isCare(field.stage) and nextField.stage == "idle") then
ADFieldJobs.notify(string.format("F%d %s", info.id, g_i18n ~= nil and g_i18n:getText("spu_field_notice_done") or "done"), false)
end
ADFieldJobs.save()
elseif decision.action == "wait" and decision.reason == "rain" then
if field.reason == nil or field.reason.key ~= "spu_field_reason_rain" then
ADFieldJobs.note(info.id, {reason = {key = "spu_field_reason_rain"}})
end
elseif decision.action == "dispatch" then
ADFieldWork.dispatch(adEnv, field, info, decision)
end
+10 -1
View File
@@ -178,7 +178,8 @@ function ADFieldModel.onReadiness(field, ratio)
local copy = copyField(field)
if (field.stage == "idle" or field.stage == "done") and ratio >= ADFieldModel.READY_RATIO then
copy.stage = "ready"
elseif field.stage == "ready" and ratio < ADFieldModel.CUT_RATIO then
elseif field.stage == "ready" and ratio < ADFieldModel.CUT_RATIO and not field.startRequested then
-- (en Start nu-forespørgsel holder marken klar: bare marker har klar-andel 0)
copy.stage = "idle"
copy.startRequested = false
end
@@ -256,6 +257,14 @@ function ADFieldModel.stop(field)
return copy
end
-- Vejrfølsomme trin: afgrøde og skår skal være tørre (høst, slåning, vending, rivning, hø-opsamling).
-- Jordbehandling, såning, pleje og ensilage-opsamling kan køre i regn.
local WEATHER_STAGES = {harvesting = true, mowing = true, tedding = true, raking = true}
function ADFieldModel.isWeatherSensitive(stage, plan, kind)
if WEATHER_STAGES[stage] then return true end
return stage == "collecting" and ADFieldModel.product(plan, kind or "mowable") == "hay"
end
-- Pleje under vækst: hvilket pleje-trin marken trænger til nu (eller nil). info fra adFields:
-- {kind, growing, fert, fertMax, lime, weed}. Højst MAX_CARE_RUNS pr. pleje pr. cyklus.
function ADFieldModel.careNeed(field, info)
+35 -3
View File
@@ -242,6 +242,7 @@ end
local function fail(fieldId, text)
note(fieldId, {retryAt = now() + ADFieldModel.RETRY_MS, reason = {text = tostring(text)}})
log(fieldId, "%s", tostring(text))
ADFieldJobs.notify(string.format("F%s: %s", tostring(fieldId), tostring(text)), true)
end
-- Hvad et sæt skal kunne ud over rollen (afgrøde, frø, ukrudtets størrelse).
@@ -339,6 +340,32 @@ local function prepareCollector(adEnv, field, info, assignment)
return true
end
-- Påfyldning undervejs (såmaskine/sprøjte/spreder): AutoDrive LOAD med automatisk påfyldningsmål og
-- hjælper = Courseplay. Når CP melder tom (onCpEmpty), kører AD til nærmeste påfyldning af varen, fylder
-- op, kører tilbage til F-markøren og genstarter CP. Courseplay og AutoDrive er bygget til netop dette.
local function prepareRefill(adEnv, field, info, assignment)
local vehicle = assignment.vehicle
local fillType = ADCpBridge.getRefillFillType(vehicle)
if fillType == nil then return end
local module = stateModule(vehicle)
local ok = pcall(function()
module:setMode(adEnv.AutoDrive.MODE_LOAD)
module:setFirstMarkerByWayPointId(info.markerId)
module:setSecondMarkerByWayPointId(info.markerId)
module:setAutomaticPickupTarget(true)
module:setFillType(fillType)
module:setStartHelper(true)
module.usedHelper = helperCp(adEnv)
enableParkAtJobFinished(vehicle)
module:raiseDirtyFlag()
end)
if ok then
assignment.adHandlesEnd = true
local name = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(fillType) or tostring(fillType)
log(field.id, "'%s' fyldes op med %s af AutoDrive når den er tom", ADRuns.vehicleLabel(vehicle), tostring(name))
end
end
-- Aflæsningsvogn under høst: Courseplays combine-unloader med stationen fra silovalget.
local function beginUnloader(adEnv, field, info, assignment)
local vehicle = assignment.vehicle
@@ -407,7 +434,12 @@ local function beginWork(adEnv, field, info, assignment)
end
return
end
if assignment.role == "collector" and not prepareCollector(adEnv, field, info, assignment) then return end
if assignment.role == "collector" then
if not prepareCollector(adEnv, field, info, assignment) then return end
assignment.adHandlesEnd = true
elseif assignment.role == "seeder" or assignment.role == "fertilizer" or assignment.role == "limer" or assignment.role == "weeder" then
prepareRefill(adEnv, field, info, assignment)
end
if assignment.role == "seeder" then
local okSeed, seedError = ADCpBridge.setSeedFruit(vehicle, ADFieldWork.sowFruitIndex(field))
if not okSeed then
@@ -462,8 +494,8 @@ end
local function finishAssignment(adEnv, assignment)
local vehicle = assignment.vehicle
log(assignment.fieldId, "%s '%s' færdig", assignment.role, ADRuns.vehicleLabel(vehicle))
-- læssevognen parkeres af AutoDrive selv (onCpFinished med parkering sat)
local park = assignment.role ~= "collector" and parkMarkerId(adEnv, vehicle) or nil
-- 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
if park ~= nil then startAd(adEnv, vehicle, adEnv.AutoDrive.MODE_DRIVETO, park, nil) end
restoreToolOffset(assignment)
assignment.phase = "finished"
+2
View File
@@ -151,6 +151,8 @@
<text name="spu_field_stage_weeding" text="Ukrudt bekæmpes"/>
<text name="spu_field_unloaders" text="Aflæsningsvogne under høst"/>
<text name="spu_field_weed" text="Bekæmp ukrudt"/>
<text name="spu_field_notice_done" text="er færdig"/>
<text name="spu_field_reason_rain" text="venter på tørvejr"/>
<text name="spu_button_start" text="Start run"/>
<text name="spu_button_stop" text="Stop run"/>
<text name="spu_button_new" text="Nyt run"/>
+2
View File
@@ -151,6 +151,8 @@
<text name="spu_field_stage_weeding" text="Weeding"/>
<text name="spu_field_unloaders" text="Unloading trailers during harvest"/>
<text name="spu_field_weed" text="Control weeds"/>
<text name="spu_field_notice_done" text="is done"/>
<text name="spu_field_reason_rain" text="waiting for dry weather"/>
<text name="spu_button_start" text="Start run"/>
<text name="spu_button_stop" text="Stop run"/>
<text name="spu_button_new" text="New run"/>