From 690805d7ca8c25ae35dffd52ae4addcde1d69d40 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 12 Oct 2018 07:14:05 +0200 Subject: [PATCH 1/6] Implemented workaround request to board and unboard cargo from buildings. Now "InAir" means a velocity < 1 m/s and a height < 30 m. Once DCS properly fixes the flag to land on buildings, this workaround can be removed. --- Moose Development/Moose/Core/Point.lua | 37 ++++++++++++++---------- Moose Development/Moose/Wrapper/Unit.lua | 12 ++++++-- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 1f58ea6d6..4b2c592a1 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -1767,7 +1767,8 @@ do -- COORDINATE --- Return a BR string from a COORDINATE to the COORDINATE. -- @param #COORDINATE self - -- @param #COORDINATE TargetCoordinate The target COORDINATE. + -- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from. + -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The BR text. function COORDINATE:ToStringBR( FromCoordinate, Settings ) local DirectionVec3 = FromCoordinate:GetDirectionVec3( self ) @@ -1778,7 +1779,8 @@ do -- COORDINATE --- Return a BRAA string from a COORDINATE to the COORDINATE. -- @param #COORDINATE self - -- @param #COORDINATE TargetCoordinate The target COORDINATE. + -- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from. + -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The BR text. function COORDINATE:ToStringBRA( FromCoordinate, Settings ) local DirectionVec3 = FromCoordinate:GetDirectionVec3( self ) @@ -1791,6 +1793,7 @@ do -- COORDINATE --- Return a BULLS string out of the BULLS of the coalition to the COORDINATE. -- @param #COORDINATE self -- @param DCS#coalition.side Coalition The coalition. + -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The BR text. function COORDINATE:ToStringBULLS( Coalition, Settings ) local BullsCoordinate = COORDINATE:NewFromVec3( coalition.getMainRefPoint( Coalition ) ) @@ -1830,7 +1833,7 @@ do -- COORDINATE --- Provides a Lat Lon string in Degree Minute Second format. -- @param #COORDINATE self - -- @param Core.Settings#SETTINGS Settings (optional) Settings + -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The LL DMS Text function COORDINATE:ToStringLLDMS( Settings ) @@ -1841,7 +1844,7 @@ do -- COORDINATE --- Provides a Lat Lon string in Degree Decimal Minute format. -- @param #COORDINATE self - -- @param Core.Settings#SETTINGS Settings (optional) Settings + -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The LL DDM Text function COORDINATE:ToStringLLDDM( Settings ) @@ -1852,7 +1855,7 @@ do -- COORDINATE --- Provides a MGRS string -- @param #COORDINATE self - -- @param Core.Settings#SETTINGS Settings (optional) Settings + -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The MGRS Text function COORDINATE:ToStringMGRS( Settings ) --R2.1 Fixes issue #424. @@ -1866,10 +1869,12 @@ do -- COORDINATE -- * Uses default settings in COORDINATE. -- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default. -- @param #COORDINATE self + -- @param #COORDINATE ReferenceCoord The refrence coordinate. + -- @param #string ReferenceName The refrence name. -- @param Wrapper.Controllable#CONTROLLABLE Controllable - -- @param Core.Settings#SETTINGS Settings + -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The coordinate Text in the configured coordinate system. - function COORDINATE:ToStringFromRP( ReferenceCoord, ReferenceName, Controllable, Settings ) -- R2.2 + function COORDINATE:ToStringFromRP( ReferenceCoord, ReferenceName, Controllable, Settings ) self:F2( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } ) @@ -1896,9 +1901,9 @@ do -- COORDINATE --- Provides a coordinate string of the point, based on the A2G coordinate format system. -- @param #COORDINATE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable - -- @param Core.Settings#SETTINGS Settings + -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The coordinate Text in the configured coordinate system. - function COORDINATE:ToStringA2G( Controllable, Settings ) -- R2.2 + function COORDINATE:ToStringA2G( Controllable, Settings ) self:F2( { Controllable = Controllable and Controllable:GetName() } ) @@ -1931,7 +1936,7 @@ do -- COORDINATE --- Provides a coordinate string of the point, based on the A2A coordinate format system. -- @param #COORDINATE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable - -- @param Core.Settings#SETTINGS Settings + -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The coordinate Text in the configured coordinate system. function COORDINATE:ToStringA2A( Controllable, Settings ) -- R2.2 @@ -1970,7 +1975,7 @@ do -- COORDINATE -- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default. -- @param #COORDINATE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable - -- @param Core.Settings#SETTINGS Settings + -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @param Tasking.Task#TASK Task The task for which coordinates need to be calculated. -- @return #string The coordinate Text in the configured coordinate system. function COORDINATE:ToString( Controllable, Settings, Task ) @@ -2023,7 +2028,7 @@ do -- COORDINATE -- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default. -- @param #COORDINATE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable - -- @param Core.Settings#SETTINGS Settings + -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The pressure text in the configured measurement system. function COORDINATE:ToStringPressure( Controllable, Settings ) -- R2.3 @@ -2039,9 +2044,9 @@ do -- COORDINATE -- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default. -- @param #COORDINATE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable - -- @param Core.Settings#SETTINGS Settings + -- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object. -- @return #string The wind text in the configured measurement system. - function COORDINATE:ToStringWind( Controllable, Settings ) -- R2.3 + function COORDINATE:ToStringWind( Controllable, Settings ) self:F2( { Controllable = Controllable and Controllable:GetName() } ) @@ -2055,9 +2060,9 @@ do -- COORDINATE -- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default. -- @param #COORDINATE self -- @param Wrapper.Controllable#CONTROLLABLE Controllable - -- @param Core.Settings#SETTINGS Settings + -- @param Core.Settings#SETTINGS -- @return #string The temperature text in the configured measurement system. - function COORDINATE:ToStringTemperature( Controllable, Settings ) -- R2.3 + function COORDINATE:ToStringTemperature( Controllable, Settings ) self:F2( { Controllable = Controllable and Controllable:GetName() } ) diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 71fd902a6..796238305 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -902,10 +902,18 @@ end function UNIT:InAir() self:F2( self.UnitName ) - local DCSUnit = self:GetDCSObject() + local DCSUnit = self:GetDCSObject() --DCS#Unit if DCSUnit then - local UnitInAir = DCSUnit:inAir() +-- Implementation of workaround. The original code is below. +-- This to simulate the landing on buildings. +-- local UnitInAir = DCSUnit:inAir() + local UnitInAir = false + local VelocityVec3 = DCSUnit:getVelocity() + local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec + if Velocity < 1 and DCSUnit:getPoint().y <= 30 then + UnitInAir = true + end self:T3( UnitInAir ) return UnitInAir end From da90826bd086b8eb2555456dcf455301698b2802 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 12 Oct 2018 20:15:10 +0200 Subject: [PATCH 2/6] Fix height problem in workaround solution. --- Moose Development/Moose/Wrapper/Unit.lua | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 796238305..a7e2a3fcd 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -896,7 +896,7 @@ function UNIT:IsShip() end --- Returns true if the UNIT is in the air. --- @param Wrapper.Positionable#UNIT self +-- @param #UNIT self -- @return #boolean true if in the air. -- @return #nil The UNIT is not existing or alive. function UNIT:InAir() @@ -908,11 +908,14 @@ function UNIT:InAir() -- Implementation of workaround. The original code is below. -- This to simulate the landing on buildings. -- local UnitInAir = DCSUnit:inAir() - local UnitInAir = false + local UnitInAir = true local VelocityVec3 = DCSUnit:getVelocity() local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec - if Velocity < 1 and DCSUnit:getPoint().y <= 30 then - UnitInAir = true + local Coordinate = DCSUnit:getPoint() + local LandHeight = land.getHeight( { x = Coordinate.x, y = Coordinate.z } ) + local Height = Coordinate.y - LandHeight + if Velocity < 1 and Height <= 30 then + UnitInAir = false end self:T3( UnitInAir ) return UnitInAir From 19e2af08e043fae5d0b858b05138ed4e919be76d Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 12 Oct 2018 21:10:58 +0200 Subject: [PATCH 3/6] increased the altitude of hover. --- Moose Development/Moose/Wrapper/Unit.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index a7e2a3fcd..5487ef3b6 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -907,6 +907,7 @@ function UNIT:InAir() if DCSUnit then -- Implementation of workaround. The original code is below. -- This to simulate the landing on buildings. + -- local UnitInAir = DCSUnit:inAir() local UnitInAir = true local VelocityVec3 = DCSUnit:getVelocity() @@ -914,7 +915,7 @@ function UNIT:InAir() local Coordinate = DCSUnit:getPoint() local LandHeight = land.getHeight( { x = Coordinate.x, y = Coordinate.z } ) local Height = Coordinate.y - LandHeight - if Velocity < 1 and Height <= 30 then + if Velocity < 1 and Height <= 60 then UnitInAir = false end self:T3( UnitInAir ) From a60626468cc92a35ecfe64656732d87d8e993069 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 13 Oct 2018 07:33:25 +0200 Subject: [PATCH 4/6] Implemented the capturing of the airbase. --- .../Moose/AI/AI_A2A_Dispatcher.lua | 68 ++++++++++++++----- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 20af4f2fe..65586f573 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -796,10 +796,17 @@ do -- AI_A2A_DISPATCHER -- -- Use the method @{#AI_A2A_DISPATCHER.SetDisengageRadius}() to modify the default Disengage Radius to another distance setting. -- + -- ## 11. Airbase capture: -- - -- ## 11. Q & A: + -- Different squadrons can be located at one airbase. + -- If the airbase gets captured, that is, when there is an enemy unit near the airbase, and there aren't anymore friendlies at the airbase, the airbase will change coalition ownership. + -- As a result, the GCI and CAP will stop! + -- However, the squadron will still stay alive. Any airplane that is airborne will continue its operations until all airborne airplanes + -- of the squadron will be destroyed. This to keep consistency of air operations not to confuse the players. -- - -- ### 11.1. Which countries will be selected for each coalition? + -- ## 12. Q & A: + -- + -- ### 12.1. Which countries will be selected for each coalition? -- -- Which countries are assigned to a coalition influences which units are available to the coalition. -- For example because the mission calls for a EWR radar on the blue side the Ukraine might be chosen as a blue country @@ -807,7 +814,7 @@ do -- AI_A2A_DISPATCHER -- Some countries assign different tasking to aircraft, for example Germany assigns the CAP task to F-4E Phantoms but the USA does not. -- Therefore if F4s are wanted as a coalition's CAP or GCI aircraft Germany will need to be assigned to that coalition. -- - -- ### 11.2. Country, type, load out, skill and skins for CAP and GCI aircraft? + -- ### 12.2. Country, type, load out, skill and skins for CAP and GCI aircraft? -- -- * Note these can be from any countries within the coalition but must be an aircraft with one of the main tasks being "CAP". -- * Obviously skins which are selected must be available to all players that join the mission otherwise they will see a default skin. @@ -995,9 +1002,13 @@ do -- AI_A2A_DISPATCHER self:HandleEvent( EVENTS.Dead, self.OnEventCrashOrDead ) --self:HandleEvent( EVENTS.RemoveUnit, self.OnEventCrashOrDead ) + self:HandleEvent( EVENTS.Land ) self:HandleEvent( EVENTS.EngineShutdown ) + -- Handle the situation where the airbases are captured. + self:HandleEvent( EVENTS.BaseCaptured ) + self:SetTacticalDisplay( false ) self:__Start( 5 ) @@ -1005,6 +1016,22 @@ do -- AI_A2A_DISPATCHER return self end + + --- @param #AI_A2A_DISPATCHER self + -- @param Core.Event#EVENTDATA EventData + function AI_A2A_DISPATCHER:OnEventBaseCaptured( EventData ) + + local AirbaseName = EventData.PlaceName -- The name of the airbase that was captured. + + -- Now search for all squadrons located at the airbase, and sanatize them. + for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do + if Squadron.AirbaseName == AirbaseName then + Squadron.Resources = -999 -- The base has been captured, and the resources are eliminated. No more spawning. + Squadron.Captured = true + end + end + end + --- @param #AI_A2A_DISPATCHER self -- @param Core.Event#EVENTDATA EventData function AI_A2A_DISPATCHER:OnEventCrashOrDead( EventData ) @@ -1497,6 +1524,7 @@ do -- AI_A2A_DISPATCHER end DefenderSquadron.Resources = Resources DefenderSquadron.TemplatePrefixes = TemplatePrefixes + DefenderSquadron.Captured = false -- Not captured. This flag will be set to true, when the airbase where the squadron is located, is captured. self:F( { Squadron = {SquadronName, AirbaseName, TemplatePrefixes, Resources } } ) @@ -1663,16 +1691,19 @@ do -- AI_A2A_DISPATCHER local DefenderSquadron = self:GetSquadron( SquadronName ) - if ( not DefenderSquadron.Resources ) or ( DefenderSquadron.Resources and DefenderSquadron.Resources > 0 ) then - - local Cap = DefenderSquadron.Cap - if Cap then - local CapCount = self:CountCapAirborne( SquadronName ) - self:F( { CapCount = CapCount } ) - if CapCount < Cap.CapLimit then - local Probability = math.random() - if Probability <= Cap.Probability then - return DefenderSquadron + if DefenderSquadron.Captured == false then -- We can only spawn new CAP if the base has not been captured. + + if ( not DefenderSquadron.Resources ) or ( DefenderSquadron.Resources and DefenderSquadron.Resources > 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 Probability = math.random() + if Probability <= Cap.Probability then + return DefenderSquadron + end end end end @@ -1693,10 +1724,13 @@ do -- AI_A2A_DISPATCHER local DefenderSquadron = self:GetSquadron( SquadronName ) - if ( not DefenderSquadron.Resources ) or ( DefenderSquadron.Resources and DefenderSquadron.Resources > 0 ) then - local Gci = DefenderSquadron.Gci - if Gci then - return DefenderSquadron + if DefenderSquadron.Captured == false then -- We can only spawn new CAP if the base has not been captured. + + if ( not DefenderSquadron.Resources ) or ( DefenderSquadron.Resources and DefenderSquadron.Resources > 0 ) then -- And, if there are sufficient resources. + local Gci = DefenderSquadron.Gci + if Gci then + return DefenderSquadron + end end end return nil From 4171cc45f5685f1f6a3e1fd85d49bfe540a9c692 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 13 Oct 2018 07:49:14 +0200 Subject: [PATCH 5/6] Fixing a mistake on capture. --- Moose Development/Moose/AI/AI_A2A_Dispatcher.lua | 4 ++++ Moose Development/Moose/Wrapper/Airbase.lua | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 65586f573..4daa08fc3 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -1023,11 +1023,14 @@ do -- AI_A2A_DISPATCHER local AirbaseName = EventData.PlaceName -- The name of the airbase that was captured. + self:I( "Captured " .. AirbaseName ) + -- Now search for all squadrons located at the airbase, and sanatize them. for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do if Squadron.AirbaseName == AirbaseName then Squadron.Resources = -999 -- The base has been captured, and the resources are eliminated. No more spawning. Squadron.Captured = true + self:I( "Squadron " .. SquadronName .. " captured." ) end end end @@ -1507,6 +1510,7 @@ do -- AI_A2A_DISPATCHER DefenderSquadron.Name = SquadronName DefenderSquadron.Airbase = AIRBASE:FindByName( AirbaseName ) + DefenderSquadron.AirbaseName = DefenderSquadron.Airbase:GetName() if not DefenderSquadron.Airbase then error( "Cannot find airbase with name:" .. AirbaseName ) end diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 40282285a..71b020489 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -334,7 +334,7 @@ end --- Find a AIRBASE in the _DATABASE using the name of an existing DCS Airbase. -- @param #AIRBASE self -- @param #string AirbaseName The Airbase Name. --- @return Wrapper.Airbase#AIRBASE self +-- @return #AIRBASE self function AIRBASE:FindByName( AirbaseName ) local AirbaseFound = _DATABASE:FindAirbase( AirbaseName ) From f8f0114f061acd80c2c594e2bf2fe166fe0f996b Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 13 Oct 2018 07:54:15 +0200 Subject: [PATCH 6/6] Documentation and exact location of test missions. --- .../Moose/AI/AI_A2A_Dispatcher.lua | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 4daa08fc3..8ba529d19 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -1,5 +1,6 @@ --- **AI** - (R2.2) - Manages the process of an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI. -- +-- === -- -- Features: -- @@ -18,6 +19,19 @@ -- * Quickly setup an A2A defense system using @{#AI_A2A_GCICAP}. -- * Setup a more advanced defense system using @{#AI_A2A_DISPATCHER}. -- +-- === +-- +-- ## Missions: +-- +-- [AID-A2A - AI A2A Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching) +-- +-- === +-- +-- ## YouTube Channel: +-- +-- [DCS WORLD - MOOSE - A2A GCICAP - Build an automatic A2A Defense System](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0S4KMNUUJpaUs6zZHjLKNx) +-- +-- === -- -- # QUICK START GUIDE -- @@ -183,18 +197,6 @@ do -- AI_A2A_DISPATCHER -- -- === -- - -- # Demo Missions - -- - -- ### [AI\_A2A\_DISPATCHER Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching) - -- - -- === - -- - -- # YouTube Channel - -- - -- ### [DCS WORLD - MOOSE - A2A GCICAP - Build an automatic A2A Defense System](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0S4KMNUUJpaUs6zZHjLKNx) - -- - -- === - -- -- ![Banner Image](..\Presentations\AI_A2A_DISPATCHER\Dia3.JPG) -- -- It includes automatic spawning of Combat Air Patrol aircraft (CAP) and Ground Controlled Intercept aircraft (GCI) in response to enemy air movements that are detected by a ground based radar network.