feat(pulje): etape 2 — tømmevogne ved høst fra puljen: ledig traktor henter en puljevogn der kan bære afgrøden, følger høsteren til høsten er færdig, sætter vognen af og kører hjem (v1.49.0.0)

This commit is contained in:
2026-09-28 18:54:44 +02:00
parent 760fbac328
commit 473f6110bf
4 changed files with 37 additions and 8 deletions
+8 -3
View File
@@ -391,7 +391,7 @@ end
-- Puljekombination: nærmeste puljeredskab til marken + nærmeste ledige traktor med nok hk. Traktoren kører til -- Puljekombination: nærmeste puljeredskab til marken + nærmeste ledige traktor med nok hk. Traktoren kører til
-- "Connect X", kobler på og fortsætter så som en almindelig udsendelse (fase fetching -> driving). -- "Connect X", kobler på og fortsætter så som en almindelig udsendelse (fase fetching -> driving).
function ADFieldWork.dispatchPool(adEnv, field, info, role, roleAccept) function ADFieldWork.dispatchPool(adEnv, field, info, role, roleAccept, decision)
local implements, tractors = ADPool.collect(adEnv, function(vehicle) local implements, tractors = ADPool.collect(adEnv, function(vehicle)
return isBusyVehicle(vehicle, ADRunsController.getVehicleId(vehicle)) return isBusyVehicle(vehicle, ADRunsController.getVehicleId(vehicle))
end) end)
@@ -404,6 +404,8 @@ function ADFieldWork.dispatchPool(adEnv, field, info, role, roleAccept)
end end
if role == "weeder" then candidate.mechanical = ADCpBridge.isMechanicalWeeder(implement.vehicle) end if role == "weeder" then candidate.mechanical = ADCpBridge.isMechanicalWeeder(implement.vehicle) end
if roleAccept ~= nil and not roleAccept(candidate) then return false end if roleAccept ~= nil and not roleAccept(candidate) then return false end
-- tømmevogn: skal kunne bære høstens vare
if role == "unloader" and not ADPool.canCarry(implement, info.harvestFillType) then return false end
local required = ADFieldModel.requiredWidth(field, role) local required = ADFieldModel.requiredWidth(field, role)
return (implement.width or 0) <= 0 or ADFieldModel.checkWidth(role, implement.width, required) return (implement.width or 0) <= 0 or ADFieldModel.checkWidth(role, implement.width, required)
end end
@@ -412,7 +414,8 @@ function ADFieldWork.dispatchPool(adEnv, field, info, role, roleAccept)
local tractor, implement = pair.tractor, pair.implement local tractor, implement = pair.tractor, pair.implement
local assignment = { local assignment = {
vehicleId = tractor.id, vehicle = tractor.vehicle, fieldId = field.id, role = role, stage = field.stage, vehicleId = tractor.id, vehicle = tractor.vehicle, fieldId = field.id, role = role, stage = field.stage,
helper = false, phase = "fetching", since = now(), width = implement.width, groupSize = 1, leader = true, helper = decision ~= nil and decision.helper == true, phase = "fetching", since = now(), width = implement.width,
groupSize = 1, leader = true, fillType = decision ~= nil and decision.helper and info.harvestFillType or nil,
startX = tractor.x, startZ = tractor.z, startX = tractor.x, startZ = tractor.z,
pool = {implementId = implement.id, implementName = implement.name, connectId = implement.connectId}, pool = {implementId = implement.id, implementName = implement.name, connectId = implement.connectId},
hitch = {done = false}, hitch = {done = false},
@@ -444,6 +447,8 @@ function ADFieldWork.dispatch(adEnv, field, info, decision)
local offNetwork = {} local offNetwork = {}
local accept = function(candidate) local accept = function(candidate)
if roleAccept ~= nil and not roleAccept(candidate) then return false end if roleAccept ~= nil and not roleAccept(candidate) then return false end
-- tømmevogn: skal kunne bære høstens vare
if role == "unloader" and not ADPool.canCarry(implement, info.harvestFillType) then return false end
-- manuel transport: spilleren kører den — afstand til AutoDrive-vejnettet er ligegyldig -- manuel transport: spilleren kører den — afstand til AutoDrive-vejnettet er ligegyldig
if role == "harvester" and candidate.manual then return true end if role == "harvester" and candidate.manual then return true end
local d = candidate.x ~= nil and ADFieldWork.distanceToNetwork(adEnv, candidate.x, candidate.z) or nil local d = candidate.x ~= nil and ADFieldWork.distanceToNetwork(adEnv, candidate.x, candidate.z) or nil
@@ -471,7 +476,7 @@ function ADFieldWork.dispatch(adEnv, field, info, decision)
end end
if ADPool ~= nil and ADPool.mayUsePool(decision, hasOwnForRole) if ADPool ~= nil and ADPool.mayUsePool(decision, hasOwnForRole)
and (why == "noRig" or why == "allBusy" or why == "cannotDo") then and (why == "noRig" or why == "allBusy" or why == "cannotDo") then
local pooled, poolWhy, poolArgs = ADFieldWork.dispatchPool(adEnv, field, info, role, roleAccept) local pooled, poolWhy, poolArgs = ADFieldWork.dispatchPool(adEnv, field, info, role, roleAccept, decision)
if pooled then return end if pooled then return end
if poolWhy == "tooWeak" then if poolWhy == "tooWeak" then
note(field.id, {reason = {text = string.format("ingen ledig traktor med ≥%.0f hk til '%s'", note(field.id, {reason = {text = string.format("ingen ledig traktor med ≥%.0f hk til '%s'",
+22 -3
View File
@@ -90,9 +90,16 @@ function ADPool.nextDrive(refill)
return "empty" return "empty"
end end
-- Puljen bruges kun til hovedopgaver med ét sæt, og ikke når marken har egne faste maskiner til rollen. -- Puljen bruges til opgaver med ét sæt (også tømmevogne ved høst), ikke når marken har egne faste maskiner
-- til rollen.
function ADPool.mayUsePool(decision, hasOwnForRole) function ADPool.mayUsePool(decision, hasOwnForRole)
return not decision.helper and (decision.count or 1) == 1 and not hasOwnForRole return (decision.count or 1) == 1 and not hasOwnForRole
end
-- Kan puljevognen bære varen? (implement.carries = {[fillType] = true}; nil vare = intet krav)
function ADPool.canCarry(implement, fillType)
if fillType == nil then return true end
return implement.carries ~= nil and implement.carries[fillType] == true
end end
-- Status til flådefanen. s = {parkName, hasConnect, attachedTo, quarantineMin, reserved} -> nøgle, argument -- Status til flådefanen. s = {parkName, hasConnect, attachedTo, quarantineMin, reserved} -> nøgle, argument
@@ -261,6 +268,17 @@ local function tractorHpOf(vehicle)
return item ~= nil and item.specs ~= nil and ADPool.numberOf(item.specs.power) or nil return item ~= nil and item.specs ~= nil and ADPool.numberOf(item.specs.power) or nil
end end
-- Varer og samlet kapacitet i redskabets fyldenheder (tømmevogne).
function ADPool.cargoOf(vehicle)
local carries, capacity = {}, 0
local units = vehicle.spec_fillUnit ~= nil and vehicle.spec_fillUnit.fillUnits or {}
for index in ipairs(units) do
capacity = capacity + (vehicle:getFillUnitCapacity(index) or 0)
for fillType in pairs(vehicle:getFillUnitSupportedFillTypes(index) or {}) do carries[fillType] = true end
end
return carries, capacity
end
local function isAttached(vehicle) local function isAttached(vehicle)
return vehicle.getAttacherVehicle ~= nil and vehicle:getAttacherVehicle() ~= nil return vehicle.getAttacherVehicle ~= nil and vehicle:getAttacherVehicle() ~= nil
end end
@@ -290,7 +308,8 @@ function ADPool.collect(adEnv, isBusy)
local role = specs ~= nil and ADPool.roleOf(specs) or nil local role = specs ~= nil and ADPool.roleOf(specs) or nil
if role ~= nil then if role ~= nil then
local x, z = positionOf(vehicle) local x, z = positionOf(vehicle)
table.insert(implements, { local carries, capacity = ADPool.cargoOf(vehicle)
table.insert(implements, {carries = carries, capacity = capacity,
id = ADRunsController.getVehicleId(vehicle), vehicle = vehicle, name = ADRuns.vehicleLabel(vehicle), 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 = specs.sprayRoles or ADFieldFleet.rolesFor(role), x = x, z = z, width = ADCpBridge.getWorkWidth(vehicle),
neededHp = neededHpOf(vehicle), connectId = connect.id, parkId = park.id, neededHp = neededHpOf(vehicle), connectId = connect.id, parkId = park.id,
+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.48.4.0</version> <version>1.49.0.0</version>
<title> <title>
<en>AD Smart Pickup</en> <en>AD Smart Pickup</en>
</title> </title>
+6 -1
View File
@@ -99,7 +99,7 @@ check("I3: tom med påfyldning", P.nextDrive({empty = true, refillId = 7}), "loa
check("I3: tom uden påfyldning", P.nextDrive({empty = true}), "empty") check("I3: tom uden påfyldning", P.nextDrive({empty = true}), "empty")
-- I4: puljen kun til hovedopgaver med ét sæt, og ikke når marken har egne faste maskiner til rollen -- I4: puljen kun til hovedopgaver med ét sæt, og ikke når marken har egne faste maskiner til rollen
check("I4: almindelig", P.mayUsePool({count = 1}, false), true) check("I4: almindelig", P.mayUsePool({count = 1}, false), true)
check("I4: tømmevogn", P.mayUsePool({count = 1, helper = true}, false), false) check("etape 2: tømmevogn må bruge puljen", P.mayUsePool({count = 1, helper = true}, false), true)
check("I4: multi-tool", P.mayUsePool({count = 2}, false), false) check("I4: multi-tool", P.mayUsePool({count = 2}, false), false)
check("I4: marken har faste", P.mayUsePool({count = 1}, true), false) check("I4: marken har faste", P.mayUsePool({count = 1}, true), false)
-- status til flådefanen -- status til flådefanen
@@ -136,5 +136,10 @@ check("M3: på grænsen -> næste", P.alignedRetry(60000, 30000), 90000)
check("M3: to marker samme takt", P.alignedRetry(62000, 30000) == P.alignedRetry(89000, 30000), true) check("M3: to marker samme takt", P.alignedRetry(62000, 30000) == P.alignedRetry(89000, 30000), true)
-- M4: for svag nævner redskabets navn -- M4: for svag nævner redskabets navn
check("M4: navn i args", weakArgs[2], "Plov nær") check("M4: navn i args", weakArgs[2], "Plov nær")
-- etape 2: puljevogn skal kunne bære høstens vare
check("bære: vare understøttet", P.canCarry({carries = {[3] = true}}, 3), true)
check("bære: vare ikke understøttet", P.canCarry({carries = {[3] = true}}, 7), false)
check("bære: ingen vare krævet", P.canCarry({carries = {}}, nil), true)
check("bære: ukendt last", P.canCarry({}, 3), 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)