OPSTRANSPORT

- Fist working steps towards multiple pickup/deploy zone combos.
This commit is contained in:
Frank 2021-08-28 00:17:16 +02:00
parent fe6826016c
commit 28ddfa5243
3 changed files with 244 additions and 58 deletions

View File

@ -288,6 +288,23 @@ function ZONE_BASE:GetCoordinate( Height ) --R2.1
return self.Coordinate return self.Coordinate
end end
--- Get 2D distance to a coordinate.
-- @param #ZONE_BASE self
-- @param Core.Point#COORDINATE Coordinate Reference coordinate. Can also be a DCS#Vec2 or DCS#Vec3 object.
-- @return #number Distance to the reference coordinate in meters.
function ZONE_BASE:Get2DDistance(Coordinate)
local a=self:GetVec2()
local b={}
if Coordinate.z then
b.x=Coordinate.x
b.y=Coordinate.z
else
b.x=Coordinate.x
b.y=Coordinate.y
end
local dist=UTILS.VecDist2D(a,b)
return dist
end
--- Define a random @{DCS#Vec2} within the zone. --- Define a random @{DCS#Vec2} within the zone.
-- @param #ZONE_BASE self -- @param #ZONE_BASE self

View File

@ -115,6 +115,7 @@
-- @field #table cargoqueue Table containing cargo groups to be transported. -- @field #table cargoqueue Table containing cargo groups to be transported.
-- @field #table cargoBay Table containing OPSGROUP loaded into this group. -- @field #table cargoBay Table containing OPSGROUP loaded into this group.
-- @field Ops.OpsTransport#OPSTRANSPORT cargoTransport Current cargo transport assignment. -- @field Ops.OpsTransport#OPSTRANSPORT cargoTransport Current cargo transport assignment.
-- @field Ops.OpsTransport#OPSTRANSPORT.TransportZone transportZone Transport zones (pickup, deploy etc.).
-- @field #string cargoStatus Cargo status of this group acting as cargo. -- @field #string cargoStatus Cargo status of this group acting as cargo.
-- @field #number cargoTransportUID Unique ID of the transport assignment this cargo group is associated with. -- @field #number cargoTransportUID Unique ID of the transport assignment this cargo group is associated with.
-- @field #string carrierStatus Carrier status of this group acting as cargo carrier. -- @field #string carrierStatus Carrier status of this group acting as cargo carrier.
@ -476,6 +477,7 @@ OPSGROUP.version="0.7.5"
-- TODO: Damage? -- TODO: Damage?
-- TODO: Shot events? -- TODO: Shot events?
-- TODO: Marks to add waypoints/tasks on-the-fly. -- TODO: Marks to add waypoints/tasks on-the-fly.
-- DONE: A lot.
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor -- Constructor
@ -687,7 +689,13 @@ function OPSGROUP:New(group)
--- Triggers the FSM event "MissionCancel". --- Triggers the FSM event "MissionCancel".
-- @function [parent=#OPSGROUP] MissionCancel -- @function [parent=#OPSGROUP] MissionCancel
-- @param #CHIEF self -- @param #OPSGROUP self
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
--- Triggers the FSM event "MissionCancel" after a delay
-- @function [parent=#OPSGROUP] MissionCancel
-- @param #OPSGROUP self
-- @param #number delay Delay in seconds.
-- @param Ops.Auftrag#AUFTRAG Mission The mission. -- @param Ops.Auftrag#AUFTRAG Mission The mission.
--- On after "MissionCancel" event. --- On after "MissionCancel" event.
@ -1769,6 +1777,36 @@ function OPSGROUP:SetCarrierUnloaderPort(Length, Width)
return self return self
end end
--- Check if group is currently inside a zone.
-- @param #OPSGROUP self
-- @param Core.Zone#ZONE Zone The zone.
-- @return #boolean If true, group is in this zone
function OPSGROUP:IsInZone(Zone)
local vec2=self:GetVec2()
local is=Zone:IsVec2InZone(vec2)
return is
end
--- Get 2D distance to a coordinate.
-- @param #OPSGROUP self
-- @param Core.Point#COORDINATE Coordinate. Can also be a DCS#Vec2 or DCS#Vec3.
-- @return #number Distance in meters.
function OPSGROUP:Get2DDistance(Coordinate)
local a=self:GetVec2()
local b={}
if Coordinate.z then
b.x=Coordinate.x
b.y=Coordinate.z
else
b.x=Coordinate.x
b.y=Coordinate.y
end
local dist=UTILS.VecDist2D(a, b)
return dist
end
--- Check if this is a FLIGHTGROUP. --- Check if this is a FLIGHTGROUP.
-- @param #OPSGROUP self -- @param #OPSGROUP self
@ -4972,11 +5010,11 @@ function OPSGROUP:_UpdateLaser()
end end
--- On before "ElementSpawned" event. Check that element is not in status spawned already. --- On before "ElementSpawned" event. Check that element is not in status spawned already.
-- @param #FLIGHTGROUP self -- @param #OPSGROUP self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
-- @param Ops.OpsGroup#OPSGROUP.Element Element The flight group element. -- @param #OPSGROUP.Element Element The flight group element.
function OPSGROUP:onbeforeElementSpawned(From, Event, To, Element) function OPSGROUP:onbeforeElementSpawned(From, Event, To, Element)
if Element and Element.status==OPSGROUP.ElementStatus.SPAWNED then if Element and Element.status==OPSGROUP.ElementStatus.SPAWNED then
@ -5505,10 +5543,19 @@ function OPSGROUP:_CheckCargoTransport()
if self:IsNotCarrier() then if self:IsNotCarrier() then
-- Debug info. -- Debug info.
self:T(self.lid.."Not carrier ==> pickup") self:T(self.lid.."Not carrier ==> pickup?")
-- Get transport zones.
local transportZone=self.cargoTransport:_GetPickupZone(self)
if transportZone then
-- Initiate the cargo transport process. -- Initiate the cargo transport process.
self:__Pickup(-1) self:__Pickup(-1, transportZone)
else
self:T(self.lid.."Not carrier ==> pickup")
end
elseif self:IsPickingup() then elseif self:IsPickingup() then
@ -5730,13 +5777,16 @@ function OPSGROUP:_GetNextCargoTransport()
local function _sort(a, b) local function _sort(a, b)
local transportA=a --Ops.OpsTransport#OPSTRANSPORT local transportA=a --Ops.OpsTransport#OPSTRANSPORT
local transportB=b --Ops.OpsTransport#OPSTRANSPORT local transportB=b --Ops.OpsTransport#OPSTRANSPORT
local distA=transportA.pickupzone:GetCoordinate():Get2DDistance(coord) --TODO: Include distance
local distB=transportB.pickupzone:GetCoordinate():Get2DDistance(coord) --local distA=transportA.pickupzone:GetCoordinate():Get2DDistance(coord)
return (transportA.prio<transportB.prio) or (transportA.prio==transportB.prio and distA<distB) --local distB=transportB.pickupzone:GetCoordinate():Get2DDistance(coord)
return (transportA.prio<transportB.prio) --or (transportA.prio==transportB.prio and distA<distB)
end end
table.sort(self.cargoqueue, _sort) table.sort(self.cargoqueue, _sort)
-- Look for first mission that is SCHEDULED. -- TODO: Find smarter next transport.
-- Importance.
local vip=math.huge local vip=math.huge
for _,_cargotransport in pairs(self.cargoqueue) do for _,_cargotransport in pairs(self.cargoqueue) do
local cargotransport=_cargotransport --Ops.OpsTransport#OPSTRANSPORT local cargotransport=_cargotransport --Ops.OpsTransport#OPSTRANSPORT
@ -6231,16 +6281,19 @@ end
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
function OPSGROUP:onafterPickup(From, Event, To) -- @param Ops.OpsTransport#OPSTRANSPORT.TransportZone TransportZone The transport zones data table.
function OPSGROUP:onafterPickup(From, Event, To, TransportZone)
-- Set carrier status. -- Set carrier status.
self:_NewCarrierStatus(OPSGROUP.CarrierStatus.PICKUP) self:_NewCarrierStatus(OPSGROUP.CarrierStatus.PICKUP)
self.transportZone=TransportZone
-- Pickup zone. -- Pickup zone.
local Zone=self.cargoTransport.pickupzone local Zone=TransportZone.PickupZone
-- Check if already in the pickup zone. -- Check if already in the pickup zone.
local inzone=Zone:IsCoordinateInZone(self:GetCoordinate()) local inzone=self:IsInZone(Zone)
local airbasePickup=nil --Wrapper.Airbase#AIRBASE local airbasePickup=nil --Wrapper.Airbase#AIRBASE
if Zone and Zone:IsInstanceOf("ZONE_AIRBASE") then if Zone and Zone:IsInstanceOf("ZONE_AIRBASE") then
@ -6278,7 +6331,7 @@ function OPSGROUP:onafterPickup(From, Event, To)
local Coordinate=Zone:GetRandomCoordinate() local Coordinate=Zone:GetRandomCoordinate()
-- Add waypoint. -- Add waypoint.
if self.isFlightgroup then if self:IsFlightgroup() then
--- ---
-- Flight Group -- Flight Group
@ -6377,6 +6430,7 @@ function OPSGROUP:onafterPickup(From, Event, To)
-- ARMYGROUP -- ARMYGROUP
local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, nil, uid) ; waypoint.detour=1 local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, nil, uid) ; waypoint.detour=1
-- Give cruise command.
self:__Cruise(-2) self:__Cruise(-2)
end end
@ -6406,14 +6460,15 @@ function OPSGROUP:onafterLoading(From, Event, To)
local cargo=_cargo --#OPSGROUP.CargoGroup local cargo=_cargo --#OPSGROUP.CargoGroup
-- Check that cargo weight is -- Check that cargo weight is
if self:CanCargo(cargo.opsgroup) and not (cargo.delivered or cargo.opsgroup:IsDead()) then if self:CanCargo(cargo.opsgroup) and (not (cargo.delivered or cargo.opsgroup:IsDead())) then
-- Check that group is NOT cargo and NOT acting as carrier already -- Check that group is NOT cargo and NOT acting as carrier already
-- TODO: Need a better :IsBusy() function or :IsReadyForMission() :IsReadyForBoarding() :IsReadyForTransport() -- TODO: Need a better :IsBusy() function or :IsReadyForMission() :IsReadyForBoarding() :IsReadyForTransport()
if cargo.opsgroup:IsNotCargo(true) and not (cargo.opsgroup:IsPickingup() or cargo.opsgroup:IsLoading() or cargo.opsgroup:IsTransporting() or cargo.opsgroup:IsUnloading()) then if cargo.opsgroup:IsNotCargo(true) and not (cargo.opsgroup:IsPickingup() or cargo.opsgroup:IsLoading() or cargo.opsgroup:IsTransporting() or cargo.opsgroup:IsUnloading()) then
-- Check if cargo is in embark/pickup zone. -- Check if cargo is in embark/pickup zone.
local inzone=self.cargoTransport.embarkzone:IsCoordinateInZone(cargo.opsgroup:GetCoordinate()) --local inzone=self.cargoTransport.embarkzone:IsCoordinateInZone(cargo.opsgroup:GetCoordinate())
local inzone=cargo.opsgroup:IsInZone(self.transportZone.EmbarkZone)
-- Cargo MUST be inside zone or it will not be loaded! -- Cargo MUST be inside zone or it will not be loaded!
if inzone then if inzone then
@ -6450,22 +6505,6 @@ function OPSGROUP:onafterLoading(From, Event, To)
end end
--- Clear waypoints.
-- @param #OPSGROUP self
-- @param #number IndexMin Clear waypoints up to this min WP index. Default 1.
-- @param #number IndexMax Clear waypoints up to this max WP index. Default `#self.waypoints`.
function OPSGROUP:ClearWaypoints(IndexMin, IndexMax)
IndexMin=IndexMin or 1
IndexMax=IndexMax or #self.waypoints
-- Clear all waypoints.
for i=IndexMax,IndexMin,-1 do
table.remove(self.waypoints, i)
end
--self.waypoints={}
end
--- Set (new) cargo status. --- Set (new) cargo status.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #string Status New status. -- @param #string Status New status.
@ -6614,10 +6653,10 @@ function OPSGROUP:onafterTransport(From, Event, To)
--TODO: This is all very similar to the onafterPickup() function. Could make it general. --TODO: This is all very similar to the onafterPickup() function. Could make it general.
-- Deploy zone. -- Deploy zone.
local Zone=self.cargoTransport.deployzone local Zone=self.transportZone.DeployZone
-- Check if already in deploy zone. -- Check if already in deploy zone.
local inzone=Zone:IsCoordinateInZone(self:GetCoordinate()) local inzone=self:IsInZone(Zone) --Zone:IsCoordinateInZone(self:GetCoordinate())
local airbaseDeploy=nil --Wrapper.Airbase#AIRBASE local airbaseDeploy=nil --Wrapper.Airbase#AIRBASE
if Zone and Zone:IsInstanceOf("ZONE_AIRBASE") then if Zone and Zone:IsInstanceOf("ZONE_AIRBASE") then
@ -7019,9 +7058,17 @@ function OPSGROUP:onafterUnloadingDone(From, Event, To)
if not delivered then if not delivered then
local transportZone=self.cargoTransport:_GetPathPickup()
if transportZone then
-- Pickup the next batch. -- Pickup the next batch.
self:I(self.lid.."Unloaded: Still cargo left ==> Pickup") self:I(self.lid.."Unloaded: Still cargo left ==> Pickup")
self:Pickup(self.cargoTransport.pickupzone) self:Pickup(transportZone)
else
env.info("FF error not implemented case!")
end
else else
@ -9920,6 +9967,22 @@ function OPSGROUP:_GetTemplate(Copy)
return nil return nil
end end
--- Clear waypoints.
-- @param #OPSGROUP self
-- @param #number IndexMin Clear waypoints up to this min WP index. Default 1.
-- @param #number IndexMax Clear waypoints up to this max WP index. Default `#self.waypoints`.
function OPSGROUP:ClearWaypoints(IndexMin, IndexMax)
IndexMin=IndexMin or 1
IndexMax=IndexMax or #self.waypoints
-- Clear all waypoints.
for i=IndexMax,IndexMin,-1 do
table.remove(self.waypoints, i)
end
--self.waypoints={}
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -38,11 +38,11 @@
-- @field #number Tstop Stop time in *abs.* seconds. Default `#nil` (never stops). -- @field #number Tstop Stop time in *abs.* seconds. Default `#nil` (never stops).
-- @field #number duration Duration (`Tstop-Tstart`) of the transport in seconds. -- @field #number duration Duration (`Tstop-Tstart`) of the transport in seconds.
-- @field #table conditionStart Start conditions. -- @field #table conditionStart Start conditions.
-- @field #table transportZones Table of transport zones. Each element of the table is of type `#OPSTRANSPORT.TransportZone`.
-- @field Core.Zone#ZONE pickupzone Zone where the cargo is picked up. -- @field Core.Zone#ZONE pickupzone Zone where the cargo is picked up.
-- @field Core.Zone#ZONE deployzone Zone where the cargo is dropped off. -- @field Core.Zone#ZONE deployzone Zone where the cargo is dropped off.
-- @field Core.Zone#ZONE embarkzone (Optional) Zone where the cargo is supposed to embark. Default is the pickup zone. -- @field Core.Zone#ZONE embarkzone (Optional) Zone where the cargo is supposed to embark. Default is the pickup zone.
-- @field Core.Zone#ZONE disembarkzone (Optional) Zone where the cargo is disembarked. Default is the deploy zone. -- @field Core.Zone#ZONE disembarkzone (Optional) Zone where the cargo is disembarked. Default is the deploy zone.
-- @field Core.Zone#ZONE unboardzone (Optional) Zone where the cargo is going to after disembarkment.
-- @field #boolean disembarkActivation Activation setting when group is disembared from carrier. -- @field #boolean disembarkActivation Activation setting when group is disembared from carrier.
-- @field #boolean disembarkInUtero Do not spawn the group in any any state but leave it "*in utero*". For example, to directly load it into another carrier. -- @field #boolean disembarkInUtero Do not spawn the group in any any state but leave it "*in utero*". For example, to directly load it into another carrier.
-- @field #table disembarkCarriers Table of carriers to which the cargo is disembared. This is a direct transfer from the old to the new carrier. -- @field #table disembarkCarriers Table of carriers to which the cargo is disembared. This is a direct transfer from the old to the new carrier.
@ -117,6 +117,7 @@ OPSTRANSPORT = {
cargos = {}, cargos = {},
carriers = {}, carriers = {},
carrierTransportStatus = {}, carrierTransportStatus = {},
transportZones = {},
conditionStart = {}, conditionStart = {},
pathsTransport = {}, pathsTransport = {},
pathsPickup = {}, pathsPickup = {},
@ -141,13 +142,22 @@ OPSTRANSPORT.Status={
DELIVERED="delivered", DELIVERED="delivered",
} }
--- Path. --- Pickup and deploy set.
-- @type OPSTRANSPORT.TransportZone
-- @field Core.Zone#ZONE PickupZone Pickup zone.
-- @field Core.Zone#ZONE DeployZone Deploy zone.
-- @field Core.Zone#ZONE EmbarkZone Embark zone if different from pickup zone.
-- @field #OPSTRANSPORT.Path PickupPath Path for pickup.
-- @field #OPSTRANSPORT.Path TransportPath Path for Transport.
-- @field #numberr Ncarriers Number of carrier groups using this transport zone.
--- Path used for pickup or transport.
-- @type OPSTRANSPORT.Path -- @type OPSTRANSPORT.Path
-- @field #table coords Table of coordinates. -- @field #table coords Table of coordinates.
-- @field #number radius Radomization radius in meters. Default 0 m. -- @field #number radius Radomization radius in meters. Default 0 m.
-- @field #number altitude Altitude in feet AGL. Only for aircraft. -- @field #number altitude Altitude in feet AGL. Only for aircraft.
--- Generic mission condition. --- Generic transport condition.
-- @type OPSTRANSPORT.Condition -- @type OPSTRANSPORT.Condition
-- @field #function func Callback function to check for a condition. Should return a #boolean. -- @field #function func Callback function to check for a condition. Should return a #boolean.
-- @field #table arg Optional arguments passed to the condition callback function. -- @field #table arg Optional arguments passed to the condition callback function.
@ -163,6 +173,7 @@ OPSTRANSPORT.version="0.3.0"
-- TODO list -- TODO list
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Allow multiple pickup/depoly zones.
-- TODO: Stop/abort transport. -- TODO: Stop/abort transport.
-- DONE: Add start conditions. -- DONE: Add start conditions.
-- DONE: Check carrier(s) dead. -- DONE: Check carrier(s) dead.
@ -295,6 +306,31 @@ function OPSTRANSPORT:AddCargoGroups(GroupSet)
return self return self
end end
--- Add pickup and deploy zone combination. Optionally, embark and disembark zones can be specified.
--
-- * The pickup zone is a zone where
-- * bla
--
-- @param #OPSTRANSPORT self
-- @param Core.Zone#ZONE PickupZone Zone where the troops are picked up.
-- @return #OPSTRANSPORT.TransportZone Transport zone table.
function OPSTRANSPORT:AddTransportZones(PickupZone, DeployZone, EmbarkZone, DisembarkZone, PickupPath, TransportPath)
local transport={} --#OPSTRANSPORT.TransportZone
transport.PickupZone=PickupZone
transport.DeployZone=DeployZone
transport.EmbarkZone=EmbarkZone or PickupZone
transport.DisembarkZone=DisembarkZone
transport.PickupPath=PickupPath
transport.TransportPath=TransportPath
transport.Ncarriers=0
table.insert(self.transportZones, transport)
return transport
end
--- Set pickup zone. --- Set pickup zone.
-- @param #OPSTRANSPORT self -- @param #OPSTRANSPORT self
-- @param Core.Zone#ZONE PickupZone Zone where the troops are picked up. -- @param Core.Zone#ZONE PickupZone Zone where the troops are picked up.
@ -501,18 +537,21 @@ end
--- Get (all) cargo @{Ops.OpsGroup#OPSGROUP}s. Optionally, only delivered or undelivered groups can be returned. --- Get (all) cargo @{Ops.OpsGroup#OPSGROUP}s. Optionally, only delivered or undelivered groups can be returned.
-- @param #OPSTRANSPORT self -- @param #OPSTRANSPORT self
-- @param #boolean Delivered If `true`, only delivered groups are returned. If `false` only undelivered groups are returned. If `nil`, all groups are returned. -- @param #boolean Delivered If `true`, only delivered groups are returned. If `false` only undelivered groups are returned. If `nil`, all groups are returned.
-- @return #table Cargo Ops groups. -- @param Ops.OpsGroup#OPSGROUP Carrier (Optional) Only count cargo groups that fit into the given carrier group. Current cargo is not a factor.
function OPSTRANSPORT:GetCargoOpsGroups(Delivered) -- @return #table Cargo Ops groups. Can be and empty table `{}`.
function OPSTRANSPORT:GetCargoOpsGroups(Delivered, Carrier)
local opsgroups={} local opsgroups={}
for _,_cargo in pairs(self.cargos) do for _,_cargo in pairs(self.cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if Delivered==nil or cargo.delivered==Delivered then if Delivered==nil or cargo.delivered==Delivered then
if cargo.opsgroup and not (cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped()) then if cargo.opsgroup and not (cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped()) then
if Carrier==nil or Carrier:CanCargo(cargo.opsgroup) then
table.insert(opsgroups, cargo.opsgroup) table.insert(opsgroups, cargo.opsgroup)
end end
end end
end end
end
return opsgroups return opsgroups
end end
@ -816,24 +855,27 @@ function OPSTRANSPORT:IsReadyToGo()
-- Current abs time. -- Current abs time.
local Tnow=timer.getAbsTime() local Tnow=timer.getAbsTime()
-- Pickup and deploy zones must be set. -- Pickup AND deploy zones must be set.
if not self.pickupzone then local gotzones=false
text=text.."No, pickup zone not defined!" for _,_tz in pairs(self.transportZones) do
return false local tz=_tz --#OPSTRANSPORT.TransportZone
if tz.PickupZone and tz.DeployZone then
gotzones=true
break
end end
if not self.deployzone then end
text=text.."No, deploy zone not defined!" if not gotzones then
return false text=text.."No, pickup/deploy zone combo not yet defined!"
end end
-- Start time did not pass yet. -- Start time did not pass yet.
if self.Tstart and Tnow<self.Tstart or false then if self.Tstart and Tnow<self.Tstart then
text=text.."No, start time not passed!" text=text.."No, start time not passed!"
return false return false
end end
-- Stop time already passed. -- Stop time already passed.
if self.Tstop and Tnow>self.Tstop or false then if self.Tstop and Tnow>self.Tstop then
text=text.."Nope, stop time already passed!" text=text.."Nope, stop time already passed!"
self:T(text) self:T(text)
return false return false
@ -914,13 +956,21 @@ function OPSTRANSPORT:onafterStatus(From, Event, To)
if self.verbose>=1 then if self.verbose>=1 then
-- Info text. -- Info text.
local pickupname=self.pickupzone and self.pickupzone:GetName() or "Unknown" local text=string.format("%s: Ncargo=%d/%d, Ncarrier=%d/%d", fsmstate:upper(), self.Ncargo, self.Ndelivered, #self.carriers, self.Ncarrier)
local deployname=self.deployzone and self.deployzone:GetName() or "Unknown"
local text=string.format("%s [%s --> %s]: Ncargo=%d/%d, Ncarrier=%d/%d", fsmstate:upper(), pickupname, deployname, self.Ncargo, self.Ndelivered, #self.carriers, self.Ncarrier)
-- Info about cargo and carrier. -- Info about cargo and carrier.
if self.verbose>=2 then if self.verbose>=2 then
for i,_tz in pairs(self.transportZones) do
local tz=_tz --#OPSTRANSPORT.TransportZone
text=text..string.format("\n[%d] %s --> %s", i, tz.PickupZone and tz.PickupZone:GetName() or "Unknown", tz.DeployZone and tz.DeployZone and tz.DeployZone:GetName() or "Unknown", tz.Ncarriers)
end
end
-- Info about cargo and carrier.
if self.verbose>=3 then
text=text..string.format("\nCargos:") text=text..string.format("\nCargos:")
for _,_cargo in pairs(self.cargos) do for _,_cargo in pairs(self.cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
@ -1222,6 +1272,62 @@ function OPSTRANSPORT:_CreateCargoGroupData(group)
return cargo return cargo
end end
--- Count how many cargo groups are inside a zone.
-- @param #OPSTRANSPORT self
-- @param Core.Zone#ZONE Zone The zone object.
-- @param #boolean Delivered If `true`, only delivered groups are returned. If `false` only undelivered groups are returned. If `nil`, all groups are returned.
-- @param Ops.OpsGroup#OPSGROUP Carrier (Optional) Only count cargo groups that fit into the given carrier group. Current cargo is not a factor.
-- @return #number Number of cargo groups.
function OPSTRANSPORT:_CountCargosInZone(Zone, Delivered, Carrier)
local cargos=self:GetCargoOpsGroups(Delivered, Carrier)
local N=0
for _,_cargo in pairs(cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP
if cargo:IsInZone(Zone) then
N=N+1
end
end
return N
end
--- Get a pickup zone for a carrier group. This will be a zone, where the most cargo groups are located that fit into the carrier.
-- @param #OPSTRANSPORT self
-- @param Ops.OpsGroup#OPSGROUP Carrier The carrier OPS group.
-- @return Core.Zone#ZONE Pickup zone or `#nil`.
function OPSTRANSPORT:_GetPickupZone(Carrier)
env.info(string.format("FF GetPickupZone"))
local pickup=nil
local distmin=nil
for i,_transportzone in pairs(self.transportZones) do
local tz=_transportzone --#OPSTRANSPORT.TransportZone
-- Count cargos in pickup zone.
local ncargo=self:_CountCargosInZone(tz.PickupZone, false, Carrier)
env.info(string.format("FF GetPickupZone i=%d, ncargo=%d", i, ncargo))
if ncargo>0 then
local vec2=Carrier:GetVec2()
local dist=tz.PickupZone:Get2DDistance(vec2)
if distmin==nil or dist<distmin then
distmin=dist
pickup=tz
end
end
end
return pickup
end
--- Get an OPSGROUP from a given OPSGROUP or GROUP object. If the object is a GROUUP, an OPSGROUP is created automatically. --- Get an OPSGROUP from a given OPSGROUP or GROUP object. If the object is a GROUUP, an OPSGROUP is created automatically.
-- @param #OPSTRANSPORT self -- @param #OPSTRANSPORT self
-- @param Core.Base#BASE Object The object, which can be a GROUP or OPSGROUP. -- @param Core.Base#BASE Object The object, which can be a GROUP or OPSGROUP.