feat: flow-guide tildeler ledige vogne til solo-traktorer

Solo-traktorer (ingen vogn bagpå) er valgbare når en frakoblet vogn med
Connect-markør kan bære flowets varer. Guiden foreslår en vogn (navnematch,
så Disponibel) med vognvalg pr. traktor; flowet husker parret ved gem, så
vognens parkering ikke skal omdøbes.
This commit is contained in:
2026-09-29 20:48:04 +02:00
parent 87b030d492
commit 1739b01d92
8 changed files with 232 additions and 8 deletions
@@ -108,15 +108,76 @@ function SmartPickupFrame:flowStoreContext(adEnv, preview, farmId)
return result
end
function SmartPickupFrame:flowVehicleContext(adEnv, preview)
-- Varer (fillType-indeks) flowet kører med: udkørsel = valgte produkter, forsyning = valgte/målets varer.
-- Tom liste = ukendt endnu (ingen mål valgt) -> enhver vogn med last-enheder tæller.
local function flowFillTypes(adEnv, preview)
local names = {}
if preview.kind == "outbound" then
for _, product in ipairs(preview.products or {}) do table.insert(names, product.fillType) end
elseif preview.ingredientMode == "manual" then
names = preview.ingredients or {}
else
for _, fillType in ipairs(ADRunsController.getTargetAcceptedFillTypes(adEnv, preview)) do table.insert(names, fillType.name) end
end
local result = {}
for _, name in ipairs(names) do
local index = g_fillTypeManager:getFillTypeIndexByName(tostring(name))
if index ~= nil then table.insert(result, index) end
end
return result
end
local function carriesAny(carriable, wanted)
if #carriable == 0 then return false end
if #wanted == 0 then return true end
for _, a in ipairs(carriable) do
for _, b in ipairs(wanted) do if a == b then return true end end
end
return false
end
-- Ledige vogne til solo-traktorer: frakoblet, egen AD-parkering med "Connect"-markør, ikke holdt af et andet flow
-- og kan bære flowets varer. Bedste først (navnematch, så "Disponibel"). In-game 29/9: flowet kunne ikke oprettes
-- uden at omdøbe en vogns parkering til flowets navn.
function SmartPickupFrame:flowWagonContext(adEnv, preview)
local farmId = g_currentMission:getFarmId()
local markers = adEnv.ADGraphManager:getMapMarkers()
local wanted = flowFillTypes(adEnv, preview)
local candidates = {}
for _, any in pairs(g_currentMission.vehicleSystem.vehicles) do
local ok, entry = pcall(function()
local index = any.advd ~= nil and any.advd.parkDestination or nil
if any.spec_motorized ~= nil or any.spec_attachable == nil or type(index) ~= "number" or index < 1 then return nil end
if any.getAttacherVehicle ~= nil and any:getAttacherVehicle() ~= nil then return nil end
if any.getOwnerFarmId == nil or any:getOwnerFarmId() ~= farmId then return nil end
local id = ADRunsController.getVehicleId(any)
local park = adEnv.ADGraphManager:getMapMarkerById(index)
if id == nil or park == nil or ADPool.connectFor(park.name, markers) == nil then return nil end
local owner = ADFlowWagons.ownerOf(ADRunsController.store.runs, id)
if owner ~= nil and owner.id ~= preview.id then return nil end
if not carriesAny(ADRunsController.getCarriableFillTypes(adEnv, any), wanted) then return nil end
return {id = id, label = tostring(park.name)}
end)
if ok and entry ~= nil then table.insert(candidates, entry) end
end
return ADFlowWagons.rankWagons(preview.name, candidates)
end
function SmartPickupFrame:flowVehicleContext(adEnv, preview, wagons)
local result = {}
local hasWagons = wagons ~= nil and #wagons > 0
for _, vehicle in ipairs(ADRunsController.getFarmVehicles(adEnv)) do
local ok, entry = pcall(function()
local text = self:describeVehicle(adEnv, preview, vehicle, false)
local validation = ADRunsController.validateVehicle(adEnv, preview, vehicle)
local other = ADRunsController.getRunForVehicle(vehicle)
return {id = ADRunsController.getVehicleId(vehicle), text = text, label = ADRunsController.getVehicleLabel(adEnv, vehicle), otherRunId = other ~= nil and other.id or nil,
otherRunName = other ~= nil and other.name or nil, blocked = SmartPickupFrame.VEHICLE_BLOCKING_REASONS[validation.reason] == true}
local label = ADRunsController.getVehicleLabel(adEnv, vehicle)
-- solo-traktor (ingen vogn bagpå, kan trække): valgbar når en ledig vogn findes — den hentes ved Connect
local solo = validation.reason == "noTrailer" and ADPool.canPull(ADPool.ownRole(vehicle))
if solo and hasWagons then text = string.format(self.i18n:getText("spu_guide_flow_soloText"), tostring(label)) end
local blocked = SmartPickupFrame.VEHICLE_BLOCKING_REASONS[validation.reason] == true and not (solo and hasWagons)
return {id = ADRunsController.getVehicleId(vehicle), text = text, label = label, otherRunId = other ~= nil and other.id or nil,
otherRunName = other ~= nil and other.name or nil, blocked = blocked, solo = solo}
end)
if ok and entry.id ~= nil then
table.insert(result, entry)
@@ -140,7 +201,9 @@ function SmartPickupFrame:flowGuideContext(adEnv, draft)
return ids
end)
local context = {buildings = self:flowBuildingContext(adEnv, draft, farmId), fillTypes = {}, products = {}, storeBuildings = {},
waitPools = ADRunsController.getWaitPools(adEnv), vehicles = self:flowVehicleContext(adEnv, preview)}
waitPools = ADRunsController.getWaitPools(adEnv)}
context.wagons = self:flowWagonContext(adEnv, preview)
context.vehicles = self:flowVehicleContext(adEnv, preview, context.wagons)
if draft.kind == "outbound" then
for _, product in ipairs(ADRunsController.getRunProducts(adEnv, preview)) do
local title = tostring(product.title)
@@ -371,6 +434,13 @@ function SmartPickupFrame:saveFlowGuide(guide, start)
local vehicle = adEnv ~= nil and ADRunsController.findVehicleById(adEnv, id) or nil
if vehicle ~= nil then ADRunsController.assignVehicle(runId, vehicle) end
end
-- solo-traktorernes vogne fra guiden: flowet husker dem straks og henter dem ved Connect ved start
local savedRun = ADRuns.getRun(ADRunsController.store, runId)
if savedRun ~= nil then
local wagons = ADRuns.copyWagons(savedRun.wagons)
for tractorId, wagonId in pairs(result.wagons or {}) do wagons[tractorId] = wagonId end
savedRun.wagons = wagons
end
ADRunsController.resolveMarkers(adEnv, ADRuns.getRun(ADRunsController.store, runId))
self.selectedRunId = runId
local saved = string.format(self.i18n:getText("spu_guide_flow_saved"), tostring(result.name))