feat(pulje): flådefanen viser puljetraktorer og -redskaber med status og hvorfor de ikke er med; puljetraktorer omdøbes ikke efter lånte redskaber (v1.48.3.0)
This commit is contained in:
@@ -136,6 +136,8 @@ local function isBusyVehicle(vehicle, id)
|
||||
or (ADFieldSilos ~= nil and ADFieldSilos.isLoaned(vehicle)) or (ADPool ~= nil and ADPool.isReturning(vehicle))
|
||||
end
|
||||
|
||||
ADFieldWork.isBusyVehicle = isBusyVehicle
|
||||
|
||||
function ADFieldWork.getRigs(adEnv)
|
||||
local rigs = {}
|
||||
local state = ADFieldJobs.state
|
||||
@@ -1112,7 +1114,9 @@ function ADFieldWork.autoNameFleet(adEnv)
|
||||
local vehicle = rig.vehicle
|
||||
local stateModule = vehicle.ad ~= nil and vehicle.ad.stateModule or nil
|
||||
local model = vehicle.getName ~= nil and tostring(vehicle:getName()) or nil
|
||||
if stateModule ~= nil and stateModule.setName ~= nil and model ~= nil and ADRuns.vehicleLabel(vehicle) == model and not rig.controlled then
|
||||
-- puljetraktor med et lånt redskab: ikke opkaldt efter redskabet (in-game 28/9: Challenger blev "Kultivator 1")
|
||||
local pooled = ADHitch ~= nil and ADPool ~= nil and #ADHitch.poolParkIds(adEnv, vehicle) > 0
|
||||
if stateModule ~= nil and stateModule.setName ~= nil and model ~= nil and ADRuns.vehicleLabel(vehicle) == model and not rig.controlled and not pooled then
|
||||
local name = ADNaming.fleetName(rig.role, rig.role == "harvester" and harvesterSubtype(rig) or nil, names)
|
||||
if name ~= nil then
|
||||
stateModule:setName(name)
|
||||
|
||||
@@ -299,7 +299,8 @@ end
|
||||
|
||||
-- Puljeredskaber bag traktoren sættes af på deres parkering, og traktoren kører hjem til sin egen.
|
||||
-- Kun redskaber med en Connect-markør til deres parkering er puljeredskaber; andre bliver siddende.
|
||||
function ADHitch.returnHome(adEnv, tractor, onDone)
|
||||
-- Parkeringer (waypoint-id) for puljeredskaberne bag traktoren (tom = ingen puljeredskaber bag).
|
||||
function ADHitch.poolParkIds(adEnv, tractor)
|
||||
local markers = adEnv.ADGraphManager:getMapMarkers()
|
||||
local parkIds = {}
|
||||
for _, implement in ipairs(ADHitch.rearImplementsOf(tractor)) do
|
||||
@@ -307,6 +308,11 @@ function ADHitch.returnHome(adEnv, tractor, onDone)
|
||||
local park = parkId ~= nil and adEnv.ADGraphManager:getMapMarkerByWayPointId(parkId) or nil
|
||||
if park ~= nil and ADPool.connectFor(park.name, markers) ~= nil then table.insert(parkIds, parkId) end
|
||||
end
|
||||
return parkIds
|
||||
end
|
||||
|
||||
function ADHitch.returnHome(adEnv, tractor, onDone)
|
||||
local parkIds = ADHitch.poolParkIds(adEnv, tractor)
|
||||
if #parkIds == 0 then return false end
|
||||
local route = ADHitch.homeRoute(parkIds, parkIdOf(adEnv, tractor))
|
||||
ADPool.setReturning(tractor, true)
|
||||
|
||||
@@ -95,6 +95,29 @@ function ADPool.mayUsePool(decision, hasOwnForRole)
|
||||
return not decision.helper and (decision.count or 1) == 1 and not hasOwnForRole
|
||||
end
|
||||
|
||||
-- Status til flådefanen. s = {parkName, hasConnect, attachedTo, quarantineMin, reserved} -> nøgle, argument
|
||||
function ADPool.implementStatus(s)
|
||||
if s.parkName == nil then return "noPark" end
|
||||
if not s.hasConnect then return "noConnect", s.parkName end
|
||||
if s.attachedTo ~= nil then return "attached", s.attachedTo end
|
||||
if (s.quarantineMin or 0) > 0 then return "quarantine", s.quarantineMin end
|
||||
if s.reserved then return "reserved" end
|
||||
return "parked", s.parkName
|
||||
end
|
||||
|
||||
-- s = {hasPark, enabled, controlled, returning, fieldId, busy, offNetwork, hitched} -> nøgle, argument
|
||||
function ADPool.tractorStatus(s)
|
||||
if not s.hasPark then return "noPark" end
|
||||
if s.controlled then return "player" end
|
||||
if s.returning then return "returning" end
|
||||
if s.fieldId ~= nil then return "job", s.fieldId end
|
||||
if s.busy then return "busy" end
|
||||
if not s.enabled then return "notInFleet" end
|
||||
if s.offNetwork then return "offNetwork" end
|
||||
if s.hitched then return "hitched" end
|
||||
return "free"
|
||||
end
|
||||
|
||||
-- Redskab med rollen nærmest marken, derefter nærmeste ledige traktor med nok hk til redskabet.
|
||||
-- blocked = {[id] = true} (reserverede og redskaber i karantæne). accept (valgfri): implement -> bool.
|
||||
function ADPool.pairFor(role, fieldX, fieldZ, implements, tractors, blocked, accept)
|
||||
@@ -153,6 +176,19 @@ function ADPool.quarantine(id, nowMs)
|
||||
quarantined[id] = nowMs + ADPool.QUARANTINE_MS
|
||||
end
|
||||
|
||||
function ADPool.quarantineMinutes(id, nowMs)
|
||||
local untilMs = quarantined[id]
|
||||
if untilMs == nil or nowMs >= untilMs then return 0 end
|
||||
return math.ceil((untilMs - nowMs) / 60000)
|
||||
end
|
||||
|
||||
function ADPool.isReserved(id)
|
||||
for _, ids in pairs(reservations) do
|
||||
for _, reserved in ipairs(ids) do if reserved == id then return true end end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function ADPool.blocked(nowMs)
|
||||
local result = {}
|
||||
for _, ids in pairs(reservations) do
|
||||
@@ -213,6 +249,15 @@ local function isAttached(vehicle)
|
||||
return vehicle.getAttacherVehicle ~= nil and vehicle:getAttacherVehicle() ~= nil
|
||||
end
|
||||
|
||||
-- Traktorens egen rolle uden de redskaber der hænger på (mejetærsker/selvkørende har en, en traktor ikke).
|
||||
function ADPool.ownRole(vehicle)
|
||||
local specs = {}
|
||||
for _, name in ipairs(ADCpBridge.SPECS) do
|
||||
if vehicle[name] ~= nil then specs[name] = true end
|
||||
end
|
||||
return ADFieldFleet.roleFromSpecs(specs)
|
||||
end
|
||||
|
||||
-- Puljeredskaber (frakoblet, parkering "X", markør "Connect X") og puljetraktorer.
|
||||
-- isBusy(vehicle): markarbejdets optaget-regel (opgave, AD/CP kører, lånt af marksilo, på hjemtur).
|
||||
function ADPool.collect(adEnv, isBusy)
|
||||
@@ -245,7 +290,7 @@ function ADPool.collect(adEnv, isBusy)
|
||||
if id ~= nil and park ~= nil and vehicle.spec_attacherJoints ~= nil and #ADHitch.rearImplementsOf(vehicle) == 0
|
||||
and ADRunsController.getRunForVehicle(vehicle) == nil and not controlled and not isBusy(vehicle)
|
||||
and not ADPool.isReturning(vehicle) and ADFieldFleet.isEnabled(state.fleetMode, state.fleet, id)
|
||||
and ADPool.canPull(ADFieldFleet.roleFromSpecs(ADCpBridge.getSpecs(vehicle))) then
|
||||
and ADPool.canPull(ADPool.ownRole(vehicle)) then
|
||||
local x, z = positionOf(vehicle)
|
||||
-- uden for AD-vejnettet: den kan ikke køre ud efter redskabet (ville sende redskaber i karantæne)
|
||||
local networkDistance = ADFieldWork.distanceToNetwork(adEnv, x, z)
|
||||
@@ -256,3 +301,56 @@ function ADPool.collect(adEnv, isBusy)
|
||||
end
|
||||
return implements, tractors
|
||||
end
|
||||
|
||||
-- Oversigt til flådefanen: alle redskaber med en markrolle (også dem der mangler parkering/Connect, så
|
||||
-- spilleren kan se hvorfor) og alle traktorer uden egen arbejdsrolle, der ikke hører til et flow.
|
||||
function ADPool.overview(adEnv)
|
||||
local markers = adEnv.ADGraphManager:getMapMarkers()
|
||||
local farmId = g_currentMission:getFarmId()
|
||||
local nowMs = ADFieldJobs.now or 0
|
||||
local implements, tractors = {}, {}
|
||||
for _, vehicle in pairs(g_currentMission.vehicleSystem.vehicles) do
|
||||
local owned = vehicle.getOwnerFarmId ~= nil and vehicle:getOwnerFarmId() == farmId
|
||||
if owned and vehicle.spec_motorized == nil and vehicle.spec_attachable ~= nil then
|
||||
local role = ADPool.roleOf(ADCpBridge.getSpecs(vehicle))
|
||||
if role ~= nil then
|
||||
local id = ADRunsController.getVehicleId(vehicle)
|
||||
local park = parkMarker(adEnv, vehicle)
|
||||
local attacher = isAttached(vehicle) and vehicle:getAttacherVehicle() or nil
|
||||
local key, arg = ADPool.implementStatus({
|
||||
parkName = park ~= nil and park.name or nil,
|
||||
hasConnect = park ~= nil and ADPool.connectFor(park.name, markers) ~= nil,
|
||||
attachedTo = attacher ~= nil and ADRuns.vehicleLabel(attacher) or nil,
|
||||
quarantineMin = id ~= nil and ADPool.quarantineMinutes(id, nowMs) or 0,
|
||||
reserved = id ~= nil and ADPool.isReserved(id),
|
||||
})
|
||||
table.insert(implements, {id = id, label = ADRuns.vehicleLabel(vehicle), role = role, status = key, arg = arg})
|
||||
end
|
||||
end
|
||||
end
|
||||
local state = ADFieldJobs.state
|
||||
for _, vehicle in ipairs(ADRunsController.getFarmVehicles(adEnv)) do
|
||||
local id = ADRunsController.getVehicleId(vehicle)
|
||||
if id ~= nil and vehicle.spec_attacherJoints ~= nil and ADRunsController.getRunForVehicle(vehicle) == nil
|
||||
and ADPool.canPull(ADPool.ownRole(vehicle)) then
|
||||
local x, z = positionOf(vehicle)
|
||||
local distance = ADFieldWork.distanceToNetwork(adEnv, x, z)
|
||||
local assignment = state.assignments[id]
|
||||
local rear = ADHitch.rearImplementsOf(vehicle)
|
||||
local key, arg = ADPool.tractorStatus({
|
||||
hasPark = parkMarker(adEnv, vehicle) ~= nil,
|
||||
enabled = ADFieldFleet.isEnabled(state.fleetMode, state.fleet, id),
|
||||
controlled = vehicle.getIsControlled ~= nil and vehicle:getIsControlled(),
|
||||
returning = ADPool.isReturning(vehicle),
|
||||
fieldId = assignment ~= nil and assignment.fieldId or nil,
|
||||
busy = ADFieldWork.isBusyVehicle(vehicle, id),
|
||||
offNetwork = distance ~= nil and distance > ADFieldWork.MAX_OFF_NETWORK,
|
||||
hitched = #rear > 0,
|
||||
})
|
||||
table.insert(tractors, {id = id, label = ADRuns.vehicleLabel(vehicle), hp = tractorHpOf(vehicle), status = key, arg = arg,
|
||||
enabled = ADFieldFleet.isEnabled(state.fleetMode, state.fleet, id)})
|
||||
end
|
||||
end
|
||||
return implements, tractors
|
||||
end
|
||||
|
||||
|
||||
@@ -249,6 +249,35 @@ function SmartPickupFrame:fillFleetRows(adEnv)
|
||||
if #rigs == 0 then
|
||||
self:addTextRow(" " .. i18n:getText("spu_field_noRigs"))
|
||||
end
|
||||
if ADPool ~= nil and ADPool.overview ~= nil then self:fillPoolRows(adEnv) end
|
||||
end
|
||||
|
||||
-- Maskinpuljen: solo-traktorer (flueben som resten af flåden) og redskaber med status og hvorfor de ikke er med.
|
||||
function SmartPickupFrame:fillPoolRows(adEnv)
|
||||
local i18n = self.i18n
|
||||
local ok, implements, tractors = pcall(ADPool.overview, adEnv)
|
||||
if not ok then return end
|
||||
local byLabel = function(a, b) return ADFlowView.naturalLess(a.label, b.label) end
|
||||
table.sort(tractors, byLabel)
|
||||
table.sort(implements, function(a, b)
|
||||
if a.role ~= b.role then return a.role < b.role end
|
||||
return byLabel(a, b)
|
||||
end)
|
||||
self:addTextRow(i18n:getText("spu_pool_section_tractors"))
|
||||
for _, tractor in ipairs(tractors) do
|
||||
local row = self:addRow(self.vehiclePrefab, {kind = "fleetVehicle", vehicleId = tractor.id})
|
||||
local status = string.format(i18n:getText("spu_pool_tractor_" .. tractor.status), tostring(tractor.arg))
|
||||
local hp = tractor.hp ~= nil and string.format(", %.0f hk", tractor.hp) or ""
|
||||
row:getDescendantByName("title"):setText(string.format(" %s%s — %s", tostring(tractor.label), hp, status))
|
||||
row:getDescendantByName("option"):setState(tractor.enabled and SmartPickupFrame.STATE_ON or SmartPickupFrame.STATE_OFF, false)
|
||||
end
|
||||
if #tractors == 0 then self:addTextRow(" " .. i18n:getText("spu_pool_noTractors")) end
|
||||
self:addTextRow(i18n:getText("spu_pool_section_implements"))
|
||||
for _, implement in ipairs(implements) do
|
||||
local status = string.format(i18n:getText("spu_pool_implement_" .. implement.status), tostring(implement.arg))
|
||||
self:addTextRow(string.format(" %s — %s: %s", tostring(implement.label), self:roleText(implement.role), status))
|
||||
end
|
||||
if #implements == 0 then self:addTextRow(" " .. i18n:getText("spu_pool_noImplements")) end
|
||||
end
|
||||
|
||||
-- ---- live ----
|
||||
|
||||
@@ -85,6 +85,25 @@
|
||||
<text name="spu_field_reasonShort_rain" text="venter på tørvejr"/>
|
||||
<text name="spu_field_reasonShort_text" text="se detaljer"/>
|
||||
<text name="spu_field_reason_allBusy" text="venter på ledig %s"/>
|
||||
<text name="spu_pool_section_tractors" text="Maskinpulje — traktorer (henter redskaber når ingen færdig kombination er ledig)"/>
|
||||
<text name="spu_pool_section_implements" text="Maskinpulje — redskaber (parkering "X" + markør "Connect X")"/>
|
||||
<text name="spu_pool_noTractors" text="ingen traktorer uden redskab"/>
|
||||
<text name="spu_pool_noImplements" text="ingen redskaber med en markrolle"/>
|
||||
<text name="spu_pool_tractor_free" text="ledig%.0s"/>
|
||||
<text name="spu_pool_tractor_noPark" text="mangler egen AD-parkering%.0s"/>
|
||||
<text name="spu_pool_tractor_player" text="spilleren kører den%.0s"/>
|
||||
<text name="spu_pool_tractor_returning" text="sætter redskab af og kører hjem%.0s"/>
|
||||
<text name="spu_pool_tractor_job" text="opgave F%s"/>
|
||||
<text name="spu_pool_tractor_busy" text="AutoDrive/Courseplay kører%.0s"/>
|
||||
<text name="spu_pool_tractor_notInFleet" text="ikke i markflåden (flueben)%.0s"/>
|
||||
<text name="spu_pool_tractor_offNetwork" text="står uden for AutoDrive-vejnettet%.0s"/>
|
||||
<text name="spu_pool_tractor_hitched" text="har et redskab på (kobl det af for at bruge den i puljen)%.0s"/>
|
||||
<text name="spu_pool_implement_parked" text="parkeret ved %s"/>
|
||||
<text name="spu_pool_implement_noPark" text="ikke i puljen — mangler AD-parkering%.0s"/>
|
||||
<text name="spu_pool_implement_noConnect" text="ikke i puljen — mangler markøren "Connect %s""/>
|
||||
<text name="spu_pool_implement_attached" text="på %s"/>
|
||||
<text name="spu_pool_implement_quarantine" text="kunne ikke kobles på — prøves igen om %s min"/>
|
||||
<text name="spu_pool_implement_reserved" text="reserveret — en traktor er på vej%.0s"/>
|
||||
<text name="spu_field_reason_noPoolTractor" text="ingen ledig traktor til at hente et redskab til %s"/>
|
||||
<text name="spu_field_reasonShort_noPoolTractor" text="venter på traktor"/>
|
||||
<text name="spu_field_reason_fetching" text="henter '%s'"/>
|
||||
|
||||
@@ -85,6 +85,25 @@
|
||||
<text name="spu_field_reasonShort_rain" text="waiting for dry weather"/>
|
||||
<text name="spu_field_reasonShort_text" text="see details"/>
|
||||
<text name="spu_field_reason_allBusy" text="waiting for a free %s"/>
|
||||
<text name="spu_pool_section_tractors" text="Machine pool — tractors (fetch implements when no ready combination is free)"/>
|
||||
<text name="spu_pool_section_implements" text="Machine pool — implements (park "X" + marker "Connect X")"/>
|
||||
<text name="spu_pool_noTractors" text="no tractors without implement"/>
|
||||
<text name="spu_pool_noImplements" text="no implements with a field role"/>
|
||||
<text name="spu_pool_tractor_free" text="free%.0s"/>
|
||||
<text name="spu_pool_tractor_noPark" text="needs its own AD park destination%.0s"/>
|
||||
<text name="spu_pool_tractor_player" text="player is driving%.0s"/>
|
||||
<text name="spu_pool_tractor_returning" text="dropping implement and driving home%.0s"/>
|
||||
<text name="spu_pool_tractor_job" text="job F%s"/>
|
||||
<text name="spu_pool_tractor_busy" text="AutoDrive/Courseplay active%.0s"/>
|
||||
<text name="spu_pool_tractor_notInFleet" text="not in field fleet (tick)%.0s"/>
|
||||
<text name="spu_pool_tractor_offNetwork" text="off the AutoDrive network%.0s"/>
|
||||
<text name="spu_pool_tractor_hitched" text="has an implement attached (detach it to use the pool)%.0s"/>
|
||||
<text name="spu_pool_implement_parked" text="parked at %s"/>
|
||||
<text name="spu_pool_implement_noPark" text="not in pool — needs an AD park destination%.0s"/>
|
||||
<text name="spu_pool_implement_noConnect" text="not in pool — needs marker "Connect %s""/>
|
||||
<text name="spu_pool_implement_attached" text="on %s"/>
|
||||
<text name="spu_pool_implement_quarantine" text="could not attach — retry in %s min"/>
|
||||
<text name="spu_pool_implement_reserved" text="reserved — a tractor is on its way%.0s"/>
|
||||
<text name="spu_field_reason_noPoolTractor" text="no free tractor to fetch an implement for %s"/>
|
||||
<text name="spu_field_reasonShort_noPoolTractor" text="waiting for tractor"/>
|
||||
<text name="spu_field_reason_fetching" text="fetching '%s'"/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<modDesc descVersion="107">
|
||||
<author>masterdraco</author>
|
||||
<version>1.48.2.0</version>
|
||||
<version>1.48.3.0</version>
|
||||
<title>
|
||||
<en>AD Smart Pickup</en>
|
||||
</title>
|
||||
|
||||
@@ -102,5 +102,33 @@ check("I4: almindelig", P.mayUsePool({count = 1}, false), true)
|
||||
check("I4: tømmevogn", P.mayUsePool({count = 1, helper = true}, false), false)
|
||||
check("I4: multi-tool", P.mayUsePool({count = 2}, false), false)
|
||||
check("I4: marken har faste", P.mayUsePool({count = 1}, true), false)
|
||||
-- status til flådefanen
|
||||
local function st(key, arg) return tostring(key) .. "|" .. tostring(arg) end
|
||||
local function ist(s) return st(P.implementStatus(s)) end
|
||||
check("redskab: uden parkering", ist({}), "noPark|nil")
|
||||
check("redskab: uden Connect", ist({parkName = "Plov"}), "noConnect|Plov")
|
||||
check("redskab: på traktor", ist({parkName = "Plov", hasConnect = true, attachedTo = "MT635"}), "attached|MT635")
|
||||
check("redskab: karantæne", ist({parkName = "Plov", hasConnect = true, quarantineMin = 8}), "quarantine|8")
|
||||
check("redskab: reserveret", ist({parkName = "Plov", hasConnect = true, reserved = true}), "reserved|nil")
|
||||
check("redskab: parkeret", ist({parkName = "Plov", hasConnect = true}), "parked|Plov")
|
||||
local function tst(s) return st(P.tractorStatus(s)) end
|
||||
local base = {hasPark = true, enabled = true}
|
||||
check("traktor: uden parkering", tst({enabled = true}), "noPark|nil")
|
||||
check("traktor: spiller", tst({hasPark = true, enabled = true, controlled = true}), "player|nil")
|
||||
check("traktor: hjemtur", tst({hasPark = true, enabled = true, returning = true}), "returning|nil")
|
||||
check("traktor: opgave", tst({hasPark = true, enabled = true, fieldId = 52}), "job|52")
|
||||
check("traktor: optaget", tst({hasPark = true, enabled = true, busy = true}), "busy|nil")
|
||||
check("traktor: ikke i flåden", tst({hasPark = true}), "notInFleet|nil")
|
||||
check("traktor: uden for vejnet", tst({hasPark = true, enabled = true, offNetwork = true}), "offNetwork|nil")
|
||||
check("traktor: har andet redskab på", tst({hasPark = true, enabled = true, hitched = true}), "hitched|nil")
|
||||
check("traktor: ledig", tst(base), "free|nil")
|
||||
-- karantæne-rest i hele minutter (rundet op) og reservation
|
||||
P.quarantine("q1", 0)
|
||||
check("karantæne: minutter tilbage", P.quarantineMinutes("q1", 60000), 9)
|
||||
check("karantæne: udløbet", P.quarantineMinutes("q1", P.QUARANTINE_MS), 0)
|
||||
P.reserve("owner", {"r1"})
|
||||
check("reserveret: ja", P.isReserved("r1"), true)
|
||||
P.release("owner")
|
||||
check("reserveret: nej", P.isReserved("r1"), false)
|
||||
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
||||
os.exit(failures == 0 and 0 or 1)
|
||||
|
||||
Reference in New Issue
Block a user