feat(marker): markflåde — alle markroller, accept-filter (afgrøde/ukrudt), pickMany til multi-tool
This commit is contained in:
@@ -1,48 +1,92 @@
|
||||
-- AD Field Fleet
|
||||
-- Markflåden som ren logik: hvilken rolle et sæt har ud fra redskabernes specs, og hvilket ledigt sæt
|
||||
-- der sendes til en mark. Kun sæt med flueben bruges; et sæt spilleren sidder i, røres aldrig.
|
||||
-- Markflåden som ren logik: hvilken rolle et sæt har ud fra redskabernes specs, og hvilke ledige sæt der
|
||||
-- sendes til en mark. Kun sæt med flueben bruges; et sæt spilleren sidder i, røres aldrig.
|
||||
|
||||
ADFieldFleet = {}
|
||||
|
||||
-- Rækkefølge = prioritet når et køretøj har flere (læssevogn med egen pickup m.m.)
|
||||
-- Rækkefølge = prioritet når et køretøj har flere (såmaskine med gødning er såmaskine; traktor med plov er
|
||||
-- plov, ikke aflæsningsvogn). sprayRole kommer fra sprøjtens/sprederens fyld (gødning/kalk/ukrudt).
|
||||
ADFieldFleet.ROLE_SPECS = {
|
||||
{role = "harvester", spec = "spec_combine"},
|
||||
{role = "collector", spec = "spec_forageWagon"},
|
||||
{role = "rake", spec = "spec_windrower"},
|
||||
{role = "tedder", spec = "spec_tedder"},
|
||||
{role = "mower", spec = "spec_mower"},
|
||||
{role = "seeder", spec = "spec_sowingMachine"},
|
||||
{role = "roller", spec = "spec_roller"},
|
||||
{role = "weeder", spec = "spec_weeder"},
|
||||
{role = "sprayRole"},
|
||||
{role = "mulcher", spec = "spec_mulcher"},
|
||||
{role = "cultivator", spec = "spec_cultivator"},
|
||||
{role = "plow", spec = "spec_plow"},
|
||||
{role = "unloader", spec = "canUnload"},
|
||||
}
|
||||
|
||||
function ADFieldFleet.roleFromSpecs(specs)
|
||||
for _, entry in ipairs(ADFieldFleet.ROLE_SPECS) do
|
||||
if specs[entry.spec] then return entry.role end
|
||||
if entry.role == "sprayRole" then
|
||||
if specs.sprayRole ~= nil then return specs.sprayRole end
|
||||
elseif specs[entry.spec] then
|
||||
return entry.role
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Nærmeste brugbare sæt til rollen. Grund når intet passer: noRig (ingen med flueben og rollen),
|
||||
-- allBusy (alle optaget/i brug af spilleren), tooWide/tooNarrow (bredden, med tal fra den første).
|
||||
function ADFieldFleet.pick(candidates, role, x, z, mowWidth)
|
||||
local best, bestDistance = nil, math.huge
|
||||
local sawRole, widthReason, widthArgs = false, nil, nil
|
||||
-- Kandidater med rollen, sorteret nærmest først, delt i brugbare og afviste (med første grund).
|
||||
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
|
||||
sawRole = true
|
||||
if not candidate.busy and not candidate.controlled then
|
||||
local ok, reason, args = ADFieldModel.checkWidth(role, candidate.width or 0, mowWidth)
|
||||
if ok then
|
||||
local dx, dz = candidate.x - x, candidate.z - z
|
||||
local distance = dx * dx + dz * dz
|
||||
if distance < bestDistance then best, bestDistance = candidate, distance end
|
||||
elseif widthReason == nil then
|
||||
widthReason, widthArgs = reason, args
|
||||
if accept == nil or accept(candidate) then
|
||||
sawAccepted = true
|
||||
if not candidate.busy and not candidate.controlled then
|
||||
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})
|
||||
elseif widthReason == nil then
|
||||
widthReason, widthArgs = reason, args
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if best ~= nil then return best end
|
||||
if not sawRole then return nil, "noRig" end
|
||||
if widthReason ~= nil then return nil, widthReason, widthArgs end
|
||||
return nil, "allBusy"
|
||||
table.sort(usable, function(a, b) return a.distance < b.distance end)
|
||||
local reason, args = nil, nil
|
||||
if not sawRole then
|
||||
reason = "noRig"
|
||||
elseif not sawAccepted then
|
||||
reason = "cannotDo"
|
||||
elseif widthReason ~= nil then
|
||||
reason, args = widthReason, widthArgs
|
||||
else
|
||||
reason = "allBusy"
|
||||
end
|
||||
return usable, reason, args
|
||||
end
|
||||
|
||||
-- Nærmeste brugbare sæt. Grund når intet passer: noRig (ingen med flueben og rollen), cannotDo (ingen kan
|
||||
-- tage opgaven, fx afgrøden), allBusy, tooWide/tooNarrow (bredden, med tal fra den første).
|
||||
-- accept (valgfri): candidate -> bool, fx "høsteren kan tage hvede".
|
||||
function ADFieldFleet.pick(candidates, role, x, z, requiredWidth, accept)
|
||||
local usable, reason, args = sortCandidates(candidates, role, x, z, requiredWidth, accept)
|
||||
if usable[1] ~= nil then return usable[1].candidate end
|
||||
return nil, reason, args
|
||||
end
|
||||
|
||||
-- n sæt på én gang (multi-tool kræver alle baner): de n nærmeste, ellers ingen. notEnough har {ledige, n}.
|
||||
function ADFieldFleet.pickMany(candidates, role, n, x, z, requiredWidth, accept)
|
||||
local usable, reason, args = sortCandidates(candidates, role, x, z, requiredWidth, accept)
|
||||
if #usable >= n then
|
||||
local picked = {}
|
||||
for index = 1, n do picked[index] = usable[index].candidate end
|
||||
return picked
|
||||
end
|
||||
if #usable > 0 then return nil, "notEnough", {#usable, n} end
|
||||
return nil, reason, args
|
||||
end
|
||||
|
||||
function ADFieldFleet.toggle(enabledIds, id)
|
||||
|
||||
Reference in New Issue
Block a user