AI_A2A_PATROL:
- Added optional race track pattern.

AI_A2A_DISPATCHER:
- Added option for CAP patrolling in a race track pattern.
This commit is contained in:
Frank 2019-07-06 20:23:07 +02:00
parent 6f140be710
commit 6973e8c028
2 changed files with 187 additions and 27 deletions

View File

@ -643,6 +643,25 @@ do -- AI_A2A_DISPATCHER
-- -- Setup the Refuelling for squadron "Gelend", at tanker (group) "TankerGelend" when the fuel in the tank of the CAP defenders is less than 80%.
-- A2ADispatcher:SetSquadronFuelThreshold( "Gelend", 0.8 )
-- A2ADispatcher:SetSquadronTanker( "Gelend", "TankerGelend" )
--
-- ## 7.4 Set up race track pattern
--
-- By default, flights patrol randomly within the CAP zone. It is also possible to let them fly a race track pattern using the
-- @{#AI_A2A_DISPATCHER.SetDefaultCapRacetrack}(*LeglengthMin*, *LeglengthMax*, *HeadingMin*, *HeadingMax*, *DurationMin*, *DurationMax*) or
-- @{#AI_A2A_DISPATCHER.SetSquadronCapRacetrack}(*SquadronName*, *LeglengthMin*, *LeglengthMax*, *HeadingMin*, *HeadingMax*, *DurationMin*, *DurationMax*) functions.
-- The first function enables this for all squadrons, the latter only for specific squadrons. For example,
--
-- -- Enable race track pattern for CAP squadron "Mineralnye".
-- A2ADispatcher:SetSquadronCapRacetrack("Mineralnye", 10000, 20000, 90, 180, 10*60, 20*60)
--
-- In this case the squadron "Mineralnye" will a race track pattern at a random point in the CAP zone. The leg length will be randomly selected between 10,000 and 20,000 meters. The heading
-- of the race track will randomly selected between 90 (West to East) and 180 (North to South) degrees.
-- After a random duration between 10 and 20 minutes, the flight will get a new random orbit location.
--
-- Note that all parameters except the squadron name are optional. If not specified, default values are taken. Speed and altitude are taken from the
--
-- Also note that the center of the race track pattern is chosen randomly within the patrol zone and can be close the the boarder of the zone. Hence, it cannot be guaranteed that the
-- whole pattern lies within the patrol zone.
--
-- ## 8. Setup a squadron for GCI:
--
@ -852,6 +871,13 @@ do -- AI_A2A_DISPATCHER
-- @field #table Table of template group names of the squadron.
-- @field #table Spawn Table of spaws Core.Spawn#SPAWN.
-- @field #table TemplatePrefixes
-- @field #boolean Racetrack If true, CAP flights will perform a racetrack pattern rather than randomly patrolling the zone.
-- @field #number RacetrackLengthMin Min Length of race track in meters. Default 10,000 m.
-- @field #number RacetrackLengthMax Max Length of race track in meters. Default 15,000 m.
-- @field #number RacetrackHeadingMin Min heading of race track in degrees. Default 0 deg, i.e. from South to North.
-- @field #number RacetrackHeadingMax Max heading of race track in degrees. Default 180 deg, i.e. from North to South.
-- @field #number RacetrackDurationMin Min duration in seconds before the CAP flight changes its orbit position. Default never.
-- @field #number RacetrackDurationMax Max duration in seconds before the CAP flight changes its orbit position. Default never.
--- Enumerator for spawns at airbases
-- @type AI_A2A_DISPATCHER.Takeoff
@ -1676,7 +1702,8 @@ do -- AI_A2A_DISPATCHER
DefenderSquadron.Uncontrolled = true
for SpawnTemplate, DefenderSpawn in pairs( self.DefenderSpawns ) do
for SpawnTemplate,_DefenderSpawn in pairs( self.DefenderSpawns ) do
local DefenderSpawn=_DefenderSpawn --Core.Spawn#SPAWN
DefenderSpawn:InitUnControlled()
end
@ -1842,7 +1869,7 @@ do -- AI_A2A_DISPATCHER
--- Check if squadron can do CAP.
-- @param #AI_A2A_DISPATCHER self
-- @param #string SquadronName The squadron name.
-- @return #table DefenderSquadron
-- @return #AI_A2A_DISPATCHER.Squadron DefenderSquadron
function AI_A2A_DISPATCHER:CanCAP( SquadronName )
self:F({SquadronName = SquadronName})
@ -1872,6 +1899,54 @@ do -- AI_A2A_DISPATCHER
end
--- Set race track pattern as default when any squadron is performing CAP.
-- @param #AI_A2A_DISPATCHER self
-- @param #number LeglengthMin Min length of the race track leg in meters. Default 10,000 m.
-- @param #number HeadingMin Min heading of the race track in degrees. Default 0 deg, i.e. from South to North.
-- @param #number HeadingMax Max heading of the race track in degrees. Default 180 deg, i.e. from North to South.
-- @param #number DurationMin (Optional) Min duration in seconds before switching the orbit position. Default is keep same orbit until RTB or engage.
-- @param #number DurationMax (Optional) Max duration in seconds before switching the orbit position. Default is keep same orbit until RTB or engage.
-- @return #AI_A2A_DISPATCHER self
function AI_A2A_DISPATCHER:SetDefaultCapRacetrack(LeglengthMin, LeglengthMax, HeadingMin, HeadingMax, DurationMin, DurationMax)
self.DefenderDefault.Racetrack=true
self.DefenderDefault.RacetrackLengthMin=LeglengthMin
self.DefenderDefault.RacetrackLengthMax=LeglengthMax
self.DefenderDefault.RacetrackHeadingMin=HeadingMin
self.DefenderDefault.RacetrackHeadingMax=HeadingMax
self.DefenderDefault.RacetrackDurationMin=DurationMin
self.DefenderDefault.RacetrackDurationMax=DurationMax
return self
end
--- Set race track pattern when squadron is performing CAP.
-- @param #AI_A2A_DISPATCHER self
-- @param #string SquadronName Name of the squadron.
-- @param #number LeglengthMin Min length of the race track leg in meters. Default 10,000 m.
-- @param #number HeadingMin Min heading of the race track in degrees. Default 0 deg, i.e. from South to North.
-- @param #number HeadingMax Max heading of the race track in degrees. Default 180 deg, i.e. from North to South.
-- @param #number DurationMin (Optional) Min duration in seconds before switching the orbit position. Default is keep same orbit until RTB or engage.
-- @param #number DurationMax (Optional) Max duration in seconds before switching the orbit position. Default is keep same orbit until RTB or engage.
-- @return #AI_A2A_DISPATCHER self
function AI_A2A_DISPATCHER:SetSquadronCapRacetrack(SquadronName, LeglengthMin, LeglengthMax, HeadingMin, HeadingMax, DurationMin, DurationMax)
local DefenderSquadron = self:GetSquadron( SquadronName )
if DefenderSquadron then
DefenderSquadron.Racetrack=true
DefenderSquadron.RacetrackLengthMin=LeglengthMin
DefenderSquadron.RacetrackLengthMax=LeglengthMax
DefenderSquadron.RacetrackHeadingMin=HeadingMin
DefenderSquadron.RacetrackHeadingMax=HeadingMax
DefenderSquadron.RacetrackDurationMin=DurationMin
DefenderSquadron.RacetrackDurationMax=DurationMax
end
return self
end
--- Check if squadron can do GCI.
-- @param #AI_A2A_DISPATCHER self
-- @param #string SquadronName The squadron name.
@ -2927,6 +3002,14 @@ do -- AI_A2A_DISPATCHER
Fsm:SetDamageThreshold( self.DefenderDefault.DamageThreshold )
Fsm:SetDisengageRadius( self.DisengageRadius )
Fsm:SetTanker( DefenderSquadron.TankerName or self.DefenderDefault.TankerName )
if DefenderSquadron.Racetrack or self.DefenderDefault.Racetrack then
Fsm:SetRaceTrackPattern(DefenderSquadron.RacetrackLengthMin or self.DefenderDefault.RacetrackLengthMin,
DefenderSquadron.RacetrackLengthMax or self.DefenderDefault.RacetrackLengthMax,
DefenderSquadron.RacetrackHeadingMin or self.DefenderDefault.RacetrackHeadingMin,
DefenderSquadron.RacetrackHeadingMax or self.DefenderDefault.RacetrackHeadingMax,
DefenderSquadron.RacetrackDurationMin or self.DefenderDefault.RacetrackDurationMin,
DefenderSquadron.RacetrackDurationMax or self.DefenderDefault.RacetrackDurationMax)
end
Fsm:Start()
self:SetDefenderTask( SquadronName, DefenderCAP, "CAP", Fsm )
@ -3328,8 +3411,10 @@ do -- AI_A2A_DISPATCHER
DefenderGroupCount = DefenderGroupCount + 1
local Fuel = Defender:GetFuelMin() * 100
local Damage = Defender:GetLife() / Defender:GetLife0() * 100
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
Defender:GetName(),
Report:Add( string.format( " - %s*%d/%d ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
Defender:GetName(),
Defender:GetSize(),
Defender:GetInitialSize(),
DefenderTask.Type,
DefenderTask.Fsm:GetState(),
Defender:GetSize(),
@ -3354,8 +3439,10 @@ do -- AI_A2A_DISPATCHER
local Fuel = Defender:GetFuelMin() * 100
local Damage = Defender:GetLife() / Defender:GetLife0() * 100
DefenderGroupCount = DefenderGroupCount + 1
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
Report:Add( string.format( " - %s*%d/%d ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
Defender:GetName(),
Defender:GetSize(),
Defender:GetInitialSize(),
DefenderTask.Type,
DefenderTask.Fsm:GetState(),
Defender:GetSize(),

View File

@ -257,6 +257,31 @@ function AI_A2A_PATROL:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
self.PatrolCeilingAltitude = PatrolCeilingAltitude
end
--- Set race track parameters. CAP flights will perform race track patterns rather than randomly patrolling the zone.
-- @param #AI_A2A_PATROL self
-- @param #number LegMin Min Length of the race track leg in meters. Default 10,000 m.
-- @param #number LegMax Max length of the race track leg in meters. Default 15,000 m.
-- @param #number HeadingMin Min heading of the race track in degrees. Default 0 deg, i.e. from South to North.
-- @param #number HeadingMax Max heading of the race track in degrees. Default 180 deg, i.e. from South to North.
-- @param #number duration (Optional) Min duration before switching the orbit position. Default is keep same orbit until RTB or engage.
-- @param #number duration (Optional) Max duration before switching the orbit position. Default is keep same orbit until RTB or engage.
-- @return #AI_A2A_PATROL self
function AI_A2A_PATROL:SetRaceTrackPattern(LegMin, LegMax, HeadingMin, HeadingMax, DurationMin, DurationMax)
self:F2({leglength, duration})
self.racetrack=true
self.racetracklegmin=LegMin or 10000
self.racetracklegmax=LegMax or 15000
self.racetrackheadingmin=HeadingMin or 0
self.racetrackheadingmax=HeadingMax or 180
self.racetrackdurationmin=DurationMin
self.racetrackdurationmax=DurationMax
if self.racetrackdurationmax and not self.racetrackdurationmin then
self.racetrackdurationmin=self.racetrackdurationmax
end
end
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
-- @param #AI_A2A_PATROL self
@ -312,7 +337,7 @@ function AI_A2A_PATROL:onafterRoute( AIPatrol, From, Event, To )
end
if AIPatrol:IsAlive() then
if AIPatrol and AIPatrol:IsAlive() then
local PatrolRoute = {}
@ -320,31 +345,79 @@ function AI_A2A_PATROL:onafterRoute( AIPatrol, From, Event, To )
local CurrentCoord = AIPatrol:GetCoordinate()
local ToTargetCoord = self.PatrolZone:GetRandomPointVec2()
ToTargetCoord:SetAlt( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ) )
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
if self.racetrack then
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
--- Create a route point of type air.
local ToPatrolRoutePoint = ToTargetCoord:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed,
true
)
-- Random altitude.
local altitude=math.random(self.PatrolFloorAltitude, self.PatrolCeilingAltitude)
-- Random speed in km/h.
local speedkmh = math.random(self.PatrolMinSpeed, self.PatrolMaxSpeed)
-- Random heading.
local heading = math.random(self.racetrackheadingmin, self.racetrackheadingmax)
-- Random leg length.
local leg=math.random(self.racetracklegmin, self.racetracklegmax)
-- Random duration if any.
local duration = self.racetrackdurationmin
if self.racetrackdurationmax then
duration=math.random(self.racetrackdurationmin, self.racetrackdurationmax)
end
-- Race track points.
local c1=self.PatrolZone:GetRandomCoordinate():SetAltitude(altitude) --Core.Point#COORDINATE
local c2=c1:Translate(leg, heading):SetAltitude(altitude)
-- Debug:
self:T(string.format("Patrol zone race track: v=%.1f knots, h=%.1f ft, heading=%03d, leg=%d m, t=%s sec", UTILS.KmphToKnots(speedkmh), UTILS.MetersToFeet(altitude), heading, leg, tostring(duration)))
--c1:MarkToAll("Race track c1")
--c2:MarkToAll("Race track c2")
PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint
PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint
local Tasks = {}
Tasks[#Tasks+1] = AIPatrol:TaskFunction( "AI_A2A_PATROL.PatrolRoute", self )
PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks )
-- Task to orbit.
local taskOrbit=AIPatrol:TaskOrbit(c1, altitude, UTILS.KmphToMps(speedkmh), c2)
-- Task function to redo the patrol at other random position.
local taskPatrol=AIPatrol:TaskFunction("AI_A2A_PATROL.PatrolRoute", self)
local taskCond=AIPatrol:TaskCondition(nil, nil, nil, nil, duration, nil)
local taskCont=AIPatrol:TaskControlled(taskOrbit, taskCond)
PatrolRoute[1]=CurrentCoord:WaypointAirTurningPoint(nil, speedkmh, {}, "Current")
PatrolRoute[2]=c1:WaypointAirTurningPoint(self.PatrolAltType, speedkmh, {taskCont, taskPatrol}, "Orbit")
else
local ToTargetCoord = self.PatrolZone:GetRandomPointVec2()
ToTargetCoord:SetAlt( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ) )
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
--- Create a route point of type air.
local ToPatrolRoutePoint = ToTargetCoord:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed,
true
)
PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint
PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint
local Tasks = {}
Tasks[#Tasks+1] = AIPatrol:TaskFunction( "AI_A2A_PATROL.PatrolRoute", self )
PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks )
end
-- ROE
AIPatrol:OptionROEReturnFire()
AIPatrol:OptionROTEvadeFire()
-- Patrol.
AIPatrol:Route( PatrolRoute, 0.5)
end