OPSTRANSPORT v0.4

- Multiple transport zone combos (TZC)
- Other issues solved.
- Demo miz D-day landing is still not working correctly.
This commit is contained in:
Frank 2021-08-30 23:45:40 +02:00
parent 28ddfa5243
commit 0b1e25b073
6 changed files with 625 additions and 294 deletions

View File

@ -6329,6 +6329,10 @@ function WAREHOUSE:_OnEventBirth(EventData)
local request=self:GetRequestByID(rid)
if asset and request then
if asset.spawned and type(asset.spawned)=="boolean" and asset.spawned==true then
return
end
-- Debug message.
self:T(self.lid..string.format("Warehouse %s captured event birth of request ID=%d, asset ID=%d, unit %s spawned=%s", self.alias, request.uid, asset.uid, EventData.IniUnitName, tostring(asset.spawned)))

View File

@ -90,10 +90,7 @@ function ARMYGROUP:New(group)
og:I(og.lid..string.format("WARNING: OPS group already exists in data base!"))
return og
end
-- First set ARMYGROUP.
self.isArmygroup=true
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, OPSGROUP:New(group)) -- #ARMYGROUP
@ -595,6 +592,16 @@ end
-- @param #number Formation Formation of the group.
function ARMYGROUP:onbeforeUpdateRoute(From, Event, To, n, Speed, Formation)
if self:IsWaiting() then
self:E(self.lid.."Update route denied. Group is WAIRING!")
return false
elseif self:IsInUtero() then
self:E(self.lid.."Update route denied. Group is INUTERO!")
return false
elseif self:IsDead() then
self:E(self.lid.."Update route denied. Group is DEAD!")
return false
elseif self:IsStopped() then
self:E(self.lid.."Update route denied. Group is STOPPED!")
return false
end
return true

View File

@ -32,7 +32,7 @@
--- FLIGHTGROUP class.
-- @type FLIGHTGROUP
-- @field #string actype Type name of the aircraft.
-- @field #number rangemax Max range in km.
-- @field #number rangemax Max range in meters.
-- @field #number ceiling Max altitude the aircraft can fly at in meters.
-- @field #number tankertype The refueling system type (0=boom, 1=probe), if the group is a tanker.
-- @field #number refueltype The refueling system type (0=boom, 1=probe), if the group can refuel from a tanker.
@ -208,9 +208,6 @@ function FLIGHTGROUP:New(group)
return og
end
-- First set FLIGHTGROUP.
self.isFlightgroup=true
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, OPSGROUP:New(group)) -- #FLIGHTGROUP
@ -1766,14 +1763,12 @@ function FLIGHTGROUP:onafterCruise(From, Event, To)
---
if self:IsTransporting() then
if self.cargoTransport and self.cargoTransport.deployzone and self.cargoTransport.deployzone:IsInstanceOf("ZONE_AIRBASE") then
local airbase=self.cargoTransport.deployzone:GetAirbase()
self:LandAtAirbase(airbase)
if self.cargoTransport and self.cargoTZC and self.cargoTZC.DeployAirbase then
self:LandAtAirbase(self.cargoTZC.DeployAirbase)
end
elseif self:IsPickingup() then
if self.cargoTransport and self.cargoTransport.pickupzone and self.cargoTransport.pickupzone:IsInstanceOf("ZONE_AIRBASE") then
local airbase=self.cargoTransport.pickupzone:GetAirbase()
self:LandAtAirbase(airbase)
if self.cargoTransport and self.cargoTZC and self.cargoTZC.PickupAirbase then
self:LandAtAirbase(self.cargoTZC.PickupAirbase)
end
else
self:_CheckGroupDone(nil, 120)
@ -1983,6 +1978,9 @@ function FLIGHTGROUP:onbeforeUpdateRoute(From, Event, To, n)
-- Group is dead! No more updates.
self:E(self.lid.."Update route denied. Group is DEAD!")
allowed=false
elseif self:IsInUtero() then
self:E(self.lid.."Update route denied. Group is INUTERO!")
allowed=false
else
-- Not airborne yet. Try again in 5 sec.
self:T(self.lid.."Update route denied ==> checking back in 5 sec")
@ -2084,9 +2082,9 @@ function FLIGHTGROUP:onafterUpdateRoute(From, Event, To, n)
local waypointAction=COORDINATE.WaypointAction.TurningPoint
if self:IsLanded() or self:IsLandedAt() or self:IsAirborne()==false then
-- Had some issues with passing waypoint function of the next WP called too ealy when the type is TurningPoint. Setting it to TakeOff solved it!
--waypointType=COORDINATE.WaypointType.TakeOff
waypointType=COORDINATE.WaypointType.TakeOffGroundHot
waypointAction=COORDINATE.WaypointAction.FromGroundAreaHot
waypointType=COORDINATE.WaypointType.TakeOff
--waypointType=COORDINATE.WaypointType.TakeOffGroundHot
--waypointAction=COORDINATE.WaypointAction.FromGroundAreaHot
end
-- Set current waypoint or we get problem that the _PassingWaypoint function is triggered too early, i.e. right now and not when passing the next WP.
@ -2585,9 +2583,9 @@ function FLIGHTGROUP:onbeforeWait(From, Event, To, Duration, Altitude, Speed)
-- Check for a current transport assignment.
if self.cargoTransport and not self:IsLandedAt() then
self:I(self.lid..string.format("WARNING: Got current TRANSPORT assignment ==> WAIT event is suspended for 30 sec!"))
Tsuspend=-30
allowed=false
--self:I(self.lid..string.format("WARNING: Got current TRANSPORT assignment ==> WAIT event is suspended for 30 sec!"))
--Tsuspend=-30
--allowed=false
end
-- Call wait again.

View File

@ -114,9 +114,6 @@ function NAVYGROUP:New(group)
return og
end
-- First set NAVYGROUP.
self.isNavygroup=true
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, OPSGROUP:New(group)) -- #NAVYGROUP
@ -467,6 +464,9 @@ function NAVYGROUP:Status(From, Event, To)
-- Is group alive?
local alive=self:IsAlive()
--
local freepath=0
if alive then
---
@ -485,7 +485,7 @@ function NAVYGROUP:Status(From, Event, To)
self:_CheckTurning()
local disttoWP=math.min(self:GetDistanceToWaypoint(), UTILS.NMToMeters(10))
local freepath=disttoWP
freepath=disttoWP
-- Only check if not currently turning.
if not self:IsTurning() then
@ -713,6 +713,16 @@ end
-- @param #number Depth Depth in meters to the next waypoint.
function NAVYGROUP:onbeforeUpdateRoute(From, Event, To, n, Speed, Depth)
if self:IsWaiting() then
self:E(self.lid.."Update route denied. Group is WAIRING!")
return false
elseif self:IsInUtero() then
self:E(self.lid.."Update route denied. Group is INUTERO!")
return false
elseif self:IsDead() then
self:E(self.lid.."Update route denied. Group is DEAD!")
return false
elseif self:IsStopped() then
self:E(self.lid.."Update route denied. Group is STOPPED!")
return false
end
return true
@ -771,7 +781,7 @@ function NAVYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Depth)
table.insert(waypoints, 1, current)
if not self.passedfinalwp then
if self:IsEngaging() or not self.passedfinalwp then
-- Debug info.
self:T(self.lid..string.format("Updateing route: WP %d-->%d (%d/%d), Speed=%.1f knots, Depth=%d m", self.currentwp, n, #waypoints, #self.waypoints, UTILS.MpsToKnots(self.speedWp), wp.alt))

View File

@ -115,7 +115,7 @@
-- @field #table cargoqueue Table containing cargo groups to be transported.
-- @field #table cargoBay Table containing OPSGROUP loaded into this group.
-- @field Ops.OpsTransport#OPSTRANSPORT cargoTransport Current cargo transport assignment.
-- @field Ops.OpsTransport#OPSTRANSPORT.TransportZone transportZone Transport zones (pickup, deploy etc.).
-- @field Ops.OpsTransport#OPSTRANSPORT.TransportZoneCombo cargoTZC Transport zone combo (pickup, deploy etc.) currently used.
-- @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 #string carrierStatus Carrier status of this group acting as cargo carrier.
@ -512,6 +512,8 @@ function OPSGROUP:New(group)
end
end
self.group:IsAir()
-- Set the template.
self:_SetTemplate()
@ -519,7 +521,27 @@ function OPSGROUP:New(group)
self.dcsgroup=self:GetDCSGroup()
self.controller=self.dcsgroup:getController()
-- Category.
self.category=self.dcsgroup:getCategory()
if self.category==Group.Category.GROUND then
self.isArmygroup=true
elseif self.category==Group.Category.TRAIN then
self.isArmygroup=true
self.isTrain=true
elseif self.category==Group.Category.SHIP then
self.isNavygroup=true
-- TODO submarine
elseif self.category==Group.Category.AIRPLANE then
self.isFlightgroup=true
elseif self.category==Group.Category.HELICOPTER then
self.isFlightgroup=true
self.isHelo=true
else
end
local units=self.group:GetUnits()
if units then
local masterunit=units[1] --Wrapper.Unit#UNIT
@ -531,10 +553,8 @@ function OPSGROUP:New(group)
if self:IsFlightgroup() then
self.rangemax=masterunit:GetRange()
self.descriptors=masterunit:GetDesc()
self.rangemax=self.descriptors.range and self.descriptors.range*1000 or 500*1000
self.ceiling=self.descriptors.Hmax
self.tankertype=select(2, masterunit:IsTanker())
@ -1783,7 +1803,10 @@ end
-- @return #boolean If true, group is in this zone
function OPSGROUP:IsInZone(Zone)
local vec2=self:GetVec2()
local is=Zone:IsVec2InZone(vec2)
local is=false
if vec2 then
is=Zone:IsVec2InZone(vec2)
end
return is
end
@ -2750,17 +2773,33 @@ function OPSGROUP:PushTask(DCSTask)
return self
end
--- Returns true if the DCS controller currently has a task.
-- @param #OPSGROUP self
-- @param #number Delay Delay in seconds.
-- @return #boolean True or false if the controller has a task. Nil if no controller.
function OPSGROUP:HasTaskController(Delay)
local hastask=nil
if self.controller then
hastask=self.controller:hasTask()
end
self:I(self.lid..string.format("Controller hasTask=%s", tostring(hastask)))
return hastask
end
--- Clear DCS tasks.
-- @param #OPSGROUP self
-- @return #OPSGROUP self
function OPSGROUP:ClearTasks()
if self:IsAlive() then
local hastask=self:HasTaskController()
if self:IsAlive() and self.controller and self:HasTaskController() then
self:I(self.lid..string.format("CLEARING Tasks"))
self.group:ClearTasks()
self.controller:resetTask()
end
return self
end
--- Add a *scheduled* task.
-- @param #OPSGROUP self
-- @param #table task DCS task table structure.
@ -5262,7 +5301,11 @@ function OPSGROUP:_Respawn(Delay, Template, Reset)
self:T({Template=Template})
-- Spawn new group.
_DATABASE:Spawn(Template)
self.group=_DATABASE:Spawn(Template)
-- Set DCS group and controller.
self.dcsgroup=self:GetDCSGroup()
self.controller=self.dcsgroup:getController()
-- Set activation and controlled state.
self.isLateActivated=Template.lateActivation
@ -5373,6 +5416,7 @@ function OPSGROUP:onafterDead(From, Event, To)
-- No current cargo transport.
self.cargoTransport=nil
self.cargoTZC=nil
if self.Ndestroyed==#self.elements then
if self.cohort then
@ -5488,10 +5532,11 @@ function OPSGROUP:_CheckCargoTransport()
if self.verbose>=3 then
local text=""
for i,_transport in pairs(self.cargoqueue) do
local transport=_transport --#Ops.OpsTransport#OPSTRANSPORT
local pickupname=transport.pickupzone and transport.pickupzone:GetName() or "unknown"
local deployname=transport.deployzone and transport.deployzone:GetName() or "unknown"
local transport=_transport --#Ops.OpsTransport#OPSTRANSPORT
local pickupzone=transport:GetPickupZone()
local deployzone=transport:GetDeployZone()
local pickupname=pickupzone and pickupzone:GetName() or "unknown"
local deployname=deployzone and deployzone:GetName() or "unknown"
text=text..string.format("\n[%d] UID=%d Status=%s: %s --> %s", i, transport.uid, transport:GetState(), pickupname, deployname)
for j,_cargo in pairs(transport.cargos) do
local cargo=_cargo --#OPSGROUP.CargoGroup
@ -5520,38 +5565,18 @@ function OPSGROUP:_CheckCargoTransport()
-- Now handle the transport.
if self.cargoTransport then
-- Debug info.
if self.verbose>=2 then
local pickupname=self.cargoTransport.pickupzone and self.cargoTransport.pickupzone:GetName() or "unknown"
local deployname=self.cargoTransport.deployzone and self.cargoTransport.deployzone:GetName() or "unknown"
local text=string.format("Carrier [%s]: %s --> %s", self.carrierStatus, pickupname, deployname)
for _,_cargo in pairs(self.cargoTransport.cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
local name=cargo.opsgroup:GetName()
local gstatus=cargo.opsgroup:GetState()
local cstatus=cargo.opsgroup.cargoStatus
local weight=cargo.opsgroup:GetWeightTotal()
local carriergroup, carrierelement, reserved=cargo.opsgroup:_GetMyCarrier()
local carrierGroupname=carriergroup and carriergroup.groupname or "none"
local carrierElementname=carrierelement and carrierelement.name or "none"
text=text..string.format("\n- %s (%.1f kg) [%s]: %s, carrier=%s (%s), delivered=%s", name, weight, gstatus, cstatus, carrierElementname, carrierGroupname, tostring(cargo.delivered))
end
self:I(self.lid..text)
end
if self:IsNotCarrier() then
-- Debug info.
self:T(self.lid.."Not carrier ==> pickup?")
-- Get transport zones.
local transportZone=self.cargoTransport:_GetPickupZone(self)
-- Get transport zone combo (TZC).
self.cargoTZC=self.cargoTransport:_GetTransportZoneCombo(self)
if transportZone then
if self.cargoTZC then
-- Initiate the cargo transport process.
self:__Pickup(-1, transportZone)
self:__Pickup(-1)
else
self:T(self.lid.."Not carrier ==> pickup")
@ -5573,7 +5598,7 @@ function OPSGROUP:_CheckCargoTransport()
local boarding=false
local gotcargo=false
for _,_cargo in pairs(self.cargoTransport.cargos) do
for _,_cargo in pairs(self.cargoTZC.Cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
-- Check if anyone is still boarding.
@ -5589,7 +5614,7 @@ function OPSGROUP:_CheckCargoTransport()
end
-- Boarding finished ==> Transport cargo.
if gotcargo and self.cargoTransport:_CheckRequiredCargos() and not boarding then
if gotcargo and self.cargoTransport:_CheckRequiredCargos(self.cargoTZC) and not boarding then
self:T(self.lid.."Boarding finished ==> Loaded")
self:Loaded()
else
@ -5613,7 +5638,7 @@ function OPSGROUP:_CheckCargoTransport()
self:T(self.lid.."Unloading ==> Checking if all cargo was delivered")
local delivered=true
for _,_cargo in pairs(self.cargoTransport.cargos) do
for _,_cargo in pairs(self.cargoTZC.Cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
local carrierGroup=cargo.opsgroup:_GetMyCarrierGroup()
@ -5629,12 +5654,33 @@ function OPSGROUP:_CheckCargoTransport()
-- Unloading finished ==> pickup next batch or call it a day.
if delivered then
self:T(self.lid.."Unloading finished ==> UnloadingDone")
self:UnloadingDone()
self:__UnloadingDone(10)
else
self:Unloading()
end
end
-- Debug info. (At this point, we might not have a current cargo transport ==> hence the check)
if self.verbose>=2 and self.cargoTransport then
local pickupzone=self.cargoTransport:GetPickupZone(self.cargoTZC)
local deployzone=self.cargoTransport:GetDeployZone(self.cargoTZC)
local pickupname=pickupzone and pickupzone:GetName() or "unknown"
local deployname=deployzone and deployzone:GetName() or "unknown"
local text=string.format("Carrier [%s]: %s --> %s", self.carrierStatus, pickupname, deployname)
for _,_cargo in pairs(self.cargoTransport:GetCargos(self.cargoTZC)) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
local name=cargo.opsgroup:GetName()
local gstatus=cargo.opsgroup:GetState()
local cstatus=cargo.opsgroup.cargoStatus
local weight=cargo.opsgroup:GetWeightTotal()
local carriergroup, carrierelement, reserved=cargo.opsgroup:_GetMyCarrier()
local carrierGroupname=carriergroup and carriergroup.groupname or "none"
local carrierElementname=carrierelement and carrierelement.name or "none"
text=text..string.format("\n- %s (%.1f kg) [%s]: %s, carrier=%s (%s), delivered=%s", name, weight, gstatus, cstatus, carrierElementname, carrierGroupname, tostring(cargo.delivered))
end
self:I(self.lid..text)
end
end
@ -5851,28 +5897,33 @@ end
function OPSGROUP:_CheckGoPickup(CargoTransport)
local done=true
for _,_cargo in pairs(CargoTransport.cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if self:CanCargo(cargo.opsgroup) then
if cargo.delivered then
-- This one is delivered.
elseif cargo.opsgroup==nil or cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped() then
-- This one is dead.
elseif cargo.opsgroup:IsLoaded(CargoTransport:_GetCarrierNames()) then
-- This one is loaded into a(nother) carrier.
else
done=false --Someone is not done!
if CargoTransport then
for _,_cargo in pairs(CargoTransport.cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if self:CanCargo(cargo.opsgroup) then
if cargo.delivered then
-- This one is delivered.
elseif cargo.opsgroup==nil or cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped() then
-- This one is dead.
elseif cargo.opsgroup:IsLoaded(CargoTransport:_GetCarrierNames()) then
-- This one is loaded into a(nother) carrier.
else
done=false --Someone is not done!
end
end
end
-- Debug info.
self:T(self.lid..string.format("Cargotransport UID=%d Status=%s: delivered=%s", CargoTransport.uid, CargoTransport:GetState(), tostring(done)))
end
-- Debug info.
self:T(self.lid..string.format("Cargotransport UID=%d Status=%s: delivered=%s", CargoTransport.uid, CargoTransport:GetState(), tostring(done)))
return done
end
@ -6067,7 +6118,7 @@ function OPSGROUP:GetWeightCargo(UnitName, IncludeReserved)
end
-- Debug info.
self:T2(self.lid..string.format("Unit=%s (reserved=%s): weight=%d, gewicht=%d", tostring(UnitName), tostring(IncludeReserved), weight, gewicht))
self:T3(self.lid..string.format("Unit=%s (reserved=%s): weight=%d, gewicht=%d", tostring(UnitName), tostring(IncludeReserved), weight, gewicht))
-- Quick check.
if IncludeReserved==false and gewicht~=weight then
@ -6281,29 +6332,29 @@ end
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Ops.OpsTransport#OPSTRANSPORT.TransportZone TransportZone The transport zones data table.
function OPSGROUP:onafterPickup(From, Event, To, TransportZone)
function OPSGROUP:onafterPickup(From, Event, To)
-- Set carrier status.
self:_NewCarrierStatus(OPSGROUP.CarrierStatus.PICKUP)
self.transportZone=TransportZone
local TZC=self.cargoTZC
-- Pickup zone.
local Zone=TransportZone.PickupZone
local Zone=TZC.PickupZone
-- Check if already in the pickup zone.
local inzone=self:IsInZone(Zone)
local airbasePickup=nil --Wrapper.Airbase#AIRBASE
if Zone and Zone:IsInstanceOf("ZONE_AIRBASE") then
airbasePickup=Zone:GetAirbase()
end
-- Pickup at an airbase.
local airbasePickup=TZC.PickupAirbase --Wrapper.Airbase#AIRBASE
-- Check if group is already ready for loading.
local ready4loading=false
if self:IsArmygroup() or self:IsNavygroup() then
-- Army and Navy groups just need to be inside the zone.
ready4loading=inzone
else
-- Aircraft is already parking at the pickup airbase.
@ -6315,6 +6366,7 @@ function OPSGROUP:onafterPickup(From, Event, To, TransportZone)
end
end
-- Ready for loading?
if ready4loading then
-- We are already in the pickup zone ==> wait and initiate loading.
@ -6350,16 +6402,14 @@ function OPSGROUP:onafterPickup(From, Event, To, TransportZone)
-- Activate uncontrolled group.
if self:IsParking() and self:IsUncontrolled() then
self:StartUncontrolled(1)
self:StartUncontrolled()
end
else
-- Order group to land at an airbase.
self:LandAtAirbase(airbasePickup)
end
-- Order group to land at an airbase.
self:__LandAtAirbase(-0.5, airbasePickup)
elseif self.isHelo then
---
@ -6375,10 +6425,10 @@ function OPSGROUP:onafterPickup(From, Event, To, TransportZone)
local waypoint=FLIGHTGROUP.AddWaypoint(self, Coordinate, nil, self:GetWaypointCurrent().uid, self.altitudeCruise, false) ; waypoint.detour=1
else
self:E(self.lid.."ERROR: Carrier aircraft cannot land in Pickup zone! Specify a ZONE_AIRBASE as pickup zone")
self:E(self.lid.."ERROR: Transportcarrier aircraft cannot land in Pickup zone! Specify a ZONE_AIRBASE as pickup zone")
end
elseif self.isNavygroup then
elseif self:IsNavygroup() then
---
-- Navy Group
@ -6388,7 +6438,7 @@ function OPSGROUP:onafterPickup(From, Event, To, TransportZone)
local uid=cwp and cwp.uid or nil
-- Get a (random) pre-defined transport path.
local path=self.cargoTransport:_GetPathPickup()
local path=self.cargoTransport:_GetPathPickup(self.cargoTZC)
if path then
-- Loop over coordinates.
@ -6406,7 +6456,7 @@ function OPSGROUP:onafterPickup(From, Event, To, TransportZone)
self:__Cruise(-2)
elseif self.isArmygroup then
elseif self:IsArmygroup() then
---
-- Army Group
@ -6416,14 +6466,13 @@ function OPSGROUP:onafterPickup(From, Event, To, TransportZone)
local uid=cwp and cwp.uid or nil
-- Get a (random) pre-defined transport path.
local path=self.cargoTransport:_GetPathPickup()
local path=self.cargoTransport:_GetPathPickup(self.cargoTZC)
if path then
-- Loop over coordinates.
for i,coordinate in pairs(path) do
local waypoint=ARMYGROUP.AddWaypoint(self, coordinate, nil, uid) ; waypoint.temp=true
uid=waypoint.uid
--coordinate:MarkToAll(string.format("Path i=%d, UID=%d", i, uid))
end
end
@ -6455,8 +6504,11 @@ function OPSGROUP:onafterLoading(From, Event, To)
--TODO: sort cargos wrt weight.
-- Cargo group table.
local cargos=self.cargoTZC.Cargos
-- Loop over all cargos.
for _,_cargo in pairs(self.cargoTransport.cargos) do
for _,_cargo in pairs(cargos) do
local cargo=_cargo --#OPSGROUP.CargoGroup
-- Check that cargo weight is
@ -6467,8 +6519,7 @@ function OPSGROUP:onafterLoading(From, Event, To)
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.
--local inzone=self.cargoTransport.embarkzone:IsCoordinateInZone(cargo.opsgroup:GetCoordinate())
local inzone=cargo.opsgroup:IsInZone(self.transportZone.EmbarkZone)
local inzone=cargo.opsgroup:IsInZone(self.cargoTZC.EmbarkZone)
-- Cargo MUST be inside zone or it will not be loaded!
if inzone then
@ -6486,12 +6537,12 @@ function OPSGROUP:onafterLoading(From, Event, To)
else
-- Debug info.
self:T(self.lid..string.format("Cannot board carrier! Group %s is NOT (yet) in zone %s", cargo.opsgroup:GetName(), self.cargoTransport.embarkzone:GetName()))
self:T(self.lid..string.format("Cannot board carrier! Group %s is NOT (yet) in zone %s", cargo.opsgroup:GetName(), self.cargoTZC.EmbarkZone:GetName()))
end
else
-- Debug info.
self:T(self.lid..string.format("Cargo %s NOT in embark zone %s", cargo.opsgroup:GetName(), self.cargoTransport.embarkzone:GetName()))
self:T(self.lid..string.format("Cargo %s NOT in embark zone %s", cargo.opsgroup:GetName(), self.cargoTZC.EmbarkZone:GetName()))
end
end
@ -6653,15 +6704,13 @@ function OPSGROUP:onafterTransport(From, Event, To)
--TODO: This is all very similar to the onafterPickup() function. Could make it general.
-- Deploy zone.
local Zone=self.transportZone.DeployZone
local Zone=self.cargoTZC.DeployZone
-- Check if already in deploy zone.
local inzone=self:IsInZone(Zone) --Zone:IsCoordinateInZone(self:GetCoordinate())
local airbaseDeploy=nil --Wrapper.Airbase#AIRBASE
if Zone and Zone:IsInstanceOf("ZONE_AIRBASE") then
airbaseDeploy=Zone:GetAirbase()
end
-- Deploy airbase (if any).
local airbaseDeploy=self.cargoTZC.DeployAirbase --Wrapper.Airbase#AIRBASE
-- Check if group is already ready for loading.
local ready2deploy=false
@ -6679,7 +6728,7 @@ function OPSGROUP:onafterTransport(From, Event, To)
if inzone then
-- We are already in the pickup zone ==> wait and initiate unloading.
-- We are already in the deploy zone ==> wait and initiate unloading.
if (self:IsArmygroup() or self:IsNavygroup()) and not self:IsHolding() then
self:FullStop()
end
@ -6693,6 +6742,7 @@ function OPSGROUP:onafterTransport(From, Event, To)
local Coordinate=nil --Core.Point#COORDINATE
if self.cargoTransport.carrierGroup and self.cargoTransport.carrierGroup:IsLoading() then
--TODO: What the heck is self.cargoTransport.carrierGroup and where is this set?!
-- Coordinate of the new carrier.
Coordinate=self.cargoTransport.carrierGroup:GetCoordinate()
else
@ -6701,14 +6751,14 @@ function OPSGROUP:onafterTransport(From, Event, To)
end
-- Add waypoint.
if self.isFlightgroup then
if self:IsFlightgroup() then
if airbaseDeploy then
---
-- Deploy at airbase
---
if airbaseDeploy then
local airbaseCurrent=self.currbase
if airbaseCurrent then
@ -6718,10 +6768,10 @@ function OPSGROUP:onafterTransport(From, Event, To)
self:StartUncontrolled()
end
else
-- Order group to land at an airbase.
self:LandAtAirbase(airbaseDeploy)
end
-- Order group to land at an airbase.
self:__LandAtAirbase(-0.1, airbaseDeploy)
elseif self.isHelo then
@ -6735,28 +6785,26 @@ function OPSGROUP:onafterTransport(From, Event, To)
-- Cancel landedAt task. This should trigger Cruise once airborne.
if self:IsFlightgroup() and self:IsLandedAt() then
local Task=self:GetTaskCurrent()
--if Task and Task.description=="Task_Landed_At" then
self:__TaskCancel(5, Task)
--end
self:__TaskCancel(5, Task)
end
else
self:E(self.lid.."ERROR: Carrier aircraft cannot land in Deploy zone! Specify a ZONE_AIRBASE as deploy zone")
end
elseif self.isArmygroup then
elseif self:IsArmygroup() then
local cwp=self:GetWaypointCurrent()
local uid=cwp and cwp.uid or nil
local path=self.cargoTransport:_GetPathTransport()
-- Get transport path.
local path=self.cargoTransport:_GetPathTransport(self.cargoTZC)
if path then
-- Loop over coordinates.
for i,coordinate in pairs(path) do
local waypoint=ARMYGROUP.AddWaypoint(self, coordinate, nil, uid) ; waypoint.temp=true
uid=waypoint.uid
--coordinate:MarkToAll(string.format("Path i=%d, UID=%d", i, uid))
end
end
@ -6766,20 +6814,19 @@ function OPSGROUP:onafterTransport(From, Event, To)
-- Give cruise command.
self:Cruise()
elseif self.isNavygroup then
elseif self:IsNavygroup() then
local cwp=self:GetWaypointCurrent()
local uid=cwp and cwp.uid or nil
-- Get a (random) pre-defined transport path.
local path=self.cargoTransport:_GetPathTransport()
local path=self.cargoTransport:_GetPathTransport(self.cargoTZC)
if path then
-- Loop over coordinates.
for i,coordinate in pairs(path) do
local waypoint=NAVYGROUP.AddWaypoint(self, coordinate, nil, uid) ; waypoint.temp=true
uid=waypoint.uid
--coordinate:MarkToAll(string.format("Path i=%d, UID=%d", i, uid))
end
end
@ -6806,9 +6853,9 @@ function OPSGROUP:onafterUnloading(From, Event, To)
self:_NewCarrierStatus(OPSGROUP.CarrierStatus.UNLOADING)
-- Deploy zone.
local zone=self.cargoTransport.disembarkzone or self.cargoTransport.deployzone --Core.Zone#ZONE
local zone=self.cargoTZC.DisembarkZone or self.cargoTZC.DeployZone --Core.Zone#ZONE
for _,_cargo in pairs(self.cargoTransport.cargos) do
for _,_cargo in pairs(self.cargoTZC.Cargos) do
local cargo=_cargo --#OPSGROUP.CargoGroup
-- Check that cargo is loaded into this group.
@ -6821,11 +6868,11 @@ function OPSGROUP:onafterUnloading(From, Event, To)
local carrierGroup=nil
if self.cargoTransport.disembarkCarriers and #self.cargoTransport.disembarkCarriers>0 then
if self.cargoTZC.DisembarkCarriers and #self.cargoTZC.DisembarkCarriers>0 then
needscarrier=true
carrier, carrierGroup=self.cargoTransport:FindTransferCarrierForCargo(cargo.opsgroup, zone)
carrier, carrierGroup=self.cargoTransport:FindTransferCarrierForCargo(cargo.opsgroup, zone, self.cargoTZC)
--TODO: max unloading time if transfer carrier does not arrive in the zone.
@ -6863,7 +6910,7 @@ function OPSGROUP:onafterUnloading(From, Event, To)
-- Delivered to deploy zone
---
if self.cargoTransport.disembarkInUtero then
if self.cargoTransport:GetDisembarkInUtero(self.cargoTZC) then
-- Unload but keep "in utero" (no coordinate provided).
self:Unload(cargo.opsgroup)
@ -6872,10 +6919,10 @@ function OPSGROUP:onafterUnloading(From, Event, To)
local Coordinate=nil
if self.cargoTransport.disembarkzone then
if self.cargoTransport:GetDisembarkZone(self.cargoTZC) then
-- Random coordinate in disembark zone.
Coordinate=self.cargoTransport.disembarkzone:GetRandomCoordinate()
Coordinate=self.cargoTransport:GetDisembarkZone(self.cargoTZC):GetRandomCoordinate()
else
@ -6891,7 +6938,7 @@ function OPSGROUP:onafterUnloading(From, Event, To)
local Heading=math.random(0,359)
-- Unload to Coordinate.
self:Unload(cargo.opsgroup, Coordinate, self.cargoTransport.disembarkActivation, Heading)
self:Unload(cargo.opsgroup, Coordinate, self.cargoTransport:GetDisembarkActivation(self.cargoTZC), Heading)
end
@ -7050,7 +7097,7 @@ function OPSGROUP:onafterUnloadingDone(From, Event, To)
-- Cancel landedAt task.
if self:IsFlightgroup() and self:IsLandedAt() then
local Task=self:GetTaskCurrent()
self:TaskCancel(Task)
self:__TaskCancel(5, Task)
end
-- Check everything was delivered (or is dead).
@ -7058,16 +7105,22 @@ function OPSGROUP:onafterUnloadingDone(From, Event, To)
if not delivered then
local transportZone=self.cargoTransport:_GetPathPickup()
self.cargoTZC=self.cargoTransport:_GetTransportZoneCombo(self)
if transportZone then
if self.cargoTZC then
-- Pickup the next batch.
self:I(self.lid.."Unloaded: Still cargo left ==> Pickup")
self:Pickup(transportZone)
self:Pickup()
else
env.info("FF error not implemented case!")
-- Debug info.
self:I(self.lid..string.format("WARNING: Not all cargo was delivered but could not get a transport zone combo ==> setting carrier state to NOT CARRIER"))
-- This is not a carrier anymore.
self:_NewCarrierStatus(OPSGROUP.CarrierStatus.NOTCARRIER)
end
else
@ -7128,6 +7181,7 @@ function OPSGROUP:onafterDelivered(From, Event, To, CargoTransport)
-- No current transport any more.
self.cargoTransport=nil
self.cargoTZC=nil
end
-- Remove cargo transport from cargo queue.
@ -7531,8 +7585,8 @@ end
-- @param #OPSGROUP self
function OPSGROUP:_CheckStuck()
-- Holding means we are not stuck.
if self:IsHolding() or self:Is("Rearming") then
-- Cases we are not stuck.
if self:IsHolding() or self:Is("Rearming") or self:IsWaiting() then
return
end
@ -7569,6 +7623,9 @@ function OPSGROUP:_CheckStuck()
-- Debug warning.
self:E(self.lid..string.format("WARNING: Group came to an unexpected standstill. Speed=%.1f<%.1f m/s expected for %d sec", speed, ExpectedSpeed, holdtime))
-- Give cruise command again.
self:__Cruise(1)
--TODO: Stuck event!
@ -7916,13 +7973,16 @@ function OPSGROUP:_InitWaypoints(WpIndexMin, WpIndexMax)
-- Get home and destination airbases from waypoints.
self.homebase=self.homebase or self:GetHomebaseFromWaypoints()
self.destbase=self.destbase or self:GetDestinationFromWaypoints()
local destbase=self:GetDestinationFromWaypoints()
self.destbase=self.destbase or destbase
self.currbase=self:GetHomebaseFromWaypoints()
-- Remove the landing waypoint. We use RTB for that. It makes adding new waypoints easier as we do not have to check if the last waypoint is the landing waypoint.
if self.destbase and #self.waypoints>1 then
if destbase and #self.waypoints>1 then
table.remove(self.waypoints, #self.waypoints)
else
end
if self.destbase==nil then
self.destbase=self.homebase
end
@ -8051,7 +8111,7 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid)
-- Get next waypoint. Tricky part is that if
local wpnext=opsgroup:GetWaypointNext()
if wpnext and (opsgroup.currentwp<#opsgroup.waypoints or opsgroup.adinfinitum or wpistemp) then
if wpnext then --and (opsgroup.currentwp<#opsgroup.waypoints or opsgroup.adinfinitum or wpistemp)
-- Debug info.
opsgroup:T(opsgroup.lid..string.format("Next waypoint UID=%d index=%d", wpnext.uid, opsgroup:GetWaypointIndex(wpnext.uid)))
@ -8074,6 +8134,12 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid)
opsgroup:_PassedFinalWaypoint(true, "_PassingWaypoint No next Waypoint found")
end
-- Check if final waypoint was reached.
if opsgroup.currentwp==#opsgroup.waypoints and not opsgroup.adinfinitum then
-- Set passed final waypoint.
opsgroup:_PassedFinalWaypoint(true, "_PassingWaypoint currentwp==#waypoints and NOT adinfinitum")
end
-- Trigger PassingWaypoint event.
if waypoint.temp then
@ -8122,9 +8188,13 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid)
if opsgroup:IsFlightgroup() then
-- Land at current pos and wait for 60 min max.
env.info("FF LandAt for Pickup")
--opsgroup:LandAt(opsgroup:GetCoordinate(), 60*60)
opsgroup:LandAt(opsgroup.cargoTransport.pickupzone:GetCoordinate(), 60*60)
local coordinate=nil
if opsgroup.cargoTZC then
coordinate=opsgroup.cargoTZC.PickupZone:GetCoordinate()
else
coordinate=opsgroup:GetCoordinate()
end
opsgroup:LandAt(coordinate, 60*60)
else
@ -8136,11 +8206,16 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid)
elseif opsgroup:IsTransporting() then
if opsgroup.isFlightgroup then
if opsgroup:IsFlightgroup() then
-- Land at current pos and wait for 60 min max.
env.info("FF LandAt for Transporting")
opsgroup:LandAt(opsgroup:GetCoordinate(), 60*60)
local coordinate=nil
if opsgroup.cargoTZC then
coordinate=opsgroup.cargoTZC.DeployZone:GetCoordinate()
else
coordinate=opsgroup:GetCoordinate()
end
opsgroup:LandAt(coordinate, 60*60)
else
-- Stop and unload.

View File

@ -29,8 +29,7 @@
-- @field #string lid Log ID.
-- @field #number uid Unique ID of the transport.
-- @field #number verbose Verbosity level.
-- @field #table cargos Cargos. Each element is a @{Ops.OpsGroup#OPSGROUP.CargoGroup}.
-- @field #table carriers Carriers assigned for this transport.
--
-- @field #number prio Priority of this transport. Should be a number between 0 (high prio) and 100 (low prio).
-- @field #boolean urgent If true, transport is urgent.
-- @field #number importance Importance of this transport. Smaller=higher.
@ -38,22 +37,21 @@
-- @field #number Tstop Stop time in *abs.* seconds. Default `#nil` (never stops).
-- @field #number duration Duration (`Tstop-Tstart`) of the transport in seconds.
-- @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 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 disembarkzone (Optional) Zone where the cargo is disembarked. Default is the deploy zone.
-- @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 #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 requiredCargos Table of cargo groups that must be loaded before the first transport is started.
--
-- @field #table cargos Cargos. Each element is a @{Ops.OpsGroup#OPSGROUP.CargoGroup}.
-- @field #table carriers Carriers assigned for this transport.
--
-- @field #table tzCombos Table of transport zone combos. Each element of the table is of type `#OPSTRANSPORT.TransportZoneCombo`.
-- @field #number tzcCounter Running number of added transport zone combos.
-- @field #OPSTRANSPORT.TransportZoneCombo tzcDefault Default transport zone combo.
--
-- @field #number Ncargo Total number of cargo groups.
-- @field #number Ncarrier Total number of assigned carriers.
-- @field #number Ndelivered Total number of cargo groups delivered.
-- @field #table pathsTransport Transport paths of `#OPSGROUP.Path`.
-- @field #table pathsPickup Pickup paths of `#OPSGROUP.Path`.
--
-- @field Ops.Auftrag#AUFTRAG mission The mission attached to this transport.
-- @field #table assets Warehouse assets assigned for this transport.
--
-- @extends Core.Fsm#FSM
--- *Victory is the beautiful, bright-colored flower. Transport is the stem without which it could never have blossomed.* -- Winston Churchill
@ -113,15 +111,13 @@
-- @field #OPSTRANSPORT
OPSTRANSPORT = {
ClassName = "OPSTRANSPORT",
verbose = 0,
cargos = {},
carriers = {},
verbose = 0,
cargos = {},
carriers = {},
carrierTransportStatus = {},
transportZones = {},
tzCombos = {},
tzcCounter = 0,
conditionStart = {},
pathsTransport = {},
pathsPickup = {},
requiredCargos = {},
assets = {},
}
@ -143,13 +139,23 @@ OPSTRANSPORT.Status={
}
--- Pickup and deploy set.
-- @type OPSTRANSPORT.TransportZone
-- @type OPSTRANSPORT.TransportZoneCombo
-- @field #number uid Unique ID of the TZ combo.
-- @field #number Ncarriers Number of carrier groups using this transport zone.
-- @field #number Ncargo Number of cargos assigned. This is a running number and *not* decreased if cargo is delivered or dead.
-- @field #table Cargos Cargo groups of the TZ combo. Each element is of type `Ops.OpsGroup#OPSGROUP.CargoGroup`.
-- @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.
-- @field Core.Zone#ZONE DisembarkZone Zone where the troops are disembared to.
-- @field Wrapper.Airbase#AIRBASE PickupAirbase Airbase for pickup.
-- @field Wrapper.Airbase#AIRBASE DeployAirbase Airbase for deploy.
-- @field #table PickupPaths Paths for pickup.
-- @field #table TransportPaths Path for Transport. Each elment of the table is of type `#OPSTRANSPORT.Path`.
-- @field #table RequiredCargos Required cargos.
-- @field #table DisembarkCarriers Carriers where the cargo is directly disembarked to.
-- @field #boolean disembarkActivation If true, troops are spawned in late activated state when disembarked from carrier.
-- @field #boolean disembarkInUtero If true, troops are disembarked "in utero".
--- Path used for pickup or transport.
-- @type OPSTRANSPORT.Path
@ -167,7 +173,7 @@ _OPSTRANSPORTID=0
--- Army Group version.
-- @field #string version
OPSTRANSPORT.version="0.3.0"
OPSTRANSPORT.version="0.4.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@ -184,11 +190,11 @@ OPSTRANSPORT.version="0.3.0"
--- Create a new OPSTRANSPORT class object. Essential input are the troops that should be transported and the zones where the troops are picked up and deployed.
-- @param #OPSTRANSPORT self
-- @param Core.Set#SET_GROUP GroupSet Set of groups to be transported. Can also be a single @{Wrapper.Group#GROUP} or @{Ops.OpsGroup#OPSGROUP} object.
-- @param Core.Zone#ZONE Pickupzone Pickup zone. This is the zone, where the carrier is going to pickup the cargo. **Important**: only cargo is considered, if it is in this zone when the carrier starts loading!
-- @param Core.Zone#ZONE Deployzone Deploy zone. This is the zone, where the carrier is going to drop off the cargo.
-- @param Core.Set#SET_GROUP CargoGroups Groups to be transported as cargo. Can also be a single @{Wrapper.Group#GROUP} or @{Ops.OpsGroup#OPSGROUP} object.
-- @param Core.Zone#ZONE PickupZone Pickup zone. This is the zone, where the carrier is going to pickup the cargo. **Important**: only cargo is considered, if it is in this zone when the carrier starts loading!
-- @param Core.Zone#ZONE DeployZone Deploy zone. This is the zone, where the carrier is going to drop off the cargo.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:New(GroupSet, Pickupzone, Deployzone)
function OPSTRANSPORT:New(CargoGroups, PickupZone, DeployZone)
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, FSM:New()) -- #OPSTRANSPORT
@ -201,26 +207,21 @@ function OPSTRANSPORT:New(GroupSet, Pickupzone, Deployzone)
-- UID of this transport.
self.uid=_OPSTRANSPORTID
-- Defaults.
self:SetPickupZone(Pickupzone)
self:SetDeployZone(Deployzone)
self:SetEmbarkZone() -- Default is pickup zone.
self.cargos={}
self.carriers={}
self.Ncargo=0
self.Ncarrier=0
self.Ndelivered=0
self:SetPriority()
self:SetTime()
-- Add cargo groups (could also be added later).
if GroupSet then
self:AddCargoGroups(GroupSet)
end
-- Set default TZC.
self.tzcDefault=self:AddTransportZoneCombo(PickupZone, DeployZone, CargoGroups)
-- FMS start state is PLANNED.
self:SetStartState(OPSTRANSPORT.Status.PLANNED)
@ -255,11 +256,54 @@ end
-- User Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Add pickup and deploy zone combination.
-- @param #OPSTRANSPORT self
-- @param Core.Zone#ZONE PickupZone Zone where the troops are picked up.
-- @param Core.Zone#ZONE DeployZone Zone where the troops are picked up.
-- @param Core.Set#SET_GROUP CargoGroups Groups to be transported as cargo. Can also be a single @{Wrapper.Group#GROUP} or @{Ops.OpsGroup#OPSGROUP} object.
-- @return #OPSTRANSPORT.TransportZoneCombo Transport zone table.
function OPSTRANSPORT:AddTransportZoneCombo(PickupZone, DeployZone, CargoGroups)
-- Increase counter.
self.tzcCounter=self.tzcCounter+1
local tzcombo={} --#OPSTRANSPORT.TransportZoneCombo
-- Init.
tzcombo.uid=self.tzcCounter
tzcombo.Ncarriers=0
tzcombo.Ncargo=0
tzcombo.Cargos={}
tzcombo.RequiredCargos={}
tzcombo.DisembarkCarriers={}
tzcombo.PickupPaths={}
tzcombo.TransportPaths={}
-- Set zones.
self:SetPickupZone(PickupZone, tzcombo)
self:SetDeployZone(DeployZone, tzcombo)
self:SetEmbarkZone(nil, tzcombo)
-- Add cargo groups (could also be added later).
if CargoGroups then
self:AddCargoGroups(CargoGroups, tzcombo)
end
-- Add to table.
table.insert(self.tzCombos, tzcombo)
return tzcombo
end
--- Add cargo groups to be transported.
-- @param #OPSTRANSPORT self
-- @param Core.Set#SET_GROUP GroupSet Set of groups to be transported. Can also be passed as a single GROUP or OPSGROUP object.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:AddCargoGroups(GroupSet)
function OPSTRANSPORT:AddCargoGroups(GroupSet, TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
-- Check type of GroupSet provided.
if GroupSet:IsInstanceOf("GROUP") or GroupSet:IsInstanceOf("OPSGROUP") then
@ -268,8 +312,13 @@ function OPSTRANSPORT:AddCargoGroups(GroupSet)
local cargo=self:_CreateCargoGroupData(GroupSet)
if cargo then
-- Add to main table.
table.insert(self.cargos, cargo)
self.Ncargo=self.Ncargo+1
-- Add to TZC table.
table.insert(TransportZoneCombo.Cargos, cargo)
TransportZoneCombo.Ncargo=TransportZoneCombo.Ncargo+1
end
else
@ -281,8 +330,13 @@ function OPSTRANSPORT:AddCargoGroups(GroupSet)
local cargo=self:_CreateCargoGroupData(group)
if cargo then
-- Add to main table.
table.insert(self.cargos, cargo)
self.Ncargo=self.Ncargo+1
-- Add to TZC table.
table.insert(TransportZoneCombo.Cargos, cargo)
TransportZoneCombo.Ncargo=TransportZoneCombo.Ncargo+1
end
end
@ -306,97 +360,174 @@ function OPSTRANSPORT:AddCargoGroups(GroupSet)
return self
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.
-- @param #OPSTRANSPORT self
-- @param Core.Zone#ZONE PickupZone Zone where the troops are picked up.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:SetPickupZone(PickupZone)
self.pickupzone=PickupZone
function OPSTRANSPORT:SetPickupZone(PickupZone, TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
TransportZoneCombo.PickupZone=PickupZone
if PickupZone and PickupZone:IsInstanceOf("ZONE_AIRBASE") then
TransportZoneCombo.PickupAirbase=PickupZone._.ZoneAirbase
end
return self
end
--- Get pickup zone.
-- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return Core.Zone#ZONE Zone where the troops are picked up.
function OPSTRANSPORT:GetPickupZone(TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
return TransportZoneCombo.PickupZone
end
--- Set deploy zone.
-- @param #OPSTRANSPORT self
-- @param Core.Zone#ZONE DeployZone Zone where the troops are deployed.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:SetDeployZone(DeployZone)
self.deployzone=DeployZone
function OPSTRANSPORT:SetDeployZone(DeployZone, TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
-- Set deploy zone.
TransportZoneCombo.DeployZone=DeployZone
-- Check if this is an airbase.
if DeployZone and DeployZone:IsInstanceOf("ZONE_AIRBASE") then
TransportZoneCombo.DeployAirbase=DeployZone._.ZoneAirbase
end
return self
end
--- Get deploy zone.
-- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return Core.Zone#ZONE Zone where the troops are deployed.
function OPSTRANSPORT:GetDeployZone(TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
return TransportZoneCombo.DeployZone
end
--- Set embark zone.
-- @param #OPSTRANSPORT self
-- @param Core.Zone#ZONE EmbarkZone Zone where the troops are embarked.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:SetEmbarkZone(EmbarkZone)
self.embarkzone=EmbarkZone or self.pickupzone
function OPSTRANSPORT:SetEmbarkZone(EmbarkZone, TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
TransportZoneCombo.EmbarkZone=EmbarkZone or TransportZoneCombo.PickupZone
return self
end
--- Get embark zone.
-- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return Core.Zone#ZONE Zone where the troops are embarked from.
function OPSTRANSPORT:GetEmbarkZone(TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
return TransportZoneCombo.EmbarkZone
end
--- Set disembark zone.
-- @param #OPSTRANSPORT self
-- @param Core.Zone#ZONE DisembarkZone Zone where the troops are disembarked.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:SetDisembarkZone(DisembarkZone)
self.disembarkzone=DisembarkZone
function OPSTRANSPORT:SetDisembarkZone(DisembarkZone, TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
TransportZoneCombo.DisembarkZone=DisembarkZone
return self
end
--- Get disembark zone.
-- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return Core.Zone#ZONE Zone where the troops are disembarked to.
function OPSTRANSPORT:GetDisembarkZone(TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
return TransportZoneCombo.DisembarkZone
end
--- Set activation status of group when disembarked from transport carrier.
-- @param #OPSTRANSPORT self
-- @param #boolean Active If `true` or `nil`, group is activated when disembarked. If `false`, group is late activated and needs to be activated manually.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:SetDisembarkActivation(Active)
function OPSTRANSPORT:SetDisembarkActivation(Active, TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
if Active==true or Active==nil then
self.disembarkActivation=true
TransportZoneCombo.disembarkActivation=true
else
self.disembarkActivation=false
end
TransportZoneCombo.disembarkActivation=false
end
return self
end
--- Get disembark activation.
-- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #boolean If `true`, groups are spawned in late activated state.
function OPSTRANSPORT:GetDisembarkActivation(TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
return TransportZoneCombo.disembarkActivation
end
--- Set transfer carrier(s). These are carrier groups, where the cargo is directly loaded into when disembarked.
-- @param #OPSTRANSPORT self
-- @param Core.Set#SET_GROUP Carriers Carrier set. Can also be passed as a #GROUP, #OPSGROUP or #SET_OPSGROUP object.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:SetDisembarkCarriers(Carriers)
function OPSTRANSPORT:SetDisembarkCarriers(Carriers, TransportZoneCombo)
-- Debug info.
self:T(self.lid.."Setting transfer carriers!")
-- Create table.
self.disembarkCarriers=self.disembarkCarriers or {}
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
if Carriers:IsInstanceOf("GROUP") or Carriers:IsInstanceOf("OPSGROUP") then
local carrier=self:_GetOpsGroupFromObject(Carriers)
if carrier then
table.insert(self.disembarkCarriers, carrier)
table.insert(TransportZoneCombo.DisembarkCarriers, carrier)
end
elseif Carriers:IsInstanceOf("SET_GROUP") or Carriers:IsInstanceOf("SET_OPSGROUP") then
@ -404,7 +535,7 @@ function OPSTRANSPORT:SetDisembarkCarriers(Carriers)
for _,object in pairs(Carriers:GetSet()) do
local carrier=self:_GetOpsGroupFromObject(object)
if carrier then
table.insert(self.disembarkCarriers, carrier)
table.insert(TransportZoneCombo.DisembarkCarriers, carrier)
end
end
@ -415,38 +546,72 @@ function OPSTRANSPORT:SetDisembarkCarriers(Carriers)
return self
end
--- Get transfer carrier(s). These are carrier groups, where the cargo is directly loaded into when disembarked.
-- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #table Table of carriers.
function OPSTRANSPORT:GetDisembarkCarriers(TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
return TransportZoneCombo.DisembarkCarriers
end
--- Set if group remains *in utero* after disembarkment from carrier. Can be used to directly load the group into another carrier. Similar to disembark in late activated state.
-- @param #OPSTRANSPORT self
-- @param #boolean InUtero If `true` or `nil`, group remains *in utero* after disembarkment.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:SetDisembarkInUtero(InUtero)
function OPSTRANSPORT:SetDisembarkInUtero(InUtero, TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
if InUtero==true or InUtero==nil then
self.disembarkInUtero=true
TransportZoneCombo.disembarkInUtero=true
else
self.disembarkInUtero=false
end
TransportZoneCombo.disembarkInUtero=false
end
return self
end
--- Get disembark in utero.
-- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #boolean If `true`, groups stay in utero after disembarkment.
function OPSTRANSPORT:GetDisembarkInUtero(TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
return TransportZoneCombo.disembarkInUtero
end
--- Set required cargo. This is a list of cargo groups that need to be loaded before the **first** transport will start.
-- @param #OPSTRANSPORT self
-- @param Core.Set#SET_GROUP Cargos Required cargo set. Can also be passed as a #GROUP, #OPSGROUP or #SET_OPSGROUP object.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:SetRequiredCargos(Cargos)
function OPSTRANSPORT:SetRequiredCargos(Cargos, TransportZoneCombo)
-- Debug info.
self:T(self.lid.."Setting required cargos!")
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
-- Create table.
self.requiredCargos=self.requiredCargos or {}
TransportZoneCombo.RequiredCargos=TransportZoneCombo.RequiredCargos or {}
if Cargos:IsInstanceOf("GROUP") or Cargos:IsInstanceOf("OPSGROUP") then
local cargo=self:_GetOpsGroupFromObject(Cargos)
if cargo then
table.insert(self.requiredCargos, cargo)
table.insert(TransportZoneCombo.RequiredCargos, cargo)
end
elseif Cargos:IsInstanceOf("SET_GROUP") or Cargos:IsInstanceOf("SET_OPSGROUP") then
@ -454,7 +619,7 @@ function OPSTRANSPORT:SetRequiredCargos(Cargos)
for _,object in pairs(Cargos:GetSet()) do
local cargo=self:_GetOpsGroupFromObject(object)
if cargo then
table.insert(self.requiredCargos, cargo)
table.insert(TransportZoneCombo.RequiredCargos, cargo)
end
end
@ -465,6 +630,17 @@ function OPSTRANSPORT:SetRequiredCargos(Cargos)
return self
end
--- Get required cargos. This is a list of cargo groups that need to be loaded before the **first** transport will start.
-- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #table Table of required cargo ops groups.
function OPSTRANSPORT:GetRequiredCargos(TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
return TransportZoneCombo.RequiredCargos
end
--- Add a carrier assigned for this transport.
@ -538,11 +714,14 @@ end
-- @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 Ops.OpsGroup#OPSGROUP Carrier (Optional) Only count cargo groups that fit into the given carrier group. Current cargo is not a factor.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #table Cargo Ops groups. Can be and empty table `{}`.
function OPSTRANSPORT:GetCargoOpsGroups(Delivered, Carrier)
function OPSTRANSPORT:GetCargoOpsGroups(Delivered, Carrier, TransportZoneCombo)
local cargos=self:GetCargos(TransportZoneCombo)
local opsgroups={}
for _,_cargo in pairs(self.cargos) do
for _,_cargo in pairs(cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if Delivered==nil or cargo.delivered==Delivered then
if cargo.opsgroup and not (cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped()) then
@ -556,13 +735,26 @@ function OPSTRANSPORT:GetCargoOpsGroups(Delivered, Carrier)
return opsgroups
end
--- Get carrier @{Ops.OpsGroup#OPSGROUP}s.
--- Get carriers.
-- @param #OPSTRANSPORT self
-- @return #table Carrier Ops groups.
function OPSTRANSPORT:GetCarrierOpsGroups()
function OPSTRANSPORT:GetCarriers()
return self.carriers
end
--- Get cargos.
-- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #table Cargos.
function OPSTRANSPORT:GetCargos(TransportZoneCombo)
if TransportZoneCombo then
return TransportZoneCombo.Cargos
else
return self.cargos
end
end
--- Set transport start and stop time.
-- @param #OPSTRANSPORT self
@ -652,8 +844,12 @@ end
-- @param #boolean Reversed If `true`, add waypoints of group in reversed order.
-- @param #number Radius Randomization radius in meters. Default 0 m.
-- @param #number Altitude Altitude in feet AGL. Only for aircraft.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport Zone combo.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:AddPathTransport(PathGroup, Reversed, Radius, Altitude)
function OPSTRANSPORT:AddPathTransport(PathGroup, Reversed, Radius, Altitude, TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
local path={} --#OPSTRANSPORT.Path
path.coords={}
@ -679,20 +875,26 @@ function OPSTRANSPORT:AddPathTransport(PathGroup, Reversed, Radius, Altitude)
-- Add path.
table.insert(self.pathsTransport, path)
table.insert(TransportZoneCombo.TransportPaths, path)
return self
end
--- Get a path for transportation.
-- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport Zone combo.
-- @return #table The path of COORDINATEs.
function OPSTRANSPORT:_GetPathTransport()
function OPSTRANSPORT:_GetPathTransport(TransportZoneCombo)
if self.pathsTransport and #self.pathsTransport>0 then
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
local pathsTransport=TransportZoneCombo.TransportPaths
if pathsTransport and #pathsTransport>0 then
-- Get a random path for transport.
local path=self.pathsTransport[math.random(#self.pathsTransport)] --#OPSTRANSPORT.Path
local path=pathsTransport[math.random(#pathsTransport)] --#OPSTRANSPORT.Path
local coordinates={}
@ -718,8 +920,12 @@ end
-- @param #boolean Reversed If `true`, add waypoints of group in reversed order.
-- @param #number Radius Randomization radius in meters. Default 0 m.
-- @param #number Altitude Altitude in feet AGL. Only for aircraft.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport Zone combo.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:AddPathPickup(PathGroup, Reversed, Radius, Altitude)
function OPSTRANSPORT:AddPathPickup(PathGroup, Reversed, Radius, Altitude, TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
local path={} --#OPSTRANSPORT.Path
path.coords={}
@ -744,20 +950,26 @@ function OPSTRANSPORT:AddPathPickup(PathGroup, Reversed, Radius, Altitude)
end
-- Add path.
table.insert(self.pathsPickup, path)
table.insert(TransportZoneCombo.PickupPaths, path)
return self
end
--- Get a path for pickup.
-- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport Zone combo.
-- @return #table The path of COORDINATEs.
function OPSTRANSPORT:_GetPathPickup()
function OPSTRANSPORT:_GetPathPickup(TransportZoneCombo)
if self.pathsPickup and #self.pathsPickup>0 then
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
local paths=TransportZoneCombo.PickupPaths
if paths and #paths>0 then
-- Get a random path for transport.
local path=self.pathsPickup[math.random(#self.pathsPickup)] --#OPSTRANSPORT.Path
local path=paths[math.random(#paths)] --#OPSTRANSPORT.Path
local coordinates={}
@ -857,8 +1069,8 @@ function OPSTRANSPORT:IsReadyToGo()
-- Pickup AND deploy zones must be set.
local gotzones=false
for _,_tz in pairs(self.transportZones) do
local tz=_tz --#OPSTRANSPORT.TransportZone
for _,_tz in pairs(self.tzCombos) do
local tz=_tz --#OPSTRANSPORT.TransportZoneCombo
if tz.PickupZone and tz.DeployZone then
gotzones=true
break
@ -961,8 +1173,8 @@ function OPSTRANSPORT:onafterStatus(From, Event, To)
-- Info about cargo and carrier.
if self.verbose>=2 then
for i,_tz in pairs(self.transportZones) do
local tz=_tz --#OPSTRANSPORT.TransportZone
for i,_tz in pairs(self.tzCombos) do
local tz=_tz --#OPSTRANSPORT.TransportZoneCombo
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
@ -1166,17 +1378,23 @@ end
--- Check if all required cargos are loaded.
-- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #boolean If true, all required cargos are loaded or there is no required cargo.
function OPSTRANSPORT:_CheckRequiredCargos()
function OPSTRANSPORT:_CheckRequiredCargos(TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
if self.requiredCargos==nil or #self.requiredCargos==0 then
local requiredCargos=TransportZoneCombo.RequiredCargos
if requiredCargos==nil or #requiredCargos==0 then
return true
end
local carrierNames=self:_GetCarrierNames()
local gotit=true
for _,_cargo in pairs(self.requiredCargos) do
for _,_cargo in pairs(requiredCargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP
@ -1219,26 +1437,30 @@ end
-- @param #OPSTRANSPORT self
-- @param Ops.OpsGroup#OPSGROUP CargoGroup The cargo group that needs to be loaded into a carrier unit/element of the carrier group.
-- @param Core.Zone#ZONE Zone (Optional) Zone where the carrier must be in.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return Ops.OpsGroup#OPSGROUP.Element New carrier element for cargo or nil.
-- @return Ops.OpsGroup#OPSGROUP New carrier group for cargo or nil.
function OPSTRANSPORT:FindTransferCarrierForCargo(CargoGroup, Zone)
function OPSTRANSPORT:FindTransferCarrierForCargo(CargoGroup, Zone, TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
local carrier=nil --Ops.OpsGroup#OPSGROUP.Element
local carrierGroup=nil --Ops.OpsGroup#OPSGROUP
--TODO: maybe sort the carriers wrt to largest free cargo bay. Or better smallest free cargo bay that can take the cargo group weight.
for _,_carrier in pairs(self.disembarkCarriers or {}) do
for _,_carrier in pairs(TransportZoneCombo.DisembarkCarriers) do
local carrierGroup=_carrier --Ops.OpsGroup#OPSGROUP
-- First check if carrier is alive and loading cargo.
if carrierGroup and carrierGroup:IsAlive() and (carrierGroup:IsLoading() or self.deployzone:IsInstanceOf("ZONE_AIRBASE")) then
if carrierGroup and carrierGroup:IsAlive() and (carrierGroup:IsLoading() or TransportZoneCombo.DeployAirbase) then
-- Find an element of the group that has enough free space.
carrier=carrierGroup:FindCarrierForCargo(CargoGroup)
if carrier then
if Zone==nil or Zone:IsCoordinateInZone(carrier.unit:GetCoordinate()) then
if Zone==nil or Zone:IsVec2InZone(carrier.unit:GetVec2()) then
return carrier, carrierGroup
else
self:T2(self.lid.."Got transfer carrier but carrier not in zone (yet)!")
@ -1277,10 +1499,11 @@ end
-- @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.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #number Number of cargo groups.
function OPSTRANSPORT:_CountCargosInZone(Zone, Delivered, Carrier)
function OPSTRANSPORT:_CountCargosInZone(Zone, Delivered, Carrier, TransportZoneCombo)
local cargos=self:GetCargoOpsGroups(Delivered, Carrier)
local cargos=self:GetCargoOpsGroups(Delivered, Carrier, TransportZoneCombo)
local N=0
for _,_cargo in pairs(cargos) do
@ -1293,37 +1516,52 @@ function OPSTRANSPORT:_CountCargosInZone(Zone, Delivered, Carrier)
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.
--- Get a transport zone combination (TZC) for a carrier group. The pickup zone 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)
function OPSTRANSPORT:_GetTransportZoneCombo(Carrier)
env.info(string.format("FF GetPickupZone"))
local pickup=nil
--- Selection criteria
-- * Distance: pickup zone should be as close as possible.
-- * Ncargo: Number of cargo groups. Pickup, where there is most cargo.
-- * Ncarrier: Number of carriers already "working" on this TZC. Would be better if not all carriers work on the same combo while others are ignored.
-- Get carrier position.
local vec2=Carrier:GetVec2()
local pickup=nil --#OPSTRANSPORT.TransportZoneCombo
local distmin=nil
for i,_transportzone in pairs(self.transportZones) do
local tz=_transportzone --#OPSTRANSPORT.TransportZone
for i,_transportzone in pairs(self.tzCombos) do
local tz=_transportzone --#OPSTRANSPORT.TransportZoneCombo
-- Count cargos in pickup zone.
local ncargo=self:_CountCargosInZone(tz.PickupZone, false, Carrier)
-- Check that pickup and deploy zones were defined.
if tz.PickupZone and tz.DeployZone and tz.EmbarkZone then
env.info(string.format("FF GetPickupZone i=%d, ncargo=%d", i, ncargo))
if ncargo>0 then
local vec2=Carrier:GetVec2()
-- Count undelivered cargos in embark(!) zone that fit into the carrier.
local ncargo=self:_CountCargosInZone(tz.EmbarkZone, false, Carrier, tz)
local dist=tz.PickupZone:Get2DDistance(vec2)
if distmin==nil or dist<distmin then
distmin=dist
pickup=tz
--env.info(string.format("FF GetPickupZone i=%d, ncargo=%d", i, ncargo))
if ncargo>0 then
local dist=tz.PickupZone:Get2DDistance(vec2)
if distmin==nil or dist<distmin then
distmin=dist
pickup=tz
end
end
end
end
-- Debug info.
if pickup then
self:T(self.lid..string.format("Found pickupzone %s for carrier group %s", pickup.PickupZone:GetName(), Carrier:GetName()))
else
self:T(self.lid..string.format("Could NOT find a pickup zone (with cargo) for carrier group %s", Carrier:GetName()))
end
return pickup
end
@ -1361,4 +1599,3 @@ function OPSTRANSPORT:_GetOpsGroupFromObject(Object)
return opsgroup
end