feat(markarbejde): tom spreder/sprøjte kan bruges (roller efter hvad den kan tage; påfyldning med rollens vare); spreder med forkert vare tømmes først og vælges kun hvis ingen anden kan (v1.28.8.0)

This commit is contained in:
2026-09-26 12:51:03 +02:00
parent abbe40da01
commit 6138b6b874
7 changed files with 128 additions and 16 deletions
+83 -11
View File
@@ -62,16 +62,78 @@ local function collect(vehicle, list)
return list
end
-- Sprøjtens/sprederens rolle ud fra det fyld den har på (tom -> nil).
-- Hvilke varer der hører til en rolle (påfyldning af en tom spreder/sprøjte), i foretrukken rækkefølge.
ADCpBridge.ROLE_FILLTYPES = {
fertilizer = {"FERTILIZER", "LIQUIDFERTILIZER", "MANURE", "LIQUIDMANURE", "DIGESTATE"},
limer = {"LIME"},
weeder = {"HERBICIDE"},
}
ADCpBridge.ROLE_ORDER = {"fertilizer", "limer", "weeder"}
-- Sprøjtens/sprederens roller: alle roller dens fyldenhed kan tage (Bredal-spreder: gødning OG kalk).
-- Primær rolle = fyldets rolle (har den kalk på, er den kalkspreder), ellers den første den kan tage.
-- Returnerer primær, sæt {[rolle] = true}, fyldets rolle (nil = tom); nil hvis ingen roller.
function ADCpBridge.sprayRolesFor(filledName, supportedNames)
local roles, first = {}, nil
for _, role in ipairs(ADCpBridge.ROLE_ORDER) do
for _, name in ipairs(ADCpBridge.ROLE_FILLTYPES[role]) do
if supportedNames[name] then
roles[role] = true
first = first or role
break
end
end
end
local filledRole = filledName ~= nil and ADCpBridge.sprayRoleForFillType(filledName) or nil
if filledRole ~= nil then roles[filledRole] = true end
local primary = filledRole or first
return primary, primary ~= nil and roles or nil, filledRole
end
local function sprayerNames(object)
local unitIndex = object:getSprayerFillUnitIndex()
local filledName = nil
if (object:getFillUnitFillLevel(unitIndex) or 0) > 0 then
filledName = g_fillTypeManager:getFillTypeNameByIndex(object:getFillUnitFillType(unitIndex))
end
local supported = {}
local unit = object.spec_fillUnit ~= nil and object.spec_fillUnit.fillUnits ~= nil and object.spec_fillUnit.fillUnits[unitIndex] or nil
for fillType, isSupported in pairs(unit ~= nil and unit.supportedFillTypes or {}) do
if isSupported then
local name = g_fillTypeManager:getFillTypeNameByIndex(fillType)
if name ~= nil then supported[name] = true end
end
end
return filledName, supported
end
local function sprayRole(object)
if object.spec_sprayer == nil or object.getSprayerFillUnitIndex == nil then return nil end
local ok, role = pcall(function()
local unit = object:getSprayerFillUnitIndex()
if (object:getFillUnitFillLevel(unit) or 0) <= 0 then return nil end
local name = g_fillTypeManager:getFillTypeNameByIndex(object:getFillUnitFillType(unit))
return ADCpBridge.sprayRoleForFillType(name)
local ok, role, roles, filledRole = pcall(function()
local filledName, supported = sprayerNames(object)
return ADCpBridge.sprayRolesFor(filledName, supported)
end)
return ok and role or nil
if not ok then return nil end
return role, roles, filledRole
end
-- Tøm sprøjten/sprederen for en vare der ikke hører til opgaven (kalk på, skal gøde). FS25 kan ikke
-- tippe gødning/kalk af, så resten kasseres. Returnerer liter og varenavn (0 hvis intet blev tømt).
function ADCpBridge.emptySprayerIfWrong(vehicle, role)
local liters, name = 0, nil
for _, object in ipairs(collect(vehicle)) do
if object.spec_sprayer ~= nil and object.getSprayerFillUnitIndex ~= nil then
pcall(function()
local filledName = sprayerNames(object)
if filledName == nil or ADCpBridge.sprayRoleForFillType(filledName) == role then return end
local unit = object:getSprayerFillUnitIndex()
local level = object:getFillUnitFillLevel(unit) or 0
object:addFillUnitFillLevel(object:getOwnerFarmId(), unit, -level, object:getFillUnitFillType(unit), ToolType.UNDEFINED, nil)
liters, name = liters + level, filledName
end)
end
end
return liters, name
end
function ADCpBridge.getSpecs(vehicle)
@@ -80,7 +142,7 @@ function ADCpBridge.getSpecs(vehicle)
for _, name in ipairs(ADCpBridge.SPECS) do
if object[name] ~= nil then specs[name] = true end
end
specs.sprayRole = specs.sprayRole or sprayRole(object)
if specs.sprayRole == nil then specs.sprayRole, specs.sprayRoles, specs.filledRole = sprayRole(object) end
end
if vehicle.getCanStartCpCombineUnloader ~= nil then
local ok, can = pcall(vehicle.getCanStartCpCombineUnloader, vehicle)
@@ -164,8 +226,9 @@ function ADCpBridge.isPlantableNow(fruitIndex)
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)
-- fyld; en TOM spreder får rollens vare (gødning ved gødskning, kalk ved kalkning), hvis dens fyldenhed
-- kan tage den. nil = intet at fylde på (strigle, plov ...).
function ADCpBridge.getRefillFillType(vehicle, role)
for _, object in ipairs(collect(vehicle)) do
if object.spec_sowingMachine ~= nil and g_fillTypeManager ~= nil then
return g_fillTypeManager:getFillTypeIndexByName("SEEDS")
@@ -173,7 +236,16 @@ function ADCpBridge.getRefillFillType(vehicle)
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)
local ok, fillType = pcall(function()
local filledName, supported = sprayerNames(object)
if filledName ~= nil and (role == nil or ADCpBridge.sprayRoleForFillType(filledName) == role) then
return g_fillTypeManager:getFillTypeIndexByName(filledName)
end
for _, name in ipairs(ADCpBridge.ROLE_FILLTYPES[role] or {}) do
if supported[name] then return g_fillTypeManager:getFillTypeIndexByName(name) end
end
return nil
end)
if ok and fillType ~= nil and fillType ~= 0 then return fillType end
end
end
+8 -3
View File
@@ -40,7 +40,7 @@ local function sortCandidates(candidates, role, x, z, requiredWidth, accept)
local usable, sawRole, sawAccepted = {}, false, false
local widthReason, widthArgs = nil, nil
for _, candidate in ipairs(candidates) do
if candidate.role == role and candidate.enabled then
if (candidate.role == role or (candidate.roles ~= nil and candidate.roles[role])) and candidate.enabled then
sawRole = true
if accept == nil or accept(candidate) then
sawAccepted = true
@@ -48,7 +48,9 @@ local function sortCandidates(candidates, role, x, z, requiredWidth, accept)
local ok, reason, args = ADFieldModel.checkWidth(role, candidate.width or 0, requiredWidth)
if ok then
local dx, dz = candidate.x - x, candidate.z - z
table.insert(usable, {candidate = candidate, distance = dx * dx + dz * dz})
-- spreder med en anden vare på skal tømmes først: kun hvis ingen anden kan
local wrongFill = candidate.filledRole ~= nil and candidate.filledRole ~= role
table.insert(usable, {candidate = candidate, distance = dx * dx + dz * dz, wrongFill = wrongFill})
elseif widthReason == nil then
widthReason, widthArgs = reason, args
end
@@ -56,7 +58,10 @@ local function sortCandidates(candidates, role, x, z, requiredWidth, accept)
end
end
end
table.sort(usable, function(a, b) return a.distance < b.distance end)
table.sort(usable, function(a, b)
if a.wrongFill ~= b.wrongFill then return not a.wrongFill end
return a.distance < b.distance
end)
local reason, args = nil, nil
if not sawRole then
reason = "noRig"
+8 -1
View File
@@ -120,6 +120,8 @@ function ADFieldWork.getRigs(adEnv)
busy = state.assignments[id] ~= nil or isAdActive(vehicle) or ADCpBridge.isWorking(vehicle),
controlled = isControlledByPlayer(vehicle),
width = ADCpBridge.getWorkWidth(vehicle), x = x, z = z,
-- tom spreder kan flere ting (gødning og kalk): alle dens roller
roles = specs.sprayRoles, filledRole = specs.filledRole,
}
if role == "harvester" then rig.fruits = ADCpBridge.getHarvestFruits(vehicle) or {} end
if role == "seeder" then
@@ -377,7 +379,12 @@ end
-- og genstarter CP. Findes ingen påfyldning, stopper sættet når det er tomt ("tom for …", se finish).
local function prepareRefill(adEnv, field, info, assignment)
local vehicle = assignment.vehicle
local fillType = ADCpBridge.getRefillFillType(vehicle)
-- forkert vare på (kalk, skal gøde): tøm først, så AutoDrive fylder den rigtige på
local dumped, dumpedName = ADCpBridge.emptySprayerIfWrong(vehicle, assignment.role)
if dumped > 0 then
log(field.id, "'%s' tømt for %.0f l %s (skal bruges til %s)", ADRuns.vehicleLabel(vehicle), dumped, tostring(dumpedName), tostring(assignment.role))
end
local fillType = ADCpBridge.getRefillFillType(vehicle, assignment.role)
if fillType == nil then return end
assignment.refillFillType = fillType
local name = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(fillType) or tostring(fillType)
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<modDesc descVersion="107">
<author>masterdraco</author>
<version>1.28.7.0</version>
<version>1.28.8.0</version>
<title>
<en>AD Smart Pickup</en>
</title>