mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Progress, patrolling works. Engagement not yet.
This commit is contained in:
parent
3789674666
commit
0e656c8520
@ -281,8 +281,8 @@ do -- AI_A2G_DISPATCHER
|
||||
self:SetDefaultGrouping( 1 )
|
||||
self:SetDefaultFuelThreshold( 0.15, 0 ) -- 15% of fuel remaining in the tank will trigger the airplane to return to base or refuel.
|
||||
self:SetDefaultDamageThreshold( 0.4 ) -- When 40% of damage, go RTB.
|
||||
self:SetDefaultCapTimeInterval( 180, 600 ) -- Between 180 and 600 seconds.
|
||||
self:SetDefaultCapLimit( 1 ) -- Maximum one CAP per squadron.
|
||||
self:SetDefaultPatrolTimeInterval( 180, 600 ) -- Between 180 and 600 seconds.
|
||||
self:SetDefaultPatrolLimit( 1 ) -- Maximum one Patrol per squadron.
|
||||
|
||||
|
||||
self:AddTransition( "Started", "Assign", "Started" )
|
||||
@ -297,33 +297,33 @@ do -- AI_A2G_DISPATCHER
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param #string PlayerName
|
||||
|
||||
self:AddTransition( "*", "CAP", "*" )
|
||||
self:AddTransition( "*", "Patrol", "*" )
|
||||
|
||||
--- CAP Handler OnBefore for AI_A2G_DISPATCHER
|
||||
-- @function [parent=#AI_A2G_DISPATCHER] OnBeforeCAP
|
||||
--- Patrol Handler OnBefore for AI_A2G_DISPATCHER
|
||||
-- @function [parent=#AI_A2G_DISPATCHER] OnBeforePatrol
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- CAP Handler OnAfter for AI_A2G_DISPATCHER
|
||||
-- @function [parent=#AI_A2G_DISPATCHER] OnAfterCAP
|
||||
--- Patrol Handler OnAfter for AI_A2G_DISPATCHER
|
||||
-- @function [parent=#AI_A2G_DISPATCHER] OnAfterPatrol
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
--- CAP Trigger for AI_A2G_DISPATCHER
|
||||
-- @function [parent=#AI_A2G_DISPATCHER] CAP
|
||||
--- Patrol Trigger for AI_A2G_DISPATCHER
|
||||
-- @function [parent=#AI_A2G_DISPATCHER] Patrol
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
|
||||
--- CAP Asynchronous Trigger for AI_A2G_DISPATCHER
|
||||
-- @function [parent=#AI_A2G_DISPATCHER] __CAP
|
||||
--- Patrol Asynchronous Trigger for AI_A2G_DISPATCHER
|
||||
-- @function [parent=#AI_A2G_DISPATCHER] __Patrol
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #number Delay
|
||||
|
||||
self:AddTransition( "*", "DEFEND", "*" )
|
||||
self:AddTransition( "*", "Defend", "*" )
|
||||
|
||||
--- GCI Handler OnBefore for AI_A2G_DISPATCHER
|
||||
-- @function [parent=#AI_A2G_DISPATCHER] OnBeforeGCI
|
||||
@ -395,7 +395,7 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
self:SetTacticalDisplay( false )
|
||||
|
||||
self.DefenderCAPIndex = 0
|
||||
self.DefenderPatrolIndex = 0
|
||||
|
||||
self:__Start( 5 )
|
||||
|
||||
@ -626,8 +626,8 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
|
||||
--- Define a border area to simulate a **cold war** scenario.
|
||||
-- A **cold war** is one where CAP aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border.
|
||||
-- A **hot war** is one where CAP aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send CAP and GCI aircraft to attack it.
|
||||
-- A **cold war** is one where Patrol aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border.
|
||||
-- A **hot war** is one where Patrol aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send Patrol and GCI aircraft to attack it.
|
||||
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
|
||||
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. Set the noborders parameter to 1
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
@ -704,45 +704,45 @@ do -- AI_A2G_DISPATCHER
|
||||
end
|
||||
|
||||
|
||||
--- Set the default CAP time interval for squadrons, which will be used to determine a random CAP timing.
|
||||
-- The default CAP time interval is between 180 and 600 seconds.
|
||||
--- Set the default Patrol time interval for squadrons, which will be used to determine a random Patrol timing.
|
||||
-- The default Patrol time interval is between 180 and 600 seconds.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #number CapMinSeconds The minimum amount of seconds for the random time interval.
|
||||
-- @param #number CapMaxSeconds The maximum amount of seconds for the random time interval.
|
||||
-- @param #number PatrolMinSeconds The minimum amount of seconds for the random time interval.
|
||||
-- @param #number PatrolMaxSeconds The maximum amount of seconds for the random time interval.
|
||||
-- @return #AI_A2G_DISPATCHER
|
||||
-- @usage
|
||||
--
|
||||
-- -- Now Setup the A2G dispatcher, and initialize it using the Detection object.
|
||||
-- A2GDispatcher = AI_A2G_DISPATCHER:New( Detection )
|
||||
--
|
||||
-- -- Now Setup the default CAP time interval.
|
||||
-- A2GDispatcher:SetDefaultCapTimeInterval( 300, 1200 ) -- Between 300 and 1200 seconds.
|
||||
-- -- Now Setup the default Patrol time interval.
|
||||
-- A2GDispatcher:SetDefaultPatrolTimeInterval( 300, 1200 ) -- Between 300 and 1200 seconds.
|
||||
--
|
||||
function AI_A2G_DISPATCHER:SetDefaultCapTimeInterval( CapMinSeconds, CapMaxSeconds )
|
||||
function AI_A2G_DISPATCHER:SetDefaultPatrolTimeInterval( PatrolMinSeconds, PatrolMaxSeconds )
|
||||
|
||||
self.DefenderDefault.CapMinSeconds = CapMinSeconds
|
||||
self.DefenderDefault.CapMaxSeconds = CapMaxSeconds
|
||||
self.DefenderDefault.PatrolMinSeconds = PatrolMinSeconds
|
||||
self.DefenderDefault.PatrolMaxSeconds = PatrolMaxSeconds
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set the default CAP limit for squadrons, which will be used to determine how many CAP can be airborne at the same time for the squadron.
|
||||
-- The default CAP limit is 1 CAP, which means one CAP group being spawned.
|
||||
--- Set the default Patrol limit for squadrons, which will be used to determine how many Patrol can be airborne at the same time for the squadron.
|
||||
-- The default Patrol limit is 1 Patrol, which means one Patrol group being spawned.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #number CapLimit The maximum amount of CAP that can be airborne at the same time for the squadron.
|
||||
-- @param #number PatrolLimit The maximum amount of Patrol that can be airborne at the same time for the squadron.
|
||||
-- @return #AI_A2G_DISPATCHER
|
||||
-- @usage
|
||||
--
|
||||
-- -- Now Setup the A2G dispatcher, and initialize it using the Detection object.
|
||||
-- A2GDispatcher = AI_A2G_DISPATCHER:New( Detection )
|
||||
--
|
||||
-- -- Now Setup the default CAP limit.
|
||||
-- A2GDispatcher:SetDefaultCapLimit( 2 ) -- Maximum 2 CAP per squadron.
|
||||
-- -- Now Setup the default Patrol limit.
|
||||
-- A2GDispatcher:SetDefaultPatrolLimit( 2 ) -- Maximum 2 Patrol per squadron.
|
||||
--
|
||||
function AI_A2G_DISPATCHER:SetDefaultCapLimit( CapLimit )
|
||||
function AI_A2G_DISPATCHER:SetDefaultPatrolLimit( PatrolLimit )
|
||||
|
||||
self.DefenderDefault.CapLimit = CapLimit
|
||||
self.DefenderDefault.PatrolLimit = PatrolLimit
|
||||
|
||||
return self
|
||||
end
|
||||
@ -1046,115 +1046,45 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
end
|
||||
|
||||
--- Set a CAP for a Squadron.
|
||||
|
||||
--- Set the squadron Patrol parameters.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed.
|
||||
-- @param #number FloorAltitude The minimum altitude at which the cap can be executed.
|
||||
-- @param #number CeilingAltitude the maximum altitude at which the cap can be executed.
|
||||
-- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed.
|
||||
-- @param #number PatrolMaxSpeed The maximum speed at which the cap can be executed.
|
||||
-- @param #number EngageMinSpeed The minimum speed at which the engage can be executed.
|
||||
-- @param #number EngageMaxSpeed The maximum speed at which the engage can be executed.
|
||||
-- @param #number AltType The altitude type, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude.
|
||||
-- @return #AI_A2G_DISPATCHER
|
||||
-- @usage
|
||||
--
|
||||
-- -- CAP Squadron execution.
|
||||
-- CAPZoneEast = ZONE_POLYGON:New( "CAP Zone East", GROUP:FindByName( "CAP Zone East" ) )
|
||||
-- A2GDispatcher:SetSquadronCap( "Mineralnye", CAPZoneEast, 4000, 10000, 500, 600, 800, 900 )
|
||||
-- A2GDispatcher:SetSquadronCapInterval( "Mineralnye", 2, 30, 60, 1 )
|
||||
--
|
||||
-- CAPZoneWest = ZONE_POLYGON:New( "CAP Zone West", GROUP:FindByName( "CAP Zone West" ) )
|
||||
-- A2GDispatcher:SetSquadronCap( "Sochi", CAPZoneWest, 4000, 8000, 600, 800, 800, 1200, "BARO" )
|
||||
-- A2GDispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 )
|
||||
--
|
||||
-- CAPZoneMiddle = ZONE:New( "CAP Zone Middle")
|
||||
-- A2GDispatcher:SetSquadronCap( "Maykop", CAPZoneMiddle, 4000, 8000, 600, 800, 800, 1200, "RADIO" )
|
||||
-- A2GDispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 )
|
||||
--
|
||||
function AI_A2G_DISPATCHER:SetSquadronCap( SquadronName, Zone, FloorAltitude, CeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, AltType )
|
||||
|
||||
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
|
||||
self.DefenderSquadrons[SquadronName].Cap = self.DefenderSquadrons[SquadronName].Cap or {}
|
||||
|
||||
local DefenderSquadron = self:GetSquadron( SquadronName )
|
||||
|
||||
local Cap = self.DefenderSquadrons[SquadronName].Cap
|
||||
Cap.Name = SquadronName
|
||||
Cap.Zone = Zone
|
||||
Cap.FloorAltitude = FloorAltitude
|
||||
Cap.CeilingAltitude = CeilingAltitude
|
||||
Cap.PatrolMinSpeed = PatrolMinSpeed
|
||||
Cap.PatrolMaxSpeed = PatrolMaxSpeed
|
||||
Cap.EngageMinSpeed = EngageMinSpeed
|
||||
Cap.EngageMaxSpeed = EngageMaxSpeed
|
||||
Cap.AltType = AltType
|
||||
|
||||
self:SetSquadronCapInterval( SquadronName, self.DefenderDefault.CapLimit, self.DefenderDefault.CapMinSeconds, self.DefenderDefault.CapMaxSeconds, 1 )
|
||||
|
||||
self:F( { CAP = { SquadronName, Zone, FloorAltitude, CeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, AltType } } )
|
||||
|
||||
-- Add the CAP to the EWR network.
|
||||
|
||||
local RecceSet = self.Detection:GetDetectionSetGroup()
|
||||
RecceSet:FilterPrefixes( DefenderSquadron.TemplatePrefixes )
|
||||
RecceSet:FilterStart()
|
||||
|
||||
self.Detection:SetFriendlyPrefixes( DefenderSquadron.TemplatePrefixes )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the squadron CAP parameters.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @param #number CapLimit (optional) The maximum amount of CAP groups to be spawned. Note that a CAP is a group, so can consist out of 1 to 4 airplanes. The default is 1 CAP group.
|
||||
-- @param #number LowInterval (optional) The minimum time boundary in seconds when a new CAP will be spawned. The default is 180 seconds.
|
||||
-- @param #number HighInterval (optional) The maximum time boundary in seconds when a new CAP will be spawned. The default is 600 seconds.
|
||||
-- @param #number PatrolLimit (optional) The maximum amount of Patrol groups to be spawned. Note that a Patrol is a group, so can consist out of 1 to 4 airplanes. The default is 1 Patrol group.
|
||||
-- @param #number LowInterval (optional) The minimum time boundary in seconds when a new Patrol will be spawned. The default is 180 seconds.
|
||||
-- @param #number HighInterval (optional) The maximum time boundary in seconds when a new Patrol will be spawned. The default is 600 seconds.
|
||||
-- @param #number Probability Is not in use, you can skip this parameter.
|
||||
-- @return #AI_A2G_DISPATCHER
|
||||
-- @usage
|
||||
--
|
||||
-- -- CAP Squadron execution.
|
||||
-- CAPZoneEast = ZONE_POLYGON:New( "CAP Zone East", GROUP:FindByName( "CAP Zone East" ) )
|
||||
-- A2GDispatcher:SetSquadronCap( "Mineralnye", CAPZoneEast, 4000, 10000, 500, 600, 800, 900 )
|
||||
-- A2GDispatcher:SetSquadronCapInterval( "Mineralnye", 2, 30, 60, 1 )
|
||||
--
|
||||
-- CAPZoneWest = ZONE_POLYGON:New( "CAP Zone West", GROUP:FindByName( "CAP Zone West" ) )
|
||||
-- A2GDispatcher:SetSquadronCap( "Sochi", CAPZoneWest, 4000, 8000, 600, 800, 800, 1200, "BARO" )
|
||||
-- A2GDispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 )
|
||||
--
|
||||
-- CAPZoneMiddle = ZONE:New( "CAP Zone Middle")
|
||||
-- A2GDispatcher:SetSquadronCap( "Maykop", CAPZoneMiddle, 4000, 8000, 600, 800, 800, 1200, "RADIO" )
|
||||
-- A2GDispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 )
|
||||
-- -- Patrol Squadron execution.
|
||||
-- PatrolZoneEast = ZONE_POLYGON:New( "Patrol Zone East", GROUP:FindByName( "Patrol Zone East" ) )
|
||||
-- A2GDispatcher:SetSquadronSeadPatrol( "Mineralnye", PatrolZoneEast, 4000, 10000, 500, 600, 800, 900 )
|
||||
-- A2GDispatcher:SetSquadronPatrolInterval( "Mineralnye", 2, 30, 60, 1 )
|
||||
--
|
||||
function AI_A2G_DISPATCHER:SetSquadronCapInterval( SquadronName, CapLimit, LowInterval, HighInterval, Probability )
|
||||
function AI_A2G_DISPATCHER:SetSquadronPatrolInterval( SquadronName, PatrolLimit, LowInterval, HighInterval, Probability, DefenseTaskType )
|
||||
|
||||
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
|
||||
self.DefenderSquadrons[SquadronName].Cap = self.DefenderSquadrons[SquadronName].Cap or {}
|
||||
|
||||
local DefenderSquadron = self:GetSquadron( SquadronName )
|
||||
|
||||
local Cap = self.DefenderSquadrons[SquadronName].Cap
|
||||
if Cap then
|
||||
Cap.LowInterval = LowInterval or 180
|
||||
Cap.HighInterval = HighInterval or 600
|
||||
Cap.Probability = Probability or 1
|
||||
Cap.CapLimit = CapLimit or 1
|
||||
Cap.Scheduler = Cap.Scheduler or SCHEDULER:New( self )
|
||||
local Scheduler = Cap.Scheduler -- Core.Scheduler#SCHEDULER
|
||||
local ScheduleID = Cap.ScheduleID
|
||||
local Variance = ( Cap.HighInterval - Cap.LowInterval ) / 2
|
||||
local Repeat = Cap.LowInterval + Variance
|
||||
local Patrol = DefenderSquadron[DefenseTaskType]
|
||||
if Patrol then
|
||||
Patrol.LowInterval = LowInterval or 180
|
||||
Patrol.HighInterval = HighInterval or 600
|
||||
Patrol.Probability = Probability or 1
|
||||
Patrol.PatrolLimit = PatrolLimit or 1
|
||||
Patrol.Scheduler = Patrol.Scheduler or SCHEDULER:New( self )
|
||||
local Scheduler = Patrol.Scheduler -- Core.Scheduler#SCHEDULER
|
||||
local ScheduleID = Patrol.ScheduleID
|
||||
local Variance = ( Patrol.HighInterval - Patrol.LowInterval ) / 2
|
||||
local Repeat = Patrol.LowInterval + Variance
|
||||
local Randomization = Variance / Repeat
|
||||
local Start = math.random( 1, Cap.HighInterval )
|
||||
local Start = math.random( 1, Patrol.HighInterval )
|
||||
|
||||
if ScheduleID then
|
||||
Scheduler:Stop( ScheduleID )
|
||||
end
|
||||
|
||||
Cap.ScheduleID = Scheduler:Schedule( self, self.SchedulerCAP, { SquadronName }, Start, Repeat, Randomization )
|
||||
Patrol.ScheduleID = Scheduler:Schedule( self, self.SchedulerPatrol, { SquadronName }, Start, Repeat, Randomization )
|
||||
else
|
||||
error( "This squadron does not exist:" .. SquadronName )
|
||||
end
|
||||
@ -1165,16 +1095,16 @@ do -- AI_A2G_DISPATCHER
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @return #AI_A2G_DISPATCHER
|
||||
function AI_A2G_DISPATCHER:GetCAPDelay( SquadronName )
|
||||
function AI_A2G_DISPATCHER:GetPatrolDelay( SquadronName )
|
||||
|
||||
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
|
||||
self.DefenderSquadrons[SquadronName].Cap = self.DefenderSquadrons[SquadronName].Cap or {}
|
||||
self.DefenderSquadrons[SquadronName].Patrol = self.DefenderSquadrons[SquadronName].Patrol or {}
|
||||
|
||||
local DefenderSquadron = self:GetSquadron( SquadronName )
|
||||
|
||||
local Cap = self.DefenderSquadrons[SquadronName].Cap
|
||||
if Cap then
|
||||
return math.random( Cap.LowInterval, Cap.HighInterval )
|
||||
local Patrol = self.DefenderSquadrons[SquadronName].Patrol
|
||||
if Patrol then
|
||||
return math.random( Patrol.LowInterval, Patrol.HighInterval )
|
||||
else
|
||||
error( "This squadron does not exist:" .. SquadronName )
|
||||
end
|
||||
@ -1184,28 +1114,27 @@ do -- AI_A2G_DISPATCHER
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @return #table DefenderSquadron
|
||||
function AI_A2G_DISPATCHER:CanCAP( SquadronName )
|
||||
function AI_A2G_DISPATCHER:CanPatrol( SquadronName, DefenseTaskType )
|
||||
self:F({SquadronName = SquadronName})
|
||||
|
||||
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
|
||||
self.DefenderSquadrons[SquadronName].Cap = self.DefenderSquadrons[SquadronName].Cap or {}
|
||||
|
||||
local DefenderSquadron = self:GetSquadron( SquadronName )
|
||||
|
||||
if DefenderSquadron.Captured == false then -- We can only spawn new CAP if the base has not been captured.
|
||||
if DefenderSquadron.Captured == false then -- We can only spawn new Patrol if the base has not been captured.
|
||||
|
||||
if ( not DefenderSquadron.ResourceCount ) or ( DefenderSquadron.ResourceCount and DefenderSquadron.ResourceCount > 0 ) then -- And, if there are sufficient resources.
|
||||
|
||||
local Cap = DefenderSquadron.Cap
|
||||
if Cap then
|
||||
local CapCount = self:CountCapAirborne( SquadronName )
|
||||
self:F( { CapCount = CapCount } )
|
||||
if CapCount < Cap.CapLimit then
|
||||
|
||||
local Patrol = DefenderSquadron[DefenseTaskType]
|
||||
if Patrol and Patrol.Patrol == true then
|
||||
local PatrolCount = self:CountPatrolAirborne( SquadronName, DefenseTaskType )
|
||||
self:F( { PatrolCount = PatrolCount, PatrolLimit = Patrol.PatrolLimit, PatrolProbability = Patrol.Probability } )
|
||||
if PatrolCount < Patrol.PatrolLimit then
|
||||
local Probability = math.random()
|
||||
if Probability <= Cap.Probability then
|
||||
return DefenderSquadron
|
||||
if Probability <= Patrol.Probability then
|
||||
return DefenderSquadron, Patrol
|
||||
end
|
||||
end
|
||||
else
|
||||
self:F( "No patrol for " .. SquadronName )
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1217,7 +1146,7 @@ do -- AI_A2G_DISPATCHER
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @return #table DefenderSquadron
|
||||
function AI_A2G_DISPATCHER:CanDEFEND( SquadronName, DefenseTaskType )
|
||||
function AI_A2G_DISPATCHER:CanDefend( SquadronName, DefenseTaskType )
|
||||
self:F({SquadronName = SquadronName, DefenseTaskType})
|
||||
|
||||
local DefenderSquadron = self:GetSquadron( SquadronName )
|
||||
@ -1225,7 +1154,7 @@ do -- AI_A2G_DISPATCHER
|
||||
if DefenderSquadron.Captured == false then -- We can only spawn new defense if the home airbase has not been captured.
|
||||
|
||||
if ( not DefenderSquadron.ResourceCount ) or ( DefenderSquadron.ResourceCount and DefenderSquadron.ResourceCount > 0 ) then -- And, if there are sufficient resources.
|
||||
if DefenderSquadron[DefenseTaskType] then
|
||||
if DefenderSquadron[DefenseTaskType] and DefenderSquadron[DefenseTaskType].Defend == true then
|
||||
return DefenderSquadron, DefenderSquadron[DefenseTaskType]
|
||||
end
|
||||
end
|
||||
@ -1257,11 +1186,55 @@ do -- AI_A2G_DISPATCHER
|
||||
Sead.Name = SquadronName
|
||||
Sead.EngageMinSpeed = EngageMinSpeed
|
||||
Sead.EngageMaxSpeed = EngageMaxSpeed
|
||||
Sead.Defend = true
|
||||
|
||||
self:F( { Sead = Sead } )
|
||||
end
|
||||
|
||||
|
||||
--- Set a Sead patrol for a Squadron.
|
||||
-- The Sead patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param #number FloorAltitude The minimum altitude at which the cap can be executed.
|
||||
-- @param #number CeilingAltitude the maximum altitude at which the cap can be executed.
|
||||
-- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed.
|
||||
-- @param #number PatrolMaxSpeed The maximum speed at which the cap can be executed.
|
||||
-- @param #number EngageMinSpeed The minimum speed at which the engage can be executed.
|
||||
-- @param #number EngageMaxSpeed The maximum speed at which the engage can be executed.
|
||||
-- @param #number AltType The altitude type, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude.
|
||||
-- @return #AI_A2G_DISPATCHER
|
||||
-- @usage
|
||||
--
|
||||
-- -- Sead Patrol Squadron execution.
|
||||
-- PatrolZoneEast = ZONE_POLYGON:New( "Patrol Zone East", GROUP:FindByName( "Patrol Zone East" ) )
|
||||
-- A2GDispatcher:SetSquadronSeadPatrol( "Mineralnye", PatrolZoneEast, 4000, 10000, 500, 600, 800, 900 )
|
||||
--
|
||||
function AI_A2G_DISPATCHER:SetSquadronSeadPatrol( SquadronName, Zone, FloorAltitude, CeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, AltType )
|
||||
|
||||
local DefenderSquadron = self:GetSquadron( SquadronName )
|
||||
|
||||
DefenderSquadron.SEAD = DefenderSquadron.SEAD or {}
|
||||
|
||||
local SeadPatrol = DefenderSquadron.SEAD
|
||||
SeadPatrol.Name = SquadronName
|
||||
SeadPatrol.Zone = Zone
|
||||
SeadPatrol.FloorAltitude = FloorAltitude
|
||||
SeadPatrol.CeilingAltitude = CeilingAltitude
|
||||
SeadPatrol.PatrolMinSpeed = PatrolMinSpeed
|
||||
SeadPatrol.PatrolMaxSpeed = PatrolMaxSpeed
|
||||
SeadPatrol.EngageMinSpeed = EngageMinSpeed
|
||||
SeadPatrol.EngageMaxSpeed = EngageMaxSpeed
|
||||
SeadPatrol.AltType = AltType
|
||||
SeadPatrol.Patrol = true
|
||||
|
||||
self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "SEAD" )
|
||||
|
||||
self:F( { Sead = SeadPatrol } )
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
@ -1285,10 +1258,54 @@ do -- AI_A2G_DISPATCHER
|
||||
Cas.Name = SquadronName
|
||||
Cas.EngageMinSpeed = EngageMinSpeed
|
||||
Cas.EngageMaxSpeed = EngageMaxSpeed
|
||||
Cas.Defend = true
|
||||
|
||||
self:F( { Cas = Cas } )
|
||||
end
|
||||
|
||||
|
||||
--- Set a Cas patrol for a Squadron.
|
||||
-- The Cas patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param #number FloorAltitude The minimum altitude at which the cap can be executed.
|
||||
-- @param #number CeilingAltitude the maximum altitude at which the cap can be executed.
|
||||
-- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed.
|
||||
-- @param #number PatrolMaxSpeed The maximum speed at which the cap can be executed.
|
||||
-- @param #number EngageMinSpeed The minimum speed at which the engage can be executed.
|
||||
-- @param #number EngageMaxSpeed The maximum speed at which the engage can be executed.
|
||||
-- @param #number AltType The altitude type, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude.
|
||||
-- @return #AI_A2G_DISPATCHER
|
||||
-- @usage
|
||||
--
|
||||
-- -- Cas Patrol Squadron execution.
|
||||
-- PatrolZoneEast = ZONE_POLYGON:New( "Patrol Zone East", GROUP:FindByName( "Patrol Zone East" ) )
|
||||
-- A2GDispatcher:SetSquadronCasPatrol( "Mineralnye", PatrolZoneEast, 4000, 10000, 500, 600, 800, 900 )
|
||||
--
|
||||
function AI_A2G_DISPATCHER:SetSquadronCasPatrol( SquadronName, Zone, FloorAltitude, CeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, AltType )
|
||||
|
||||
local DefenderSquadron = self:GetSquadron( SquadronName )
|
||||
|
||||
DefenderSquadron.CAS = DefenderSquadron.CAS or {}
|
||||
|
||||
local CasPatrol = DefenderSquadron.CAS
|
||||
CasPatrol.Name = SquadronName
|
||||
CasPatrol.Zone = Zone
|
||||
CasPatrol.FloorAltitude = FloorAltitude
|
||||
CasPatrol.CeilingAltitude = CeilingAltitude
|
||||
CasPatrol.PatrolMinSpeed = PatrolMinSpeed
|
||||
CasPatrol.PatrolMaxSpeed = PatrolMaxSpeed
|
||||
CasPatrol.EngageMinSpeed = EngageMinSpeed
|
||||
CasPatrol.EngageMaxSpeed = EngageMaxSpeed
|
||||
CasPatrol.AltType = AltType
|
||||
CasPatrol.Patrol = true
|
||||
|
||||
self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "CAS" )
|
||||
|
||||
self:F( { Cas = CasPatrol } )
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
@ -1313,10 +1330,54 @@ do -- AI_A2G_DISPATCHER
|
||||
Bai.Name = SquadronName
|
||||
Bai.EngageMinSpeed = EngageMinSpeed
|
||||
Bai.EngageMaxSpeed = EngageMaxSpeed
|
||||
Bai.Defend = true
|
||||
|
||||
self:F( { Bai = Bai } )
|
||||
end
|
||||
|
||||
|
||||
--- Set a Bai patrol for a Squadron.
|
||||
-- The Bai patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param #number FloorAltitude The minimum altitude at which the cap can be executed.
|
||||
-- @param #number CeilingAltitude the maximum altitude at which the cap can be executed.
|
||||
-- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed.
|
||||
-- @param #number PatrolMaxSpeed The maximum speed at which the cap can be executed.
|
||||
-- @param #number EngageMinSpeed The minimum speed at which the engage can be executed.
|
||||
-- @param #number EngageMaxSpeed The maximum speed at which the engage can be executed.
|
||||
-- @param #number AltType The altitude type, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude.
|
||||
-- @return #AI_A2G_DISPATCHER
|
||||
-- @usage
|
||||
--
|
||||
-- -- Bai Patrol Squadron execution.
|
||||
-- PatrolZoneEast = ZONE_POLYGON:New( "Patrol Zone East", GROUP:FindByName( "Patrol Zone East" ) )
|
||||
-- A2GDispatcher:SetSquadronBaiPatrol( "Mineralnye", PatrolZoneEast, 4000, 10000, 500, 600, 800, 900 )
|
||||
--
|
||||
function AI_A2G_DISPATCHER:SetSquadronBaiPatrol( SquadronName, Zone, FloorAltitude, CeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, AltType )
|
||||
|
||||
local DefenderSquadron = self:GetSquadron( SquadronName )
|
||||
|
||||
DefenderSquadron.BAI = DefenderSquadron.BAI or {}
|
||||
|
||||
local BaiPatrol = DefenderSquadron.BAI
|
||||
BaiPatrol.Name = SquadronName
|
||||
BaiPatrol.Zone = Zone
|
||||
BaiPatrol.FloorAltitude = FloorAltitude
|
||||
BaiPatrol.CeilingAltitude = CeilingAltitude
|
||||
BaiPatrol.PatrolMinSpeed = PatrolMinSpeed
|
||||
BaiPatrol.PatrolMaxSpeed = PatrolMaxSpeed
|
||||
BaiPatrol.EngageMinSpeed = EngageMinSpeed
|
||||
BaiPatrol.EngageMaxSpeed = EngageMaxSpeed
|
||||
BaiPatrol.AltType = AltType
|
||||
BaiPatrol.Patrol = true
|
||||
|
||||
self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "BAI" )
|
||||
|
||||
self:F( { Bai = BaiPatrol } )
|
||||
end
|
||||
|
||||
|
||||
--- Defines the default amount of extra planes that will take-off as part of the defense system.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
@ -1399,7 +1460,7 @@ do -- AI_A2G_DISPATCHER
|
||||
--- Sets the default grouping of new airplanes spawned.
|
||||
-- Grouping will trigger how new airplanes will be grouped if more than one airplane is spawned for defense.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #number Grouping The level of grouping that will be applied of the CAP or GCI defenders.
|
||||
-- @param #number Grouping The level of grouping that will be applied of the Patrol or GCI defenders.
|
||||
-- @usage:
|
||||
--
|
||||
-- local A2GDispatcher = AI_A2G_DISPATCHER:New( ... )
|
||||
@ -1421,7 +1482,7 @@ do -- AI_A2G_DISPATCHER
|
||||
-- Grouping will trigger how new airplanes will be grouped if more than one airplane is spawned for defense.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The name of the squadron.
|
||||
-- @param #number Grouping The level of grouping that will be applied of the CAP or GCI defenders.
|
||||
-- @param #number Grouping The level of grouping that will be applied of the Patrol or GCI defenders.
|
||||
-- @usage:
|
||||
--
|
||||
-- local A2GDispatcher = AI_A2G_DISPATCHER:New( ... )
|
||||
@ -2064,48 +2125,23 @@ do -- AI_A2G_DISPATCHER
|
||||
end
|
||||
|
||||
|
||||
--- Creates an SWEEP task when there are targets for it.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
|
||||
-- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units.
|
||||
-- @return #nil If there are no targets to be set.
|
||||
function AI_A2G_DISPATCHER:EvaluateSWEEP( DetectedItem )
|
||||
self:F( { DetectedItem.ItemID } )
|
||||
|
||||
local DetectedSet = DetectedItem.Set
|
||||
local DetectedZone = DetectedItem.Zone
|
||||
|
||||
|
||||
if DetectedItem.IsDetected == false then
|
||||
|
||||
-- Here we're doing something advanced... We're copying the DetectedSet.
|
||||
local TargetSetUnit = SET_UNIT:New()
|
||||
TargetSetUnit:SetDatabase( DetectedSet )
|
||||
TargetSetUnit:FilterOnce() -- Filter but don't do any events!!! Elements are added manually upon each detection.
|
||||
|
||||
return TargetSetUnit
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
---
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_DISPATCHER:CountCapAirborne( SquadronName )
|
||||
function AI_A2G_DISPATCHER:CountPatrolAirborne( SquadronName, DefenseTaskType )
|
||||
|
||||
local CapCount = 0
|
||||
local PatrolCount = 0
|
||||
|
||||
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
|
||||
if DefenderSquadron then
|
||||
for AIGroup, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
||||
if DefenderTask.SquadronName == SquadronName then
|
||||
if DefenderTask.Type == "CAP" then
|
||||
if DefenderTask.Type == DefenseTaskType then
|
||||
if AIGroup:IsAlive() then
|
||||
-- Check if the CAP is patrolling or engaging. If not, this is not a valid CAP, even if it is alive!
|
||||
-- The CAP could be damaged, lost control, or out of fuel!
|
||||
-- Check if the Patrol is patrolling or engaging. If not, this is not a valid Patrol, even if it is alive!
|
||||
-- The Patrol could be damaged, lost control, or out of fuel!
|
||||
if DefenderTask.Fsm:Is( "Patrolling" ) or DefenderTask.Fsm:Is( "Engaging" ) or DefenderTask.Fsm:Is( "Refuelling" )
|
||||
or DefenderTask.Fsm:Is( "Started" ) then
|
||||
CapCount = CapCount + 1
|
||||
PatrolCount = PatrolCount + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -2113,7 +2149,7 @@ do -- AI_A2G_DISPATCHER
|
||||
end
|
||||
end
|
||||
|
||||
return CapCount
|
||||
return PatrolCount
|
||||
end
|
||||
|
||||
|
||||
@ -2173,7 +2209,7 @@ do -- AI_A2G_DISPATCHER
|
||||
local DefenderTask = self:GetDefenderTask( FriendlyGroup )
|
||||
if DefenderTask then
|
||||
-- The Task should be SEAD
|
||||
if DefenderTask.Type == "SEAD" or DefenderTask.Type == "CAS" or DefenderTask.Type == "BAI" then
|
||||
if true then -- TODO: fix this to the correct DefenderTaskType
|
||||
-- If there is no target, then add the AIGroup to the ResultAIGroups for Engagement to the AttackerSet
|
||||
if DefenderTask.Target == nil then
|
||||
if DefenderTask.Fsm:Is( "Returning" )
|
||||
@ -2196,50 +2232,6 @@ do -- AI_A2G_DISPATCHER
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_DISPATCHER:CountDefendersToBeEngaged( AttackerDetection, DefenderCount )
|
||||
|
||||
local Friendlies = nil
|
||||
|
||||
local AttackerSet = AttackerDetection.Set
|
||||
local AttackerCount = AttackerSet:Count()
|
||||
|
||||
local DefenderFriendlies = self:GetAIFriendliesNearBy( AttackerDetection )
|
||||
|
||||
for FriendlyDistance, AIFriendly in UTILS.spairs( DefenderFriendlies or {} ) do
|
||||
-- We only allow to ENGAGE targets as long as the Units on both sides are balanced.
|
||||
if AttackerCount > DefenderCount then
|
||||
local Friendly = AIFriendly:GetGroup() -- Wrapper.Group#GROUP
|
||||
if Friendly and Friendly:IsAlive() then
|
||||
-- Ok, so we have a friendly near the potential target.
|
||||
-- Now we need to check if the AIGroup has a Task.
|
||||
local DefenderTask = self:GetDefenderTask( Friendly )
|
||||
if DefenderTask then
|
||||
-- The Task should be CAP or GCI
|
||||
if DefenderTask.Type == "CAP" or DefenderTask.Type == "GCI" then
|
||||
-- If there is no target, then add the AIGroup to the ResultAIGroups for Engagement to the AttackerSet
|
||||
if DefenderTask.Target == nil then
|
||||
if DefenderTask.Fsm:Is( "Returning" )
|
||||
or DefenderTask.Fsm:Is( "Patrolling" ) then
|
||||
Friendlies = Friendlies or {}
|
||||
Friendlies[Friendly] = Friendly
|
||||
DefenderCount = DefenderCount + Friendly:GetSize()
|
||||
self:F( { Friendly = Friendly:GetName(), FriendlyDistance = FriendlyDistance } )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return Friendlies
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_DISPATCHER:ResourceActivate( DefenderSquadron, DefendersNeeded )
|
||||
@ -2251,7 +2243,7 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
if self:IsSquadronVisible( SquadronName ) then
|
||||
|
||||
-- Here we CAP the new planes.
|
||||
-- Here we Patrol the new planes.
|
||||
-- The Resources table is filled in advance.
|
||||
local TemplateID = math.random( 1, #DefenderSquadron.Spawn ) -- Choose the template.
|
||||
|
||||
@ -2261,20 +2253,20 @@ do -- AI_A2G_DISPATCHER
|
||||
-- New we will form the group to spawn in.
|
||||
-- We search for the first free resource matching the template.
|
||||
local DefenderUnitIndex = 1
|
||||
local DefenderCAPTemplate = nil
|
||||
local DefenderPatrolTemplate = nil
|
||||
local DefenderName = nil
|
||||
for GroupName, DefenderGroup in pairs( DefenderSquadron.Resources[TemplateID] or {} ) do
|
||||
self:F( { GroupName = GroupName } )
|
||||
local DefenderTemplate = _DATABASE:GetGroupTemplate( GroupName )
|
||||
if DefenderUnitIndex == 1 then
|
||||
DefenderCAPTemplate = UTILS.DeepCopy( DefenderTemplate )
|
||||
self.DefenderCAPIndex = self.DefenderCAPIndex + 1
|
||||
DefenderCAPTemplate.name = SquadronName .. "#" .. self.DefenderCAPIndex .. "#" .. GroupName
|
||||
DefenderName = DefenderCAPTemplate.name
|
||||
DefenderPatrolTemplate = UTILS.DeepCopy( DefenderTemplate )
|
||||
self.DefenderPatrolIndex = self.DefenderPatrolIndex + 1
|
||||
DefenderPatrolTemplate.name = SquadronName .. "#" .. self.DefenderPatrolIndex .. "#" .. GroupName
|
||||
DefenderName = DefenderPatrolTemplate.name
|
||||
else
|
||||
-- Add the unit in the template to the DefenderCAPTemplate.
|
||||
-- Add the unit in the template to the DefenderPatrolTemplate.
|
||||
local DefenderUnitTemplate = DefenderTemplate.units[1]
|
||||
DefenderCAPTemplate.units[DefenderUnitIndex] = DefenderUnitTemplate
|
||||
DefenderPatrolTemplate.units[DefenderUnitIndex] = DefenderUnitTemplate
|
||||
end
|
||||
DefenderUnitIndex = DefenderUnitIndex + 1
|
||||
DefenderSquadron.Resources[TemplateID][GroupName] = nil
|
||||
@ -2284,15 +2276,15 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
end
|
||||
|
||||
if DefenderCAPTemplate then
|
||||
if DefenderPatrolTemplate then
|
||||
local TakeoffMethod = self:GetSquadronTakeoff( SquadronName )
|
||||
local SpawnGroup = GROUP:Register( DefenderName )
|
||||
DefenderCAPTemplate.lateActivation = nil
|
||||
DefenderCAPTemplate.uncontrolled = nil
|
||||
DefenderPatrolTemplate.lateActivation = nil
|
||||
DefenderPatrolTemplate.uncontrolled = nil
|
||||
local Takeoff = self:GetSquadronTakeoff( SquadronName )
|
||||
DefenderCAPTemplate.route.points[1].type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
|
||||
DefenderCAPTemplate.route.points[1].action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
|
||||
local Defender = _DATABASE:Spawn( DefenderCAPTemplate )
|
||||
DefenderPatrolTemplate.route.points[1].type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
|
||||
DefenderPatrolTemplate.route.points[1].action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
|
||||
local Defender = _DATABASE:Spawn( DefenderPatrolTemplate )
|
||||
|
||||
self:AddDefenderToSquadron( DefenderSquadron, Defender, DefenderGrouping )
|
||||
return Defender, DefenderGrouping
|
||||
@ -2316,72 +2308,65 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
---
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_DISPATCHER:onafterCAP( From, Event, To, SquadronName )
|
||||
function AI_A2G_DISPATCHER:onafterPatrol( From, Event, To, SquadronName, DefenseTaskType )
|
||||
|
||||
self:F({SquadronName = SquadronName})
|
||||
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
|
||||
self.DefenderSquadrons[SquadronName].Cap = self.DefenderSquadrons[SquadronName].Cap or {}
|
||||
|
||||
local DefenderSquadron = self:CanCAP( SquadronName )
|
||||
local DefenderSquadron, Patrol = self:CanPatrol( SquadronName, DefenseTaskType )
|
||||
|
||||
if DefenderSquadron then
|
||||
|
||||
local Cap = DefenderSquadron.Cap
|
||||
|
||||
if Cap then
|
||||
if Patrol then
|
||||
|
||||
local DefenderCAP, DefenderGrouping = self:ResourceActivate( DefenderSquadron )
|
||||
|
||||
if DefenderCAP then
|
||||
|
||||
local Fsm = AI_A2G_CAP:New( DefenderCAP, Cap.Zone, Cap.FloorAltitude, Cap.CeilingAltitude, Cap.PatrolMinSpeed, Cap.PatrolMaxSpeed, Cap.EngageMinSpeed, Cap.EngageMaxSpeed, Cap.AltType )
|
||||
Fsm:SetDispatcher( self )
|
||||
Fsm:SetHomeAirbase( DefenderSquadron.Airbase )
|
||||
Fsm:SetFuelThreshold( DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold, 60 )
|
||||
Fsm:SetDamageThreshold( self.DefenderDefault.DamageThreshold )
|
||||
Fsm:SetDisengageRadius( self.DisengageRadius )
|
||||
Fsm:SetTanker( DefenderSquadron.TankerName or self.DefenderDefault.TankerName )
|
||||
Fsm:Start()
|
||||
|
||||
self:SetDefenderTask( SquadronName, DefenderCAP, "CAP", Fsm )
|
||||
local DefenderPatrol, DefenderGrouping = self:ResourceActivate( DefenderSquadron )
|
||||
|
||||
if DefenderPatrol then
|
||||
|
||||
function Fsm:onafterTakeoff( Defender, From, Event, To )
|
||||
self:F({"CAP Birth", Defender:GetName()})
|
||||
--self:GetParent(self).onafterBirth( self, Defender, From, Event, To )
|
||||
|
||||
local Dispatcher = Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||
local Squadron = Dispatcher:GetSquadronFromDefender( Defender )
|
||||
local Fsm = AI_A2G_PATROL:New( DefenderPatrol, Patrol.Zone, Patrol.FloorAltitude, Patrol.CeilingAltitude, Patrol.PatrolMinSpeed, Patrol.PatrolMaxSpeed, Patrol.EngageMinSpeed, Patrol.EngageMaxSpeed, Patrol.AltType )
|
||||
Fsm:SetDispatcher( self )
|
||||
Fsm:SetHomeAirbase( DefenderSquadron.Airbase )
|
||||
Fsm:SetFuelThreshold( DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold, 60 )
|
||||
Fsm:SetDamageThreshold( self.DefenderDefault.DamageThreshold )
|
||||
Fsm:SetDisengageRadius( self.DisengageRadius )
|
||||
Fsm:SetTanker( DefenderSquadron.TankerName or self.DefenderDefault.TankerName )
|
||||
Fsm:Start()
|
||||
|
||||
if Squadron then
|
||||
Fsm:__Patrol( 2 ) -- Start Patrolling
|
||||
end
|
||||
self:SetDefenderTask( SquadronName, DefenderPatrol, DefenseTaskType, Fsm )
|
||||
|
||||
function Fsm:onafterTakeoff( Defender, From, Event, To )
|
||||
self:F({"Patrol Birth", Defender:GetName()})
|
||||
--self:GetParent(self).onafterBirth( self, Defender, From, Event, To )
|
||||
|
||||
local Dispatcher = Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||
local Squadron = Dispatcher:GetSquadronFromDefender( Defender )
|
||||
|
||||
if Squadron then
|
||||
Fsm:__Patrol( 2 ) -- Start Patrolling
|
||||
end
|
||||
|
||||
function Fsm:onafterRTB( Defender, From, Event, To )
|
||||
self:F({"CAP RTB", Defender:GetName()})
|
||||
self:GetParent(self).onafterRTB( self, Defender, From, Event, To )
|
||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||
Dispatcher:ClearDefenderTaskTarget( Defender )
|
||||
end
|
||||
|
||||
function Fsm:onafterRTB( Defender, From, Event, To )
|
||||
self:F({"Patrol RTB", Defender:GetName()})
|
||||
self:GetParent(self).onafterRTB( self, Defender, From, Event, To )
|
||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||
Dispatcher:ClearDefenderTaskTarget( Defender )
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
function Fsm:onafterHome( Defender, From, Event, To, Action )
|
||||
self:F({"Patrol Home", Defender:GetName()})
|
||||
self:GetParent(self).onafterHome( self, Defender, From, Event, To )
|
||||
|
||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||
local Squadron = Dispatcher:GetSquadronFromDefender( Defender )
|
||||
|
||||
if Action and Action == "Destroy" then
|
||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||
Defender:Destroy()
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
function Fsm:onafterHome( Defender, From, Event, To, Action )
|
||||
self:F({"CAP Home", Defender:GetName()})
|
||||
self:GetParent(self).onafterHome( self, Defender, From, Event, To )
|
||||
|
||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||
local Squadron = Dispatcher:GetSquadronFromDefender( Defender )
|
||||
|
||||
if Action and Action == "Destroy" then
|
||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||
Defender:Destroy()
|
||||
end
|
||||
|
||||
if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2G_DISPATCHER.Landing.NearAirbase then
|
||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||
Defender:Destroy()
|
||||
self:ParkDefender( Squadron, Defender )
|
||||
end
|
||||
|
||||
if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2G_DISPATCHER.Landing.NearAirbase then
|
||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||
Defender:Destroy()
|
||||
self:ParkDefender( Squadron, Defender )
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -2392,7 +2377,7 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
---
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_DISPATCHER:onafterENGAGE( From, Event, To, AttackerDetection, Defenders )
|
||||
function AI_A2G_DISPATCHER:onafterEngage( From, Event, To, AttackerDetection, Defenders )
|
||||
|
||||
if Defenders then
|
||||
|
||||
@ -2409,7 +2394,7 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
---
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_DISPATCHER:onafterDEFEND( From, Event, To, AttackerDetection, DefendersMissing, DefenderFriendlies, DefenseTaskType )
|
||||
function AI_A2G_DISPATCHER:onafterDefend( From, Event, To, AttackerDetection, DefendersMissing, DefenderFriendlies, DefenseTaskType )
|
||||
|
||||
self:F( { From, Event, To, AttackerDetection.Index, DefendersMissing, DefenderFriendlies } )
|
||||
|
||||
@ -2469,7 +2454,7 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
if ClosestDefenderSquadronName then
|
||||
|
||||
local DefenderSquadron, Defense = self:CanDEFEND( ClosestDefenderSquadronName, DefenseTaskType )
|
||||
local DefenderSquadron, Defense = self:CanDefend( ClosestDefenderSquadronName, DefenseTaskType )
|
||||
|
||||
if Defense then
|
||||
|
||||
@ -2757,7 +2742,7 @@ do -- AI_A2G_DISPATCHER
|
||||
local DistanceProbability = ( self.DefenseDistance / EvaluateDistance * self.DefenseReactivity )
|
||||
local DefenseProbability = math.random()
|
||||
|
||||
self:F({DistanceProbability=DistanceProbability,DefenseProbability=DefenseProbability})
|
||||
self:F( { DistanceProbability = DistanceProbability, DefenseProbability = DefenseProbability } )
|
||||
|
||||
if DefenseProbability <= DistanceProbability / ( 300 / 30 ) then
|
||||
DefenseCoordinate = EvaluateCoordinate
|
||||
@ -2770,7 +2755,7 @@ do -- AI_A2G_DISPATCHER
|
||||
local DefendersMissing, Friendlies = self:Evaluate_SEAD( DetectedItem ) -- Returns a SET_UNIT with the SEAD targets to be engaged...
|
||||
if DefendersMissing and DefendersMissing > 0 then
|
||||
self:F( { SeadGroups = Friendlies } )
|
||||
self:__DEFEND( Delay, DetectedItem, DefendersMissing, Friendlies, "SEAD", DefenseCoordinate )
|
||||
self:__Defend( Delay, DetectedItem, DefendersMissing, Friendlies, "SEAD", DefenseCoordinate )
|
||||
Delay = Delay + 1
|
||||
end
|
||||
end
|
||||
@ -2779,7 +2764,7 @@ do -- AI_A2G_DISPATCHER
|
||||
local DefendersMissing, Friendlies = self:Evaluate_CAS( DetectedItem ) -- Returns a SET_UNIT with the CAS targets to be engaged...
|
||||
if DefendersMissing and DefendersMissing > 0 then
|
||||
self:F( { CasGroups = Friendlies } )
|
||||
self:__DEFEND( Delay, DetectedItem, DefendersMissing, Friendlies, "CAS", DefenseCoordinate )
|
||||
self:__Defend( Delay, DetectedItem, DefendersMissing, Friendlies, "CAS", DefenseCoordinate )
|
||||
Delay = Delay + 1
|
||||
end
|
||||
end
|
||||
@ -2788,7 +2773,7 @@ do -- AI_A2G_DISPATCHER
|
||||
local DefendersMissing, Friendlies = self:Evaluate_BAI( DetectedItem ) -- Returns a SET_UNIT with the CAS targets to be engaged...
|
||||
if DefendersMissing and DefendersMissing > 0 then
|
||||
self:F( { BaiGroups = Friendlies } )
|
||||
self:__DEFEND( Delay, DetectedItem, DefendersMissing, Friendlies, "BAI", DefenseCoordinate )
|
||||
self:__Defend( Delay, DetectedItem, DefendersMissing, Friendlies, "BAI", DefenseCoordinate )
|
||||
Delay = Delay + 1
|
||||
end
|
||||
end
|
||||
@ -2952,11 +2937,13 @@ do
|
||||
return FriendliesCount, FriendlyTypesReport
|
||||
end
|
||||
|
||||
--- Schedules a new CAP for the given SquadronName.
|
||||
--- Schedules a new Patrol for the given SquadronName.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
function AI_A2G_DISPATCHER:SchedulerCAP( SquadronName )
|
||||
self:CAP( SquadronName )
|
||||
function AI_A2G_DISPATCHER:SchedulerPatrol( SquadronName )
|
||||
local PatrolTaskTypes = { "SEAD", "CAS", "BAI" }
|
||||
local PatrolTaskType = PatrolTaskTypes[math.random(1,3)]
|
||||
self:Patrol( SquadronName, PatrolTaskType )
|
||||
end
|
||||
|
||||
end
|
||||
@ -3122,7 +3109,7 @@ do
|
||||
--
|
||||
-- You can change or add a CAP zone by using the inherited methods from AI\_A2G\_DISPATCHER:
|
||||
--
|
||||
-- The method @{#AI_A2G_DISPATCHER.SetSquadronCap}() defines a CAP execution for a squadron.
|
||||
-- The method @{#AI_A2G_DISPATCHER.SetSquadronPatrol}() defines a CAP execution for a squadron.
|
||||
--
|
||||
-- Setting-up a CAP zone also requires specific parameters:
|
||||
--
|
||||
@ -3133,14 +3120,14 @@ do
|
||||
--
|
||||
-- These define how the squadron will perform the CAP while partrolling. Different terrain types requires different types of CAP.
|
||||
--
|
||||
-- The @{#AI_A2G_DISPATCHER.SetSquadronCapInterval}() method specifies **how much** and **when** CAP flights will takeoff.
|
||||
-- The @{#AI_A2G_DISPATCHER.SetSquadronPatrolInterval}() method specifies **how much** and **when** CAP flights will takeoff.
|
||||
--
|
||||
-- It is recommended not to overload the air defense with CAP flights, as these will decrease the performance of the overall system.
|
||||
--
|
||||
-- For example, the following setup will create a CAP for squadron "Sochi":
|
||||
--
|
||||
-- A2GDispatcher:SetSquadronCap( "Sochi", CAPZoneWest, 4000, 8000, 600, 800, 800, 1200, "BARO" )
|
||||
-- A2GDispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 )
|
||||
-- A2GDispatcher:SetSquadronPatrol( "Sochi", CAPZoneWest, 4000, 8000, 600, 800, 800, 1200, "BARO" )
|
||||
-- A2GDispatcher:SetSquadronPatrolInterval( "Sochi", 2, 30, 120, 1 )
|
||||
--
|
||||
-- ### 2.4) Each airbase will perform GCI when required, with the following parameters:
|
||||
--
|
||||
@ -3227,8 +3214,8 @@ do
|
||||
-- @param #AI_A2G_GCICAP self
|
||||
-- @param #string EWRPrefixes A list of prefixes that of groups that setup the Early Warning Radar network.
|
||||
-- @param #string TemplatePrefixes A list of template prefixes.
|
||||
-- @param #string CapPrefixes A list of CAP zone prefixes (polygon zones).
|
||||
-- @param #number CapLimit A number of how many CAP maximum will be spawned.
|
||||
-- @param #string PatrolPrefixes A list of CAP zone prefixes (polygon zones).
|
||||
-- @param #number PatrolLimit A number of how many CAP maximum will be spawned.
|
||||
-- @param #number GroupingRadius The radius in meters wherein detected planes are being grouped as one target area.
|
||||
-- For airplanes, 6000 (6km) is recommended, and is also the default value of this parameter.
|
||||
-- @param #number EngageRadius The radius in meters wherein detected airplanes will be engaged by airborne defenders without a task.
|
||||
@ -3308,7 +3295,7 @@ do
|
||||
--
|
||||
-- A2GDispatcher = AI_A2G_GCICAP:New( { "DF CCCP" }, { "SQ CCCP" }, nil, nil, nil, nil, nil, 30 )
|
||||
--
|
||||
function AI_A2G_GCICAP:New( EWRPrefixes, TemplatePrefixes, CapPrefixes, CapLimit, GroupingRadius, EngageRadius, GciRadius, ResourceCount )
|
||||
function AI_A2G_GCICAP:New( EWRPrefixes, TemplatePrefixes, PatrolPrefixes, PatrolLimit, GroupingRadius, EngageRadius, GciRadius, ResourceCount )
|
||||
|
||||
local EWRSetGroup = SET_GROUP:New()
|
||||
EWRSetGroup:FilterPrefixes( EWRPrefixes )
|
||||
@ -3370,7 +3357,7 @@ do
|
||||
-- CAP will be launched from there.
|
||||
|
||||
self.CAPTemplates = SET_GROUP:New()
|
||||
self.CAPTemplates:FilterPrefixes( CapPrefixes )
|
||||
self.CAPTemplates:FilterPrefixes( PatrolPrefixes )
|
||||
self.CAPTemplates:FilterOnce()
|
||||
|
||||
self:I( "Setting up CAP ..." )
|
||||
@ -3396,8 +3383,8 @@ do
|
||||
end
|
||||
if AirbaseClosest then
|
||||
self:I( { CAPAirbase = AirbaseClosest:GetName() } )
|
||||
self:SetSquadronCap( AirbaseClosest:GetName(), CAPZone, 6000, 10000, 500, 800, 800, 1200, "RADIO" )
|
||||
self:SetSquadronCapInterval( AirbaseClosest:GetName(), CapLimit, 300, 600, 1 )
|
||||
self:SetSquadronPatrol( AirbaseClosest:GetName(), CAPZone, 6000, 10000, 500, 800, 800, 1200, "RADIO" )
|
||||
self:SetSquadronPatrolInterval( AirbaseClosest:GetName(), PatrolLimit, 300, 600, 1 )
|
||||
end
|
||||
end
|
||||
|
||||
@ -3432,8 +3419,8 @@ do
|
||||
-- @param #string EWRPrefixes A list of prefixes that of groups that setup the Early Warning Radar network.
|
||||
-- @param #string TemplatePrefixes A list of template prefixes.
|
||||
-- @param #string BorderPrefix A Border Zone Prefix.
|
||||
-- @param #string CapPrefixes A list of CAP zone prefixes (polygon zones).
|
||||
-- @param #number CapLimit A number of how many CAP maximum will be spawned.
|
||||
-- @param #string PatrolPrefixes A list of CAP zone prefixes (polygon zones).
|
||||
-- @param #number PatrolLimit A number of how many CAP maximum will be spawned.
|
||||
-- @param #number GroupingRadius The radius in meters wherein detected planes are being grouped as one target area.
|
||||
-- For airplanes, 6000 (6km) is recommended, and is also the default value of this parameter.
|
||||
-- @param #number EngageRadius The radius in meters wherein detected airplanes will be engaged by airborne defenders without a task.
|
||||
@ -3522,9 +3509,9 @@ do
|
||||
--
|
||||
-- A2GDispatcher = AI_A2G_GCICAP:NewWithBorder( { "DF CCCP" }, { "SQ CCCP" }, "Border", nil, nil, nil, nil, nil, 30 )
|
||||
--
|
||||
function AI_A2G_GCICAP:NewWithBorder( EWRPrefixes, TemplatePrefixes, BorderPrefix, CapPrefixes, CapLimit, GroupingRadius, EngageRadius, GciRadius, ResourceCount )
|
||||
function AI_A2G_GCICAP:NewWithBorder( EWRPrefixes, TemplatePrefixes, BorderPrefix, PatrolPrefixes, PatrolLimit, GroupingRadius, EngageRadius, GciRadius, ResourceCount )
|
||||
|
||||
local self = AI_A2G_GCICAP:New( EWRPrefixes, TemplatePrefixes, CapPrefixes, CapLimit, GroupingRadius, EngageRadius, GciRadius, ResourceCount )
|
||||
local self = AI_A2G_GCICAP:New( EWRPrefixes, TemplatePrefixes, PatrolPrefixes, PatrolLimit, GroupingRadius, EngageRadius, GciRadius, ResourceCount )
|
||||
|
||||
if BorderPrefix then
|
||||
self:SetBorderZone( ZONE_POLYGON:New( BorderPrefix, GROUP:FindByName( BorderPrefix ) ) )
|
||||
|
||||
488
Moose Development/Moose/AI/AI_A2G_Patrol.lua
Normal file
488
Moose Development/Moose/AI/AI_A2G_Patrol.lua
Normal file
@ -0,0 +1,488 @@
|
||||
--- **AI** -- Models the process of A2G patrolling and engaging ground targets for airplanes and helicopters.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module AI.AI_A2G_Patrol
|
||||
-- @image AI_Combat_Air_Patrol.JPG
|
||||
|
||||
--- @type AI_A2G_PATROL
|
||||
-- @extends AI.AI_A2A_Patrol#AI_A2A_PATROL
|
||||
|
||||
|
||||
--- The AI_A2G_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}
|
||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_A2G_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_A2G_PATROL process can be started using the **Start** event.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||
-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- This cycle will continue.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- When enemies are detected, the AI will automatically engage the enemy.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## 1. AI_A2G_PATROL constructor
|
||||
--
|
||||
-- * @{#AI_A2G_PATROL.New}(): Creates a new AI_A2G_PATROL object.
|
||||
--
|
||||
-- ## 2. AI_A2G_PATROL is a FSM
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ### 2.1 AI_A2G_PATROL States
|
||||
--
|
||||
-- * **None** ( Group ): The process is not started yet.
|
||||
-- * **Patrolling** ( Group ): The AI is patrolling the Patrol Zone.
|
||||
-- * **Engaging** ( Group ): The AI is engaging the bogeys.
|
||||
-- * **Returning** ( Group ): The AI is returning to Base..
|
||||
--
|
||||
-- ### 2.2 AI_A2G_PATROL Events
|
||||
--
|
||||
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
|
||||
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
|
||||
-- * **@{#AI_A2G_PATROL.Engage}**: Let the AI engage the bogeys.
|
||||
-- * **@{#AI_A2G_PATROL.Abort}**: Aborts the engagement and return patrolling in the patrol zone.
|
||||
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
|
||||
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
|
||||
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
||||
-- * **@{#AI_A2G_PATROL.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
|
||||
-- * **@{#AI_A2G_PATROL.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
|
||||
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
||||
--
|
||||
-- ## 3. Set the Range of Engagement
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional range can be set in meters,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
||||
-- The range is applied at the position of the AI.
|
||||
-- Use the method @{AI.AI_CAP#AI_A2G_PATROL.SetEngageRange}() to define that range.
|
||||
--
|
||||
-- ## 4. Set the Zone of Engagement
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional @{Zone} can be set,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- Use the method @{AI.AI_Cap#AI_A2G_PATROL.SetEngageZone}() to define that Zone.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_A2G_PATROL
|
||||
AI_A2G_PATROL = {
|
||||
ClassName = "AI_A2G_PATROL",
|
||||
}
|
||||
|
||||
--- Creates a new AI_A2G_PATROL object
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
|
||||
-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
||||
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
||||
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
||||
-- @return #AI_A2G_PATROL
|
||||
function AI_A2G_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, AI_A2A_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_A2G_PATROL
|
||||
|
||||
self.Accomplished = false
|
||||
self.Engaging = false
|
||||
|
||||
self.EngageMinSpeed = EngageMinSpeed
|
||||
self.EngageMaxSpeed = EngageMaxSpeed
|
||||
|
||||
self:AddTransition( { "Patrolling", "Engaging", "Returning", "Airborne" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2G_PATROL.
|
||||
|
||||
--- OnBefore Transition Handler for Event Engage.
|
||||
-- @function [parent=#AI_A2G_PATROL] OnBeforeEngage
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #boolean Return false to cancel Transition.
|
||||
|
||||
--- OnAfter Transition Handler for Event Engage.
|
||||
-- @function [parent=#AI_A2G_PATROL] OnAfterEngage
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
--- Synchronous Event Trigger for Event Engage.
|
||||
-- @function [parent=#AI_A2G_PATROL] Engage
|
||||
-- @param #AI_A2G_PATROL self
|
||||
|
||||
--- Asynchronous Event Trigger for Event Engage.
|
||||
-- @function [parent=#AI_A2G_PATROL] __Engage
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param #number Delay The delay in seconds.
|
||||
|
||||
--- OnLeave Transition Handler for State Engaging.
|
||||
-- @function [parent=#AI_A2G_PATROL] OnLeaveEngaging
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #boolean Return false to cancel Transition.
|
||||
|
||||
--- OnEnter Transition Handler for State Engaging.
|
||||
-- @function [parent=#AI_A2G_PATROL] OnEnterEngaging
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2G_PATROL.
|
||||
|
||||
--- OnBefore Transition Handler for Event Fired.
|
||||
-- @function [parent=#AI_A2G_PATROL] OnBeforeFired
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #boolean Return false to cancel Transition.
|
||||
|
||||
--- OnAfter Transition Handler for Event Fired.
|
||||
-- @function [parent=#AI_A2G_PATROL] OnAfterFired
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
--- Synchronous Event Trigger for Event Fired.
|
||||
-- @function [parent=#AI_A2G_PATROL] Fired
|
||||
-- @param #AI_A2G_PATROL self
|
||||
|
||||
--- Asynchronous Event Trigger for Event Fired.
|
||||
-- @function [parent=#AI_A2G_PATROL] __Fired
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param #number Delay The delay in seconds.
|
||||
|
||||
self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_A2G_PATROL.
|
||||
|
||||
--- OnBefore Transition Handler for Event Destroy.
|
||||
-- @function [parent=#AI_A2G_PATROL] OnBeforeDestroy
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #boolean Return false to cancel Transition.
|
||||
|
||||
--- OnAfter Transition Handler for Event Destroy.
|
||||
-- @function [parent=#AI_A2G_PATROL] OnAfterDestroy
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
--- Synchronous Event Trigger for Event Destroy.
|
||||
-- @function [parent=#AI_A2G_PATROL] Destroy
|
||||
-- @param #AI_A2G_PATROL self
|
||||
|
||||
--- Asynchronous Event Trigger for Event Destroy.
|
||||
-- @function [parent=#AI_A2G_PATROL] __Destroy
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param #number Delay The delay in seconds.
|
||||
|
||||
|
||||
self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2G_PATROL.
|
||||
|
||||
--- OnBefore Transition Handler for Event Abort.
|
||||
-- @function [parent=#AI_A2G_PATROL] OnBeforeAbort
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #boolean Return false to cancel Transition.
|
||||
|
||||
--- OnAfter Transition Handler for Event Abort.
|
||||
-- @function [parent=#AI_A2G_PATROL] OnAfterAbort
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
--- Synchronous Event Trigger for Event Abort.
|
||||
-- @function [parent=#AI_A2G_PATROL] Abort
|
||||
-- @param #AI_A2G_PATROL self
|
||||
|
||||
--- Asynchronous Event Trigger for Event Abort.
|
||||
-- @function [parent=#AI_A2G_PATROL] __Abort
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param #number Delay The delay in seconds.
|
||||
|
||||
self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2G_PATROL.
|
||||
|
||||
--- OnBefore Transition Handler for Event Accomplish.
|
||||
-- @function [parent=#AI_A2G_PATROL] OnBeforeAccomplish
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #boolean Return false to cancel Transition.
|
||||
|
||||
--- OnAfter Transition Handler for Event Accomplish.
|
||||
-- @function [parent=#AI_A2G_PATROL] OnAfterAccomplish
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
--- Synchronous Event Trigger for Event Accomplish.
|
||||
-- @function [parent=#AI_A2G_PATROL] Accomplish
|
||||
-- @param #AI_A2G_PATROL self
|
||||
|
||||
--- Asynchronous Event Trigger for Event Accomplish.
|
||||
-- @function [parent=#AI_A2G_PATROL] __Accomplish
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param #number Delay The delay in seconds.
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- onafter State Transition for Event Patrol.
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The AI Group managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
function AI_A2G_PATROL:onafterStart( AIPatrol, From, Event, To )
|
||||
|
||||
self:GetParent( self ).onafterStart( self, AIPatrol, From, Event, To )
|
||||
AIPatrol:HandleEvent( EVENTS.Takeoff, nil, self )
|
||||
|
||||
end
|
||||
|
||||
--- Set the Engage Zone which defines where the AI will engage bogies.
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Core.Zone#ZONE EngageZone The zone where the AI is performing CAP.
|
||||
-- @return #AI_A2G_PATROL self
|
||||
function AI_A2G_PATROL:SetEngageZone( EngageZone )
|
||||
self:F2()
|
||||
|
||||
if EngageZone then
|
||||
self.EngageZone = EngageZone
|
||||
else
|
||||
self.EngageZone = nil
|
||||
end
|
||||
end
|
||||
|
||||
--- Set the Engage Range when the AI will engage with airborne enemies.
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param #number EngageRange The Engage Range.
|
||||
-- @return #AI_A2G_PATROL self
|
||||
function AI_A2G_PATROL:SetEngageRange( EngageRange )
|
||||
self:F2()
|
||||
|
||||
if EngageRange then
|
||||
self.EngageRange = EngageRange
|
||||
else
|
||||
self.EngageRange = nil
|
||||
end
|
||||
end
|
||||
|
||||
--- onafter State Transition for Event Patrol.
|
||||
-- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The AI Group managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
function AI_A2G_PATROL:onafterPatrol( AIPatrol, From, Event, To )
|
||||
|
||||
-- Call the parent Start event handler
|
||||
self:GetParent(self).onafterPatrol( self, AIPatrol, From, Event, To )
|
||||
self:HandleEvent( EVENTS.Dead )
|
||||
|
||||
end
|
||||
|
||||
-- todo: need to fix this global function
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIPatrol
|
||||
function AI_A2G_PATROL.AttackRoute( AIPatrol, Fsm )
|
||||
|
||||
AIPatrol:F( { "AI_A2G_PATROL.AttackRoute:", AIPatrol:GetName() } )
|
||||
|
||||
if AIPatrol:IsAlive() then
|
||||
Fsm:__Engage( 0.5 )
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
function AI_A2G_PATROL:onbeforeEngage( AIPatrol, From, Event, To )
|
||||
|
||||
if self.Accomplished == true then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The AI Group managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
function AI_A2G_PATROL:onafterAbort( AIPatrol, From, Event, To )
|
||||
AIPatrol:ClearTasks()
|
||||
self:__Route( 0.5 )
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The AIPatrol Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
function AI_A2G_PATROL:onafterEngage( AIPatrol, From, Event, To, AttackSetUnit )
|
||||
|
||||
self:F( { AIPatrol, From, Event, To, AttackSetUnit} )
|
||||
|
||||
self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT
|
||||
|
||||
local FirstAttackUnit = self.AttackSetUnit:GetFirst() -- Wrapper.Unit#UNIT
|
||||
|
||||
if FirstAttackUnit and FirstAttackUnit:IsAlive() then -- If there is no attacker anymore, stop the engagement.
|
||||
|
||||
if AIPatrol:IsAlive() then
|
||||
|
||||
local EngageRoute = {}
|
||||
|
||||
--- Calculate the target route point.
|
||||
local CurrentCoord = AIPatrol:GetCoordinate()
|
||||
local ToTargetCoord = self.AttackSetUnit:GetFirst():GetCoordinate()
|
||||
local ToTargetSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed )
|
||||
local ToInterceptAngle = CurrentCoord:GetAngleDegrees( CurrentCoord:GetDirectionVec3( ToTargetCoord ) )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToPatrolRoutePoint = CurrentCoord:Translate( 5000, ToInterceptAngle ):WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
self:F( { Angle = ToInterceptAngle, ToTargetSpeed = ToTargetSpeed } )
|
||||
self:T2( { self.MinSpeed, self.MaxSpeed, ToTargetSpeed } )
|
||||
|
||||
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
|
||||
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
|
||||
|
||||
local AttackTasks = {}
|
||||
|
||||
for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do
|
||||
local AttackUnit = AttackUnit -- Wrapper.Unit#UNIT
|
||||
self:T( { "Attacking Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsAir() } )
|
||||
if AttackUnit:IsAlive() and AttackUnit:IsAir() then
|
||||
AttackTasks[#AttackTasks+1] = AIPatrol:TaskAttackUnit( AttackUnit )
|
||||
end
|
||||
end
|
||||
|
||||
if #AttackTasks == 0 then
|
||||
self:E("No targets found -> Going back to Patrolling")
|
||||
self:__Abort( 0.5 )
|
||||
else
|
||||
AIPatrol:OptionROEOpenFire()
|
||||
AIPatrol:OptionROTEvadeFire()
|
||||
|
||||
AttackTasks[#AttackTasks+1] = AIPatrol:TaskFunction( "AI_A2G_PATROL.AttackRoute", self )
|
||||
EngageRoute[#EngageRoute].task = AIPatrol:TaskCombo( AttackTasks )
|
||||
end
|
||||
|
||||
AIPatrol:Route( EngageRoute, 0.5 )
|
||||
end
|
||||
else
|
||||
self:E("No targets found -> Going back to Patrolling")
|
||||
self:__Abort( 0.5 )
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
function AI_A2G_PATROL:onafterAccomplish( AIPatrol, From, Event, To )
|
||||
self.Accomplished = true
|
||||
self:SetDetectionOff()
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_A2G_PATROL:onafterDestroy( AIPatrol, From, Event, To, EventData )
|
||||
|
||||
if EventData.IniUnit then
|
||||
self.AttackUnits[EventData.IniUnit] = nil
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_PATROL self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_A2G_PATROL:OnEventDead( EventData )
|
||||
self:F( { "EventDead", EventData } )
|
||||
|
||||
if EventData.IniDCSUnit then
|
||||
if self.AttackUnits and self.AttackUnits[EventData.IniUnit] then
|
||||
self:__Destroy( 1, EventData )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIPatrol
|
||||
function AI_A2G_PATROL.Resume( AIPatrol, Fsm )
|
||||
|
||||
AIPatrol:I( { "AI_A2G_PATROL.Resume:", AIPatrol:GetName() } )
|
||||
if AIPatrol:IsAlive() then
|
||||
Fsm:__Reset( 1 )
|
||||
Fsm:__Route( 5 )
|
||||
end
|
||||
|
||||
end
|
||||
@ -68,6 +68,7 @@ AI/AI_A2A_Gci.lua
|
||||
AI/AI_A2A_Dispatcher.lua
|
||||
AI/AI_A2G.lua
|
||||
AI/AI_A2G_Engage.lua
|
||||
AI/AI_A2G_Patrol.lua
|
||||
AI/AI_A2G_Dispatcher.lua
|
||||
AI/AI_Patrol.lua
|
||||
AI/AI_Cap.lua
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user