diff --git a/Moose Development/Moose/AI/AI_A2A.lua b/Moose Development/Moose/AI/AI_A2A.lua new file mode 100644 index 000000000..d5e8317fe --- /dev/null +++ b/Moose Development/Moose/AI/AI_A2A.lua @@ -0,0 +1,547 @@ +--- **AI** -- **AI A2A Air Patrolling or Staging.** +-- +-- ==== +-- +-- ### Author: **Sven Van de Velde (FlightControl)** +-- ### Contributions: +-- +-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) +-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Testing and API concept review. +-- +-- ==== +-- +-- @module AI_A2A + +--BASE:TraceClass("AI_A2A") + + +--- @type AI_A2A +-- @extends Core.Fsm#FSM_CONTROLLABLE + +--- # AI_A2A class, extends @{Fsm#FSM_CONTROLLABLE} +-- +-- The AI_A2A class implements the core functions to operate an AI @{Group} A2A tasking. +-- +-- +-- ## AI_A2A constructor +-- +-- * @{#AI_A2A.New}(): Creates a new AI_A2A object. +-- +-- ## 2. AI_A2A is a FSM +-- +-- ![Process](..\Presentations\AI_PATROL\Dia2.JPG) +-- +-- ### 2.1. AI_A2A States +-- +-- * **None** ( Group ): The process is not started yet. +-- * **Patrolling** ( Group ): The AI is patrolling the Patrol Zone. +-- * **Returning** ( Group ): The AI is returning to Base. +-- * **Stopped** ( Group ): The process is stopped. +-- * **Crashed** ( Group ): The AI has crashed or is dead. +-- +-- ### 2.2. AI_A2A Events +-- +-- * **Start** ( Group ): Start the process. +-- * **Stop** ( Group ): Stop the process. +-- * **Route** ( Group ): Route the AI to a new random 3D point within the Patrol Zone. +-- * **RTB** ( Group ): Route the AI to the home base. +-- * **Detect** ( Group ): The AI is detecting targets. +-- * **Detected** ( Group ): The AI has detected new targets. +-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. +-- +-- ## 3. Set or Get the AI controllable +-- +-- * @{#AI_A2A.SetControllable}(): Set the AIControllable. +-- * @{#AI_A2A.GetControllable}(): Get the AIControllable. +-- +-- @field #AI_A2A +AI_A2A = { + ClassName = "AI_A2A", +} + +--- Creates a new AI_A2A object +-- @param #AI_A2A self +-- @param Wrapper.Group#GROUP AIGroup The GROUP object to receive the A2A Process. +-- @return #AI_A2A +function AI_A2A:New( AIGroup ) + + -- Inherits from BASE + local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_A2A + + self:SetControllable( AIGroup ) + + self:ManageFuel( .2, 60 ) + self:ManageDamage( 0.4 ) + + self:SetStartState( "Stopped" ) + + self:AddTransition( "*", "Start", "Started" ) + + --- Start Handler OnBefore for AI_A2A + -- @function [parent=#AI_A2A] OnBeforeStart + -- @param #AI_A2A self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @return #boolean + + --- Start Handler OnAfter for AI_A2A + -- @function [parent=#AI_A2A] OnAfterStart + -- @param #AI_A2A self + -- @param #string From + -- @param #string Event + -- @param #string To + + --- Start Trigger for AI_A2A + -- @function [parent=#AI_A2A] Start + -- @param #AI_A2A self + + --- Start Asynchronous Trigger for AI_A2A + -- @function [parent=#AI_A2A] __Start + -- @param #AI_A2A self + -- @param #number Delay + + self:AddTransition( "*", "Stop", "Stopped" ) + +--- OnLeave Transition Handler for State Stopped. +-- @function [parent=#AI_A2A] OnLeaveStopped +-- @param #AI_A2A self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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 Stopped. +-- @function [parent=#AI_A2A] OnEnterStopped +-- @param #AI_A2A self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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. + +--- OnBefore Transition Handler for Event Stop. +-- @function [parent=#AI_A2A] OnBeforeStop +-- @param #AI_A2A self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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 Stop. +-- @function [parent=#AI_A2A] OnAfterStop +-- @param #AI_A2A self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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 Stop. +-- @function [parent=#AI_A2A] Stop +-- @param #AI_A2A self + +--- Asynchronous Event Trigger for Event Stop. +-- @function [parent=#AI_A2A] __Stop +-- @param #AI_A2A self +-- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "Status", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A. + +--- OnBefore Transition Handler for Event Status. +-- @function [parent=#AI_A2A] OnBeforeStatus +-- @param #AI_A2A self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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 Status. +-- @function [parent=#AI_A2A] OnAfterStatus +-- @param #AI_A2A self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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 Status. +-- @function [parent=#AI_A2A] Status +-- @param #AI_A2A self + +--- Asynchronous Event Trigger for Event Status. +-- @function [parent=#AI_A2A] __Status +-- @param #AI_A2A self +-- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "RTB", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A. + +--- OnBefore Transition Handler for Event RTB. +-- @function [parent=#AI_A2A] OnBeforeRTB +-- @param #AI_A2A self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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 RTB. +-- @function [parent=#AI_A2A] OnAfterRTB +-- @param #AI_A2A self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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 RTB. +-- @function [parent=#AI_A2A] RTB +-- @param #AI_A2A self + +--- Asynchronous Event Trigger for Event RTB. +-- @function [parent=#AI_A2A] __RTB +-- @param #AI_A2A self +-- @param #number Delay The delay in seconds. + +--- OnLeave Transition Handler for State Returning. +-- @function [parent=#AI_A2A] OnLeaveReturning +-- @param #AI_A2A self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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 Returning. +-- @function [parent=#AI_A2A] OnEnterReturning +-- @param #AI_A2A self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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( "*", "Return", "Returning" ) + self:AddTransition( "*", "Home", "Home" ) + self:AddTransition( "*", "LostControl", "LostControl" ) + self:AddTransition( "*", "Fuel", "Fuel" ) + self:AddTransition( "*", "Damaged", "Damaged" ) + self:AddTransition( "*", "Eject", "*" ) + self:AddTransition( "*", "Crash", "Crashed" ) + self:AddTransition( "*", "PilotDead", "*" ) + + return self +end + +function AI_A2A:SetDispatcher( Dispatcher ) + self.Dispatcher = Dispatcher +end + +function AI_A2A:GetDispatcher() + return self.Dispatcher +end + +function AI_A2A:SetTargetDistance( Coordinate ) + + local CurrentCoord = self.Controllable:GetCoordinate() + self.TargetDistance = CurrentCoord:Get2DDistance( Coordinate ) + + self.ClosestTargetDistance = ( not self.ClosestTargetDistance or self.ClosestTargetDistance > self.TargetDistance ) and self.TargetDistance or self.ClosestTargetDistance +end + + +function AI_A2A:ClearTargetDistance() + + self.TargetDistance = nil + self.ClosestTargetDistance = nil +end + + +--- Sets (modifies) the minimum and maximum speed of the patrol. +-- @param #AI_A2A self +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @return #AI_A2A self +function AI_A2A:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed ) + self:F2( { PatrolMinSpeed, PatrolMaxSpeed } ) + + self.PatrolMinSpeed = PatrolMinSpeed + self.PatrolMaxSpeed = PatrolMaxSpeed +end + + +--- Sets the floor and ceiling altitude of the patrol. +-- @param #AI_A2A self +-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @return #AI_A2A self +function AI_A2A:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude ) + self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } ) + + self.PatrolFloorAltitude = PatrolFloorAltitude + self.PatrolCeilingAltitude = PatrolCeilingAltitude +end + + +--- Sets the home airbase. +-- @param #AI_A2A self +-- @param Wrapper.Airbase#AIRBASE HomeAirbase +-- @return #AI_A2A self +function AI_A2A:SetHomeAirbase( HomeAirbase ) + self:F2( { HomeAirbase } ) + + self.HomeAirbase = HomeAirbase +end + + + +--- Set the status checking off. +-- @param #AI_A2A self +-- @return #AI_A2A self +function AI_A2A:SetStatusOff() + self:F2() + + self.CheckStatus = false +end + + +--- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base. +-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated. +-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_A2A. +-- Once the time is finished, the old AI will return to the base. +-- @param #AI_A2A self +-- @param #number PatrolFuelTresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel. +-- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base. +-- @return #AI_A2A self +function AI_A2A:ManageFuel( PatrolFuelTresholdPercentage, PatrolOutOfFuelOrbitTime ) + + self.PatrolManageFuel = true + self.PatrolFuelTresholdPercentage = PatrolFuelTresholdPercentage + self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime + + self.Controllable:OptionRTBBingoFuel( false ) + + return self +end + +--- When the AI is damaged beyond a certain treshold, it is required that the AI returns to the home base. +-- However, damage cannot be foreseen early on. +-- Therefore, when the damage treshold is reached, +-- the AI will return immediately to the home base (RTB). +-- Note that for groups, the average damage of the complete group will be calculated. +-- So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage treshold will be 0.25. +-- @param #AI_A2A self +-- @param #number PatrolDamageTreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged. +-- @return #AI_A2A self +function AI_A2A:ManageDamage( PatrolDamageTreshold ) + + self.PatrolManageDamage = true + self.PatrolDamageTreshold = PatrolDamageTreshold + + return self +end + +--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings. +-- @param #AI_A2A self +-- @return #AI_A2A self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A:onafterStart( Controllable, From, Event, To ) + self:F2() + + self:__Status( 10 ) -- Check status status every 30 seconds. + + self:HandleEvent( EVENTS.PilotDead, self.OnPilotDead ) + self:HandleEvent( EVENTS.Crash, self.OnCrash ) + self:HandleEvent( EVENTS.Ejection, self.OnEjection ) + + Controllable:OptionROEHoldFire() + Controllable:OptionROTVertical() +end + + + +--- @param #AI_A2A self +function AI_A2A:onbeforeStatus() + + return self.CheckStatus +end + +--- @param #AI_A2A self +function AI_A2A:onafterStatus() + self:F() + + if self.Controllable and self.Controllable:IsAlive() then + + local RTB = false + + local Fuel = self.Controllable:GetUnit(1):GetFuel() + self:F({Fuel=Fuel}) + if Fuel < self.PatrolFuelTresholdPercentage then + self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" ) + local OldAIControllable = self.Controllable + local AIControllableTemplate = self.Controllable:GetTemplate() + + local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed ) + local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) ) + OldAIControllable:SetTask( TimedOrbitTask, 10 ) + + self:Fuel() + RTB = true + else + end + + -- TODO: Check GROUP damage function. + local Damage = self.Controllable:GetLife() + local InitialLife = self.Controllable:GetLife0() + self:F( { Damage = Damage, InitialLife = InitialLife, DamageTreshold = self.PatrolDamageTreshold } ) + if ( Damage / InitialLife ) < self.PatrolDamageTreshold then + self:E( self.Controllable:GetName() .. " is damaged: " .. Damage .. " ... RTB!" ) + self:Damaged() + RTB = true + end + + -- Check if planes went RTB + local TargetDistance = self.TargetDistance + local ClosestTargetDistance = self.ClosestTargetDistance + if TargetDistance then + if ClosestTargetDistance <= 40000 then + if TargetDistance > 40000 then + self:E( "Lost control of group " .. self.Controllable:GetName() .. " ... RTB!" ) + self:LostControl() + RTB = true + end + end + end + + if RTB == true then + self:__RTB( 0.5 ) + else + self:__Status( 10 ) -- Execute the Patrol event after 30 seconds. + end + end +end + + +--- @param Wrapper.Group#GROUP AIGroup +function AI_A2A.RTBRoute( AIGroup ) + + AIGroup:E( { "RTBRoute:", AIGroup:GetName() } ) + local _AI_A2A = AIGroup:GetState( AIGroup, "AI_A2A" ) -- #AI_A2A + _AI_A2A:__RTB( 0.5 ) +end + +--- @param #AI_A2A self +-- @param Wrapper.Group#GROUP AIGroup +function AI_A2A:onafterRTB( AIGroup, From, Event, To ) + self:F( { AIGroup, From, Event, To } ) + + self:E( "Group " .. self.Controllable:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" ) + + if AIGroup and AIGroup:IsAlive() then + + self.CheckStatus = false + + self:ClearTargetDistance() + AIGroup:ClearTasks() + AIGroup:ClearTasks() + + local EngageRoute = {} + + --- Calculate the target route point. + + local CurrentCoord = AIGroup:GetCoordinate() + local ToTargetCoord = self.HomeAirbase:GetCoordinate() + local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed ) + local ToAirbaseAngle = CurrentCoord:GetAngleDegrees( CurrentCoord:GetDirectionVec3( ToTargetCoord ) ) + + local Distance = CurrentCoord:Get2DDistance( ToTargetCoord ) + + local ToAirbaseCoord = CurrentCoord:Translate( 5000, ToAirbaseAngle ) + if Distance < 5000 then + self:Home() + return + end + --- Create a route point of type air. + local ToPatrolRoutePoint = ToAirbaseCoord:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + ToTargetSpeed, + true + ) + + self:F( { Angle = ToAirbaseAngle, ToTargetSpeed = ToTargetSpeed } ) + self:T2( { self.MinSpeed, self.MaxSpeed, ToTargetSpeed } ) + + EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint + + AIGroup:OptionROEHoldFire() + AIGroup:OptionROTEvadeFire() + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + AIGroup:WayPointInitialize( EngageRoute ) + + local Tasks = {} + Tasks[#Tasks+1] = AIGroup:TaskFunction( 1, 1, "AI_A2A.RTBRoute" ) + EngageRoute[1].task = AIGroup:TaskCombo( Tasks ) + + AIGroup:SetState( AIGroup, "AI_A2A", self ) + + --- NOW ROUTE THE GROUP! + AIGroup:WayPointExecute( 1, 0 ) + + end + +end + +--- @param #AI_A2A self +-- @param Wrapper.Group#GROUP AIGroup +function AI_A2A:onafterHome( AIGroup, From, Event, To ) + self:F( { AIGroup, From, Event, To } ) + + self:E( "Group " .. self.Controllable:GetName() .. " ... Home! ( " .. self:GetState() .. " )" ) + + if AIGroup and AIGroup:IsAlive() then + end + +end + + + +--- @param #AI_A2A self +function AI_A2A:onafterDead() + self:SetStatusOff() +end + + +--- @param #AI_A2A self +-- @param Core.Event#EVENTDATA EventData +function AI_A2A:OnCrash( EventData ) + + if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then + self:E( self.Controllable:GetUnits() ) + if #self.Controllable:GetUnits() == 1 then + self:__Crash( 1, EventData ) + end + end +end + +--- @param #AI_A2A self +-- @param Core.Event#EVENTDATA EventData +function AI_A2A:OnEjection( EventData ) + + if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then + self:__Eject( 1, EventData ) + end +end + +--- @param #AI_A2A self +-- @param Core.Event#EVENTDATA EventData +function AI_A2A:OnPilotDead( EventData ) + + if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then + self:__PilotDead( 1, EventData ) + end +end diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua new file mode 100644 index 000000000..64846ae01 --- /dev/null +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -0,0 +1,491 @@ +--- **AI** -- **Execute Combat Air Patrol (CAP).** +-- +-- ![Banner Image](..\Presentations\AI_CAP\Dia1.JPG) +-- +-- === +-- +-- AI CAP classes makes AI Controllables execute a Combat Air Patrol. +-- +-- There are the following types of CAP classes defined: +-- +-- * @{#AI_A2A_CAP}: Perform a CAP in a zone. +-- +-- ==== +-- +-- ### Author: **Sven Van de Velde (FlightControl)** +-- +-- ### Contributions: +-- +-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing. +-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Concept, Advice & Testing. +-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision. +-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing. +-- * **[Delta99](https://forums.eagle.ru/member.php?u=125166): Testing. +-- +-- ==== +-- +-- @module AI_A2A_Cap + +--BASE:TraceClass("AI_A2A_CAP") + +--- @type AI_A2A_CAP +-- @extends AI.AI_A2A_Patrol#AI_A2A_PATROL + + +--- # AI_A2A_CAP class, extends @{AI_CAP#AI_PATROL_ZONE} +-- +-- The AI_A2A_CAP class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group} +-- and automatically engage any airborne enemies that are within a certain range or within a certain zone. +-- +-- ![Process](..\Presentations\AI_CAP\Dia3.JPG) +-- +-- The AI_A2A_CAP is assigned a @{Group} and this must be done before the AI_A2A_CAP process can be started using the **Start** event. +-- +-- ![Process](..\Presentations\AI_CAP\Dia4.JPG) +-- +-- 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. +-- +-- ![Process](..\Presentations\AI_CAP\Dia5.JPG) +-- +-- This cycle will continue. +-- +-- ![Process](..\Presentations\AI_CAP\Dia6.JPG) +-- +-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event. +-- +-- ![Process](..\Presentations\AI_CAP\Dia9.JPG) +-- +-- When enemies are detected, the AI will automatically engage the enemy. +-- +-- ![Process](..\Presentations\AI_CAP\Dia10.JPG) +-- +-- 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. +-- +-- ![Process](..\Presentations\AI_CAP\Dia13.JPG) +-- +-- ## 1. AI_A2A_CAP constructor +-- +-- * @{#AI_A2A_CAP.New}(): Creates a new AI_A2A_CAP object. +-- +-- ## 2. AI_A2A_CAP is a FSM +-- +-- ![Process](..\Presentations\AI_CAP\Dia2.JPG) +-- +-- ### 2.1 AI_A2A_CAP 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_A2A_CAP Events +-- +-- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. +-- * **@{#AI_A2A_CAP.Engage}**: Let the AI engage the bogeys. +-- * **@{#AI_A2A_CAP.Abort}**: Aborts the engagement and return patrolling in the patrol zone. +-- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. +-- * **@{#AI_A2A_CAP.Destroy}**: The AI has destroyed a bogey @{Unit}. +-- * **@{#AI_A2A_CAP.Destroyed}**: The AI has destroyed all bogeys @{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 +-- +-- ![Range](..\Presentations\AI_CAP\Dia11.JPG) +-- +-- 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_CAP#AI_A2A_CAP.SetEngageRange}() to define that range. +-- +-- ## 4. Set the Zone of Engagement +-- +-- ![Zone](..\Presentations\AI_CAP\Dia12.JPG) +-- +-- An optional @{Zone} can be set, +-- that will define when the AI will engage with the detected airborne enemy targets. +-- Use the method @{AI_Cap#AI_A2A_CAP.SetEngageZone}() to define that Zone. +-- +-- === +-- +-- @field #AI_A2A_CAP +AI_A2A_CAP = { + ClassName = "AI_A2A_CAP", +} + +--- Creates a new AI_A2A_CAP object +-- @param #AI_A2A_CAP self +-- @param Wrapper.Group#GROUP AIGroup +-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. +-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed EngageMinSpeed The minimum speed of the @{Controllable} in km/h when engaging a target. +-- @param Dcs.DCSTypes#Speed EngageMaxSpeed The maximum speed of the @{Controllable} in km/h when engaging a target. +-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @return #AI_A2A_CAP +function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType ) + + -- Inherits from BASE + local self = BASE:Inherit( self, AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_A2A_CAP + + self.Accomplished = false + self.Engaging = false + + self.EngageMinSpeed = EngageMinSpeed + self.EngageMaxSpeed = EngageMaxSpeed + + self:AddTransition( { "Patrolling", "Engaging", "Returning" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP. + + --- OnBefore Transition Handler for Event Engage. + -- @function [parent=#AI_A2A_CAP] OnBeforeEngage + -- @param #AI_A2A_CAP self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_CAP] OnAfterEngage + -- @param #AI_A2A_CAP self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_CAP] Engage + -- @param #AI_A2A_CAP self + + --- Asynchronous Event Trigger for Event Engage. + -- @function [parent=#AI_A2A_CAP] __Engage + -- @param #AI_A2A_CAP self + -- @param #number Delay The delay in seconds. + +--- OnLeave Transition Handler for State Engaging. +-- @function [parent=#AI_A2A_CAP] OnLeaveEngaging +-- @param #AI_A2A_CAP self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_CAP] OnEnterEngaging +-- @param #AI_A2A_CAP self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_CAP. + + --- OnBefore Transition Handler for Event Fired. + -- @function [parent=#AI_A2A_CAP] OnBeforeFired + -- @param #AI_A2A_CAP self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_CAP] OnAfterFired + -- @param #AI_A2A_CAP self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_CAP] Fired + -- @param #AI_A2A_CAP self + + --- Asynchronous Event Trigger for Event Fired. + -- @function [parent=#AI_A2A_CAP] __Fired + -- @param #AI_A2A_CAP self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP. + + --- OnBefore Transition Handler for Event Destroy. + -- @function [parent=#AI_A2A_CAP] OnBeforeDestroy + -- @param #AI_A2A_CAP self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_CAP] OnAfterDestroy + -- @param #AI_A2A_CAP self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_CAP] Destroy + -- @param #AI_A2A_CAP self + + --- Asynchronous Event Trigger for Event Destroy. + -- @function [parent=#AI_A2A_CAP] __Destroy + -- @param #AI_A2A_CAP self + -- @param #number Delay The delay in seconds. + + + self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP. + + --- OnBefore Transition Handler for Event Abort. + -- @function [parent=#AI_A2A_CAP] OnBeforeAbort + -- @param #AI_A2A_CAP self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_CAP] OnAfterAbort + -- @param #AI_A2A_CAP self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_CAP] Abort + -- @param #AI_A2A_CAP self + + --- Asynchronous Event Trigger for Event Abort. + -- @function [parent=#AI_A2A_CAP] __Abort + -- @param #AI_A2A_CAP self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP. + + --- OnBefore Transition Handler for Event Accomplish. + -- @function [parent=#AI_A2A_CAP] OnBeforeAccomplish + -- @param #AI_A2A_CAP self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_CAP] OnAfterAccomplish + -- @param #AI_A2A_CAP self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_CAP] Accomplish + -- @param #AI_A2A_CAP self + + --- Asynchronous Event Trigger for Event Accomplish. + -- @function [parent=#AI_A2A_CAP] __Accomplish + -- @param #AI_A2A_CAP self + -- @param #number Delay The delay in seconds. + + return self +end + + +--- Set the Engage Zone which defines where the AI will engage bogies. +-- @param #AI_A2A_CAP self +-- @param Core.Zone#ZONE EngageZone The zone where the AI is performing CAP. +-- @return #AI_A2A_CAP self +function AI_A2A_CAP: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_A2A_CAP self +-- @param #number EngageRange The Engage Range. +-- @return #AI_A2A_CAP self +function AI_A2A_CAP:SetEngageRange( EngageRange ) + self:F2() + + if EngageRange then + self.EngageRange = EngageRange + else + self.EngageRange = nil + end +end + +--- onafter State Transition for Event Patrol. +-- @param #AI_A2A_CAP self +-- @param Wrapper.Controllable#CONTROLLABLE AIGroup 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_A2A_CAP:onafterPatrol( AIGroup, From, Event, To ) + + -- Call the parent Start event handler + self:GetParent(self).onafterPatrol( self, AIGroup, From, Event, To ) + self:HandleEvent( EVENTS.Dead ) + +end + +-- todo: need to fix this global function + +--- @param Wrapper.Group#GROUP AIGroup +function AI_A2A_CAP.AttackRoute( AIGroup ) + + local EngageZone = AIGroup:GetState( AIGroup, "AI_A2A_CAP" ) -- AI.AI_Cap#AI_A2A_CAP + EngageZone:__Engage( 0.5 ) +end + +--- @param #AI_A2A_CAP self +-- @param Wrapper.Controllable#CONTROLLABLE AIGroup The Controllable 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_A2A_CAP:onbeforeEngage( AIGroup, From, Event, To ) + + if self.Accomplished == true then + return false + end +end + +--- @param #AI_A2A_CAP self +-- @param Wrapper.Controllable#CONTROLLABLE AIGroup 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_A2A_CAP:onafterAbort( AIGroup, From, Event, To ) + AIGroup:ClearTasks() + self:__Route( 0.5 ) +end + + +--- @param #AI_A2A_CAP self +-- @param Wrapper.Controllable#CONTROLLABLE AIGroup The Controllable 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_A2A_CAP:onafterEngage( AIGroup, From, Event, To, AttackSetUnit ) + + self:F( { AIGroup, From, Event, To, AttackSetUnit} ) + + self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT + + local FirstAttackUnit = self.AttackSetUnit:GetFirst() + + if FirstAttackUnit then + + if AIGroup:IsAlive() then + + local EngageRoute = {} + + --- Calculate the target route point. + local CurrentCoord = AIGroup: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 ):RoutePointAir( + 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 + + AIGroup:OptionROEOpenFire() + AIGroup:OptionROTPassiveDefense() + + 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] = AIGroup:TaskAttackUnit( AttackUnit ) + end + end + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + self.Controllable:WayPointInitialize( EngageRoute ) + + + if #AttackTasks == 0 then + self:E("No targets found -> Going back to Patrolling") + self:__Abort( 0.5 ) + else + AttackTasks[#AttackTasks+1] = AIGroup:TaskFunction( 1, #AttackTasks, "AI_A2A_CAP.AttackRoute" ) + AttackTasks[#AttackTasks+1] = AIGroup:TaskOrbitCircle( 4000, self.PatrolMinSpeed ) + + EngageRoute[1].task = AIGroup:TaskCombo( AttackTasks ) + + --- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ... + AIGroup:SetState( AIGroup, "AI_A2A_CAP", self ) + end + + --- NOW ROUTE THE GROUP! + AIGroup:WayPointExecute( 1, 0 ) + end + else + self:E("No targets found -> Going back to Patrolling") + self:__Abort( 0.5 ) + end +end + +--- @param #AI_A2A_CAP self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_CAP:onafterAccomplish( Controllable, From, Event, To ) + self.Accomplished = true + self:SetDetectionOff() +end + +--- @param #AI_A2A_CAP self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_CAP:onafterDestroy( Controllable, From, Event, To, EventData ) + + if EventData.IniUnit then + self.AttackUnits[EventData.IniUnit] = nil + end +end + +--- @param #AI_A2A_CAP self +-- @param Core.Event#EVENTDATA EventData +function AI_A2A_CAP: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 diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua new file mode 100644 index 000000000..e7d811fa4 --- /dev/null +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -0,0 +1,1764 @@ +--- **AI** - The AI_A2A_DISPATCHER creates an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI. +-- +-- ==== +-- +-- ### Authors: **Sven Van de Velde (FlightControl)** +-- **Stonehouse** +-- +-- ### Contributions: +-- +-- ==== +-- +-- @module AI_A2A_Dispatcher + +--BASE:TraceClass("AI_A2A_DISPATCHER") + +do -- AI_A2A_DISPATCHER + + --- AI_A2A_DISPATCHER class. + -- @type AI_A2A_DISPATCHER + -- @extends Tasking.DetectionManager#DETECTION_MANAGER + + --- # AI_A2A_DISPATCHER class, extends @{Tasking#DETECTION_MANAGER} + -- + -- The @{#AI_A2A_DISPATCHER} class is designed to create an automatic air defence system for a coalition. + -- 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. + -- CAP flights will take off and proceed to designated CAP zones where they will remain on station until the ground radars direct them to intercept detected enemy aircraft or they run short of fuel and must return to base (RTB). When a CAP flight leaves their zone to perform an interception or return to base a new CAP flight will spawn to take their place. + -- If all CAP flights are engaged or RTB then additional GCI interceptors will scramble to intercept unengaged enemy aircraft under ground radar control. + -- With a little time and with a little work it provides the mission designer with a convincing and completely automatic air defence system. + -- In short it is a plug in very flexible and configurable air defence module for DCS World. + -- + -- Note that in order to create a two way A2A defense system, two AI_A2A_DISPATCHER defense system may need to be created, for each coalition one. + -- This is a good implementation, because maybe in the future, more coalitions may become available in DCS world. + -- + -- ## 1. AI_A2A_DISPATCHER constructor: + -- + -- The @{#AI_A2A_DISPATCHER.New}() method creates a new AI_A2A_DISPATCHER instance. + -- There are two parameters required, a @{Set#SET_GROUP} that defines the Groups of the EWR network, and a radius in meters, that will be used to group the detected targets. + -- + -- The @{#AI_A2A_DISPATCHER.New}() method is used to setup the EWR network and to define the grouping. + -- + -- ### 1.1. Define the EWR network: + -- + -- Typically EWR networks are setup using 55G6 EWR, 1L13 EWR, Hawk sr and Patriot str ground based radar units. + -- These radars have different ranges and 55G6 EWR and 1L13 EWR radars are Eastern Bloc units (eg Russia, Ukraine, Georgia) while the Hawk and Patriot radars are Western (eg US). + -- Additionally, ANY other radar capable unit can be part of the EWR network! Also AWACS airborne units, planes, helicopters can help to detect targets, as long as they have radar. + -- The position of these units is very important as they need to provide enough coverage + -- to pick up enemy aircraft as they approach so that CAP and GCI flights can be tasked to intercept them. + -- Additionally in a hot war situation where the border is no longer respected the placement of radars has a big effect on how fast the war escalates. + -- For example if they are a long way forward and can detect enemy planes on the ground and taking off + -- they will start to vector CAP and GCI flights to attack them straight away which will immediately draw a response from the other coalition. + -- Having the radars further back will mean a slower escalation because fewer targets will be detected and + -- therefore less CAP and GCI flights will spawn and this will tend to make just the border area active rather than a melee over the whole map. + -- It all depends on what the desired effect is. + -- + -- EWR networks are dynamically constructed, that is, they form part of the @{Set#SET_GROUP} object that is given as the input parameter of the AI_A2A_DISPATCHER class. + -- By defining in a smart way the names or name prefixes of the groups of EWR capable units, these units will be automatically added or deleted from the EWR network, + -- increasing or decreasing the radar coverage of the Early Warning System. + -- + -- See the following example to setup an EWR network containing EWR stations and AWACS. + -- + -- -- Define a SET_GROUP object that builds a collection of groups that define the EWR network. + -- -- Here we build the network with all the groups that have a name starting with DF CCCP AWACS and DF CCCP EWR. + -- DetectionSetGroup = SET_GROUP:New() + -- DetectionSetGroup:FilterPrefixes( { "DF CCCP AWACS", "DF CCCP EWR" } ) + -- DetectionSetGroup:FilterStart() + -- + -- -- Setup the A2A dispatcher, and initialize it. + -- A2ADispatcher = AI_A2A_DISPATCHER:New( DetectionSetGroup, 30000 ) + -- + -- The above example creates a SET_GROUP instance, and stores this in the variable (object) **DetectionSetGroup**. + -- **DetectionSetGroup** is then being configured to filter all active groups with a group name starting with **DF CCCP AWACS** or **DF CCCP EWR** to be included in the Set. + -- **DetectionSetGroup** is then being ordered to start the dynamic filtering. Note that any destroy or new spawn of a group with the above names will be removed or added to the Set. + -- The **DetectionSetGroup** variable is then passed to the @{#AI_A2A_DISPATCHER.New}() method to indicate the EWR network configuration and setup the A2A defense detection mechanism. + -- As a second parameter of the @{#AI_A2A_DISPATCHER.New}() method, 30000 indicates that detected targets need to be grouped within a radius of 30km. + -- The grouping radius should not be too small, but also depends on the types of planes and the era of the simulation. + -- Fast planes like in the 80s, need a larger radius than WWII planes. + -- Typically I suggest to use 30000 for new generation planes and 10000 for older era aircraft. + -- + -- Note that detected targets are constantly re-grouped, that is, when certain detected aircraft are moving further than the group radius, then these aircraft will become a separate + -- group being detected. This may result in additional GCI being started by the dispatcher! So don't make this value too small! + -- + -- ## 2. Set the **engage radius**: + -- + -- Define the radius to engage any target by airborne friendlies, which are executing cap or returning from an intercept mission. + -- So, if there is a target area detected and reported, + -- then any friendlies that are airborne near this target area, + -- will be commanded to (re-)engage that target when available (if no other tasks were commanded). + -- For example, if 100000 is given as a value, then any friendly that is airborne within 100km from the detected target, + -- will be considered to receive the command to engage that target area. + -- You need to evaluate the value of this parameter carefully. + -- If too small, more intercept missions may be triggered upon detected target areas. + -- If too large, any airborne cap may not be able to reach the detected target area in time, because it is too far. + -- + -- ## 3. Set the **borders**: + -- + -- According to the tactical and strategic design of the mission broadly decide the shape and extent of red and blue territories. + -- They should be laid out such that a border area is created between the two coalitions. + -- + -- Define a border area to simulate a **cold war** scenario and use the method @{#AI_A2A_DISPATCHER.SetBorderZone}() to create a border zone for the dispatcher. + -- + -- 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. + -- If it’s a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Zone#ZONE_BASE}. + -- 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 + -- + -- ## 4. Squadrons: + -- + -- The AI_A2A_DISPATCHER works with **Squadrons**, that need to be defined using the different methods available. + -- + -- Use the method @{#AI_A2A_DISPATCHER.SetSquadron}() to **setup a new squadron** active at an airfield, + -- while defining which plane types are being used by the squadron and how many resources are available. + -- + -- Squadrons: + -- + -- * Have name (string) that is the identifier or key of the squadron. + -- * Have specific plane types. + -- * Are located at one airbase. + -- * Have a limited set of resources. + -- + -- The name of the squadron given acts as the **squadron key** in the AI_A2A_DISPATCHER:Squadron...() methods. + -- + -- Additionally, squadrons have specific configuration options to: + -- + -- * Control how new aircraft are taking off from the airfield (in the air, cold, hot, at the runway). + -- * Control how returning aircraft are landing at the airfield (in the air near the airbase, after landing, after engine shutdown). + -- * Control the **grouping** of new aircraft spawned at the airfield. If there is more than one aircraft to be spawned, these may be grouped. + -- * Control the **overhead** or defensive strength of the squadron. Depending on the types of planes and amount of resources, the mission designer can choose to increase or reduce the amount of planes spawned. + -- + -- For performance and bug workaround reasons within DCS, squadrons have different methods to spawn new aircraft or land returning or damaged aircraft. + -- + -- + -- ### 4.1. Set squadron take-off methods + -- + -- Use the various SetSquadronTakeoff... methods to control how squadrons are taking-off from the airfield: + -- + -- * @{#AI_A2A_DISPATCHER.SetSquadronTakeoff}() is the generic configuration method to control takeoff from the air, hot, cold or from the runway. See the method for further details. + -- * @{#AI_A2A_DISPATCHER.SetSquadronTakeoffInAir}() will spawn new aircraft from the squadron directly in the air. + -- * @{#AI_A2A_DISPATCHER.SetSquadronTakeoffFromParkingCold}() will spawn new aircraft in without running engines at a parking spot at the airfield. + -- * @{#AI_A2A_DISPATCHER.SetSquadronTakeoffFromParkingHot}() will spawn new aircraft in with running engines at a parking spot at the airfield. + -- * @{#AI_A2A_DISPATCHER.SetSquadronTakeoffFromRunway}() will spawn new aircraft at the runway at the airfield. + -- + -- Use these methods to fine-tune for specific airfields that are known to create bottlenecks, or have reduced airbase efficiency. + -- The more and the longer aircraft need to taxi at an airfield, the more risk there is that: + -- + -- * aircraft will stop waiting for each other or for a landing aircraft before takeoff. + -- * aircraft may get into a "dead-lock" situation, where two aircraft are blocking each other. + -- * aircraft may collide at the airbase. + -- * aircraft may be awaiting the landing of a plane currently in the air, but never lands ... + -- + -- Currently within the DCS engine, the airfield traffic coordination is erroneous and contains a lot of bugs. + -- If you experience while testing problems with aircraft take-off or landing, please use one of the above methods as a solution to workaround these issues! + -- + -- ### 4.2. Set squadron landing methods + -- + -- In analogy with takeoff, the landing methods are to control how squadrons land at the airfield: + -- + -- * @{#AI_A2A_DISPATCHER.SetSquadronLanding}() is the generic configuration method to control landing, namely despawn the aircraft near the airfield in the air, right after landing, or at engine shutdown. + -- * @{#AI_A2A_DISPATCHER.SetSquadronLandingNearAirbase}() will despawn the returning aircraft in the air when near the airfield. + -- * @{#AI_A2A_DISPATCHER.SetSquadronLandingAtRunway}() will despawn the returning aircraft directly after landing at the runway. + -- * @{#AI_A2A_DISPATCHER.SetSquadronLandingAtEngineShutdown}() will despawn the returning aircraft when the aircraft has returned to its parking spot and has turned off its engines. + -- + -- You can use these methods to minimize the airbase coodination overhead and to increase the airbase efficiency. + -- When there are lots of aircraft returning for landing, at the same airbase, the takeoff process will be halted, which can cause a complete failure of the + -- A2A defense system, as no new CAP or GCI planes can takeoff. + -- Note that the method @{#AI_A2A_DISPATCHER.SetSquadronLandingNearAirbase}() will only work for returning aircraft, not for damaged or out of fuel aircraft. + -- Damaged or out-of-fuel aircraft are returning to the nearest friendly airbase and will land, and are out of control from ground control. + -- + -- ### 4.3. Set squadron grouping + -- + -- Choices are 1, 2, 3 or 4 when CAP or GCI flights spawn. Use the method @{#AI_A2A_DISPATCHER.SetSquadronGrouping}() to set the amount of CAP or GCI flights that will take-off when spawned. + -- In the case of GCI, the @{#AI_A2A_DISPATCHER.SetSquadronGrouping}() method has additional behaviour. When there aren't enough CAP flights airborne, a GCI will be initiated for the remaining + -- targets to be engaged. Depending on the grouping parameter, the spawned flights for GCI are grouped into this setting. + -- For example with a group setting of 2, if 3 targets are detected and cannot be engaged by CAP or any airborne flight, + -- a GCI needs to be started, the GCI flights will be grouped as follows: Group 1 of 2 flights and Group 2 of one flight! + -- + -- The **grouping value is set for a Squadron**, and can be **dynamically adjusted** during mission execution, so to adjust the defense flights grouping when the tactical situation changes. + -- + -- ### 4.4. Balance or setup effectiveness of the air defenses in case of GCI + -- + -- The effectiveness can be set with the **overhead parameter**. This is a number that is used to calculate the amount of Units that dispatching command will allocate to GCI in surplus of detected amount of units. + -- The **default value** of the overhead parameter is 1.0, which means **equal balance**. + -- + -- However, depending on the (type of) aircraft (strength and payload) in the squadron and the amount of resources available, this parameter can be changed. + -- + -- The @{#AI_A2A_DISPATCHER.SetOverhead}() method can be used to tweak the defense strength, + -- taking into account the plane types of the squadron. + -- + -- For example, a MIG-31 with full long-distance A2A missiles payload, may still be less effective than a F-15C with short missiles... + -- So in this case, one may want to use the @{#AI_A2A_DISPATCHER.SetOverhead}() method to allocate more defending planes as the amount of detected attacking planes. + -- The overhead must be given as a decimal value with 1 as the neutral value, which means that overhead values: + -- + -- * Higher than 1.0, for example 1.5, will increase the defense unit amounts. For 4 planes detected, 6 planes will be spawned. + -- * Lower than 1, for example 0.75, will decrease the defense unit amounts. For 4 planes detected, only 3 planes will be spawned. + -- + -- The amount of defending units is calculated by multiplying the amount of detected attacking planes as part of the detected group + -- multiplied by the Overhead and rounded up to the smallest integer. + -- + -- The **overhead value is set for a Squadron**, and can be **dynamically adjusted** during mission execution, so to adjust the defense overhead when the tactical situation changes. + -- + -- ## 5. Setup a squadron for CAP + -- + -- ### 5.1. Set the CAP zones + -- + -- * CAP zones are patrol areas where Combat Air Patrol (CAP) flights loiter until they either return to base due to low fuel or are assigned an interception task by ground control. + -- + -- * As the CAP flights wander around within the zone waiting to be tasked, these zones need to be large enough that the aircraft are not constantly turning + -- but do not have to be big and numerous enough to completely cover a border. + -- + -- * CAP zones can be of any type, and are derived from the @{Zone#ZONE_BASE} class. Zones can be @{Zone#ZONE}, @{Zone#ZONE_POLYGON}, @{Zone#ZONE_UNIT}, @{Zone#ZONE_GROUP}, etc. + -- This allows to setup **static, moving and/or complex zones** wherein aircraft will perform the CAP. + -- + -- * Typically 20000-50000 metres width is used and they are spaced so that aircraft in the zone waiting for tasks don’t have to far to travel to protect their coalitions important targets. + -- These targets are chosen as part of the mission design and might be an important airfield or town etc. + -- Zone size is also determined somewhat by territory size, plane types + -- (eg WW2 aircraft might mean smaller zones or more zones because they are slower and take longer to intercept enemy aircraft). + -- + -- * In a **cold war** it is important to make sure a CAP zone doesn’t intrude into enemy territory as otherwise CAP flights will likely cross borders + -- and spark a full scale conflict which will escalate rapidly. + -- + -- * CAP flights do not need to be in the CAP zone before they are “on station” and ready for tasking. + -- + -- * Typically if a CAP flight is tasked and therefore leaves their zone empty while they go off and intercept their target another CAP flight will spawn to take their place. + -- + -- The following example illustrates how CAP zones are coded: + -- + -- -- CAP Squadron execution. + -- CAPZoneEast = ZONE_POLYGON:New( "CAP Zone East", GROUP:FindByName( "CAP Zone East" ) ) + -- A2ADispatcher:SetSquadronCap( "Mineralnye", CAPZoneEast, 4000, 10000, 500, 600, 800, 900 ) + -- A2ADispatcher:SetSquadronCapInterval( "Mineralnye", 2, 30, 60, 1 ) + -- + -- CAPZoneWest = ZONE_POLYGON:New( "CAP Zone West", GROUP:FindByName( "CAP Zone West" ) ) + -- A2ADispatcher:SetSquadronCap( "Sochi", CAPZoneWest, 4000, 8000, 600, 800, 800, 1200, "BARO" ) + -- A2ADispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 ) + -- + -- CAPZoneMiddle = ZONE:New( "CAP Zone Middle") + -- A2ADispatcher:SetSquadronCap( "Maykop", CAPZoneMiddle, 4000, 8000, 600, 800, 800, 1200, "RADIO" ) + -- A2ADispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 ) + -- + -- Note the different @{Zone} MOOSE classes being used to create zones of different types. Please click the @{Zone} link for more information about the different zone types. + -- Zones can be circles, can be setup in the mission editor using trigger zones, but can also be setup in the mission editor as polygons and in this case GROUP objects are being used! + -- + -- ## 5.2. Set the squadron to execute CAP: + -- + -- The method @{#AI_A2A_DISPATCHER.SetSquadronCap}() defines a CAP execution for a squadron. + -- + -- Setting-up a CAP zone also requires specific parameters: + -- + -- * The minimum and maximum altitude + -- * The minimum speed and maximum patrol speed + -- * The minimum and maximum engage speed + -- * The type of altitude measurement + -- + -- These define how the squadron will perform the CAP while partrolling. Different terrain types requires different types of CAP. + -- + -- The @{#AI_A2A_DISPATCHER.SetSquadronCapInterval}() 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": + -- + -- A2ADispatcher:SetSquadronCap( "Sochi", CAPZoneWest, 4000, 8000, 600, 800, 800, 1200, "BARO" ) + -- A2ADispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 ) + -- + -- ## 6. Setup a squadron for GCI: + -- + -- The method @{#AI_A2A_DISPATCHER.SetSquadronGci}() defines a GCI execution for a squadron. + -- + -- Setting-up a GCI readiness also requires specific parameters: + -- + -- * The minimum speed and maximum patrol speed + -- + -- Essentially this controls how many flights of GCI aircraft can be active at any time. + -- Note allowing large numbers of active GCI flights can adversely impact mission performance on low or medium specification hosts/servers. + -- GCI needs to be setup at strategic airbases. Too far will mean that the aircraft need to fly a long way to reach the intruders, + -- too short will mean that the intruders may have alraedy passed the ideal interception point! + -- + -- For example, the following setup will create a GCI for squadron "Sochi": + -- + -- A2ADispatcher:SetSquadronGci( "Mozdok", 900, 1200 ) + -- + -- ## 7. User Guide: + -- + -- ## 8. Questionnaire: + -- + -- ### 8.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 + -- so that the 55G6 EWR radar unit is available to blue. + -- 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. + -- + -- ### 8.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. + -- * Load outs should be appropriate to a CAP mission eg perhaps drop tanks for CAP flights and extra missiles for GCI flights. + -- * These decisions will eventually lead to template aircraft units being placed as late activation units that the script will use as templates for spawning CAP and GCI flights. Up to 4 different aircraft configurations can be chosen for each coalition. The spawned aircraft will inherit the characteristics of the template aircraft. + -- * The selected aircraft type must be able to perform the CAP tasking for the chosen country. + -- + -- + -- @field #AI_A2A_DISPATCHER + AI_A2A_DISPATCHER = { + ClassName = "AI_A2A_DISPATCHER", + Mission = nil, + Detection = nil, + Tasks = {}, + SweepZones = {}, + } + + + --- Enumerator for spawns at airbases + -- @type AI_A2A_DISPATCHER.Takeoff + -- @extends Wrapper.Group#GROUP.Takeoff + + --- @field #AI_A2A_DISPATCHER.Takeoff Takeoff + AI_A2A_DISPATCHER.Takeoff = GROUP.Takeoff + + --- Defnes Landing location. + -- @field Landing + AI_A2A_DISPATCHER.Landing = { + NearAirbase = 1, + AtRunway = 2, + AtEngineShutdown = 3, + } + + --- AI_A2A_DISPATCHER constructor. + -- @param #AI_A2A_DISPATCHER self + -- @param #string The Squadron Name. This name is used to control the squadron settings in the A2A dispatcher, and also in communication to human players. + -- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of group objects that will setup the Early Warning Radar network. + -- @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. + -- @return #AI_A2A_DISPATCHER self + -- @usage + -- + -- -- Set a new AI A2A Dispatcher object, based on an EWR network with a 6 km grouping radius. + -- + -- + function AI_A2A_DISPATCHER:New( DetectionSetGroup, GroupingRadius ) + + local Detection = DETECTION_AREAS:New( DetectionSetGroup, GroupingRadius ) + + -- Inherits from DETECTION_MANAGER + local self = BASE:Inherit( self, DETECTION_MANAGER:New( nil, Detection ) ) -- #AI_A2A_DISPATCHER + + self.Detection = Detection -- Functional.Detection#DETECTION_AREAS + + -- This table models the DefenderSquadron templates. + self.DefenderSquadrons = {} -- The Defender Squadrons. + self.DefenderSpawns = {} + self.DefenderTasks = {} -- The Defenders Tasks. + + -- TODO: Check detection through radar. + self.Detection:FilterCategories( Unit.Category.AIRPLANE, Unit.Category.HELICOPTER ) + --self.Detection:InitDetectRadar( true ) + self.Detection:SetDetectionInterval( 30 ) + + self:AddTransition( "Started", "Assign", "Started" ) + + --- OnAfter Transition Handler for Event Assign. + -- @function [parent=#AI_A2A_DISPATCHER] OnAfterAssign + -- @param #AI_A2A_DISPATCHER self + -- @param #string From The From State string. + -- @param #string Event The Event string. + -- @param #string To The To State string. + -- @param Tasking.Task_A2A#AI_A2A Task + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param #string PlayerName + + self:AddTransition( "*", "CAP", "*" ) + + --- CAP Handler OnBefore for AI_A2A_DISPATCHER + -- @function [parent=#AI_A2A_DISPATCHER] OnBeforeCAP + -- @param #AI_A2A_DISPATCHER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @return #boolean + + --- CAP Handler OnAfter for AI_A2A_DISPATCHER + -- @function [parent=#AI_A2A_DISPATCHER] OnAfterCAP + -- @param #AI_A2A_DISPATCHER self + -- @param #string From + -- @param #string Event + -- @param #string To + + --- CAP Trigger for AI_A2A_DISPATCHER + -- @function [parent=#AI_A2A_DISPATCHER] CAP + -- @param #AI_A2A_DISPATCHER self + + --- CAP Asynchronous Trigger for AI_A2A_DISPATCHER + -- @function [parent=#AI_A2A_DISPATCHER] __CAP + -- @param #AI_A2A_DISPATCHER self + -- @param #number Delay + + self:AddTransition( "*", "GCI", "*" ) + + --- GCI Handler OnBefore for AI_A2A_DISPATCHER + -- @function [parent=#AI_A2A_DISPATCHER] OnBeforeGCI + -- @param #AI_A2A_DISPATCHER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @return #boolean + + --- GCI Handler OnAfter for AI_A2A_DISPATCHER + -- @function [parent=#AI_A2A_DISPATCHER] OnAfterGCI + -- @param #AI_A2A_DISPATCHER self + -- @param #string From + -- @param #string Event + -- @param #string To + + --- GCI Trigger for AI_A2A_DISPATCHER + -- @function [parent=#AI_A2A_DISPATCHER] GCI + -- @param #AI_A2A_DISPATCHER self + + --- GCI Asynchronous Trigger for AI_A2A_DISPATCHER + -- @function [parent=#AI_A2A_DISPATCHER] __GCI + -- @param #AI_A2A_DISPATCHER self + -- @param #number Delay + + self:AddTransition( "*", "ENGAGE", "*" ) + + --- ENGAGE Handler OnBefore for AI_A2A_DISPATCHER + -- @function [parent=#AI_A2A_DISPATCHER] OnBeforeENGAGE + -- @param #AI_A2A_DISPATCHER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @return #boolean + + --- ENGAGE Handler OnAfter for AI_A2A_DISPATCHER + -- @function [parent=#AI_A2A_DISPATCHER] OnAfterENGAGE + -- @param #AI_A2A_DISPATCHER self + -- @param #string From + -- @param #string Event + -- @param #string To + + --- ENGAGE Trigger for AI_A2A_DISPATCHER + -- @function [parent=#AI_A2A_DISPATCHER] ENGAGE + -- @param #AI_A2A_DISPATCHER self + + --- ENGAGE Asynchronous Trigger for AI_A2A_DISPATCHER + -- @function [parent=#AI_A2A_DISPATCHER] __ENGAGE + -- @param #AI_A2A_DISPATCHER self + -- @param #number Delay + + + -- Subscribe to the CRASH event so that when planes are shot + -- by a Unit from the dispatcher, they will be removed from the detection... + -- This will avoid the detection to still "know" the shot unit until the next detection. + -- Otherwise, a new intercept or engage may happen for an already shot plane! + + self:HandleEvent( EVENTS.Crash, self.OnEventCrashOrDead ) + self:HandleEvent( EVENTS.Dead, self.OnEventCrashOrDead ) + + self:HandleEvent( EVENTS.Land ) + self:HandleEvent( EVENTS.EngineShutdown ) + + + self:__Start( 5 ) + + return self + end + + --- @param #AI_A2A_DISPATCHER self + -- @param Core.Event#EVENTDATA EventData + function AI_A2A_DISPATCHER:OnEventCrashOrDead( EventData ) + self.Detection:ForgetDetectedUnit( EventData.IniUnitName ) + end + + --- @param #AI_A2A_DISPATCHER self + -- @param Core.Event#EVENTDATA EventData + function AI_A2A_DISPATCHER:OnEventLand( EventData ) + local DefenderUnit = EventData.IniUnit + local Defender = EventData.IniGroup + local Squadron = self:GetSquadronFromDefender( Defender ) + if Squadron then + self:F( { SquadronName = Squadron.Name } ) + local LandingMethod = self:GetSquadronLanding( Squadron.Name ) + if LandingMethod == AI_A2A_DISPATCHER.Landing.AtRunway then + local DefenderSize = Defender:GetSize() + if DefenderSize == 1 then + self:RemoveDefenderFromSquadron( Squadron, Defender ) + end + DefenderUnit:Destroy() + return + end + if DefenderUnit:GetLife() ~= DefenderUnit:GetLife0() then + -- Damaged units cannot be repaired anymore. + DefenderUnit:Destroy() + return + end + end + end + + --- @param #AI_A2A_DISPATCHER self + -- @param Core.Event#EVENTDATA EventData + function AI_A2A_DISPATCHER:OnEventEngineShutdown( EventData ) + local DefenderUnit = EventData.IniUnit + local Defender = EventData.IniGroup + local Squadron = self:GetSquadronFromDefender( Defender ) + if Squadron then + self:F( { SquadronName = Squadron.Name } ) + local LandingMethod = self:GetSquadronLanding( Squadron.Name ) + if LandingMethod == AI_A2A_DISPATCHER.Landing.AtEngineShutdown then + local DefenderSize = Defender:GetSize() + if DefenderSize == 1 then + self:RemoveDefenderFromSquadron( Squadron, Defender ) + end + DefenderUnit:Destroy() + end + end + end + + --- Define the radius to engage any target by airborne friendlies, which are executing cap or returning from an intercept mission. + -- So, if there is a target area detected and reported, + -- then any friendlies that are airborne near this target area, + -- will be commanded to (re-)engage that target when available (if no other tasks were commanded). + -- For example, if 100000 is given as a value, then any friendly that is airborne within 100km from the detected target, + -- will be considered to receive the command to engage that target area. + -- You need to evaluate the value of this parameter carefully. + -- If too small, more intercept missions may be triggered upon detected target areas. + -- If too large, any airborne cap may not be able to reach the detected target area in time, because it is too far. + -- @param #AI_A2A_DISPATCHER self + -- @param #number FriendliesRadius The radius to report friendlies near the target. + -- @return #AI_A2A_DISPATCHER + -- @usage + -- + -- -- Set 100km as the radius to engage any target by airborne friendlies. + -- Dispatcher:InitDetectionFriendiesRadius( 100000 ) + -- + function AI_A2A_DISPATCHER:SetEngageRadius( FriendliesRadius ) + + self.Detection:SetFriendliesRange( FriendliesRadius ) + + return self + end + + --- 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. + -- If it’s a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{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_A2A_DISPATCHER self + -- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, that defines a zone between + -- @return #AI_A2A_DISPATCHER + -- @usage + -- + -- -- Set a polygon zone as the border for the A2A dispatcher. + -- local BorderZone = ZONE_POLYGON( "CCCP Border", GROUP:FindByName( "CCCP Border" ) ) -- The GROUP object is a late activate helicopter unit. + -- Dispatcher:SetBorderZone( BorderZone ) + -- + function AI_A2A_DISPATCHER:SetBorderZone( BorderZone ) + + self.Detection:SetAcceptZones( BorderZone ) + + return self + end + + --- Display a tactical report every 30 seconds about which aircraft are: + -- * Patrolling + -- * Engaging + -- * Returning + -- * Damaged + -- * Out of Fuel + -- * ... + -- @param #AI_A2A_DISPATCHER self + -- @param #boolean TacticalDisplay Provide a value of **true** to display every 30 seconds a tactical overview. + -- @return #AI_A2A_DISPATCHER + function AI_A2A_DISPATCHER:SetTacticalDisplay( TacticalDisplay ) + + self.TacticalDisplay = TacticalDisplay + + return self + end + + --- Calculates which AI friendlies are nearby the area + -- @param #AI_A2A_DISPATCHER self + -- @param DetectedItem + -- @return #number, Core.CommandCenter#REPORT + function AI_A2A_DISPATCHER:GetAIFriendliesNearBy( DetectedItem ) + + local FriendliesNearBy = self.Detection:GetFriendliesNearBy( DetectedItem ) + + return FriendliesNearBy + end + + --- + -- @param #AI_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:GetDefenderTasks() + return self.DefenderTasks or {} + end + + --- + -- @param #AI_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:GetDefenderTask( Defender ) + return self.DefenderTasks[Defender] + end + + --- + -- @param #AI_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:GetDefenderTaskFsm( Defender ) + return self:GetDefenderTask( Defender ).Fsm + end + + --- + -- @param #AI_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:GetDefenderTaskTarget( Defender ) + return self:GetDefenderTask( Defender ).Target + end + + --- + -- @param #AI_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:ClearDefenderTask( Defender ) + if Defender:IsAlive() and self.DefenderTasks[Defender] then + local Target = self.DefenderTasks[Defender].Target + local Message = "Clearing (" .. self.DefenderTasks[Defender].Type .. ") " + Message = Message .. Defender:GetName() + if Target then + Message = Message .. ( Target and ( " from " .. Target.Index .. " [" .. Target.Set:Count() .. "]" ) ) or "" + end + self:F( { Target = Message } ) + end + self.DefenderTasks[Defender] = nil + return self + end + + --- + -- @param #AI_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:ClearDefenderTaskTarget( Defender ) + + local DefenderTask = self:GetDefenderTask( Defender ) + + if Defender:IsAlive() and DefenderTask then + local Target = DefenderTask.Target + local Message = "Clearing (" .. DefenderTask.Type .. ") " + Message = Message .. Defender:GetName() + if Target then + Message = Message .. ( Target and ( " from " .. Target.Index .. " [" .. Target.Set:Count() .. "]" ) ) or "" + end + self:F( { Target = Message } ) + end + if Defender and DefenderTask and DefenderTask.Target then + DefenderTask.Target = nil + end +-- if Defender and DefenderTask then +-- if DefenderTask.Fsm:Is( "Fuel" ) +-- or DefenderTask.Fsm:Is( "LostControl") +-- or DefenderTask.Fsm:Is( "Damaged" ) then +-- self:ClearDefenderTask( Defender ) +-- end +-- end + return self + end + + + --- + -- @param #AI_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:SetDefenderTask( Defender, Type, Fsm, Target ) + + self.DefenderTasks[Defender] = self.DefenderTasks[Defender] or {} + self.DefenderTasks[Defender].Type = Type + self.DefenderTasks[Defender].Fsm = Fsm + + if Target then + self:SetDefenderTaskTarget( Defender, Target ) + end + return self + end + + + --- + -- @param #AI_A2A_DISPATCHER self + -- @param Wrapper.Group#GROUP AIGroup + function AI_A2A_DISPATCHER:SetDefenderTaskTarget( Defender, Target ) + + local Message = "(" .. self.DefenderTasks[Defender].Type .. ") " + Message = Message .. Defender:GetName() + Message = Message .. ( Target and ( " target " .. Target.Index .. " [" .. Target.Set:Count() .. "]" ) ) or "" + self:F( { Target = Message } ) + if Target then + self.DefenderTasks[Defender].Target = Target + end + return self + end + + + --- + -- @param #AI_A2A_DISPATCHER self + -- @return #AI_A2A_DISPATCHER + function AI_A2A_DISPATCHER:SetSquadron( SquadronName, AirbaseName, SpawnTemplates, Resources ) + + self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {} + + local DefenderSquadron = self.DefenderSquadrons[SquadronName] + + self:E( { AirbaseName = AirbaseName } ) + DefenderSquadron.Name = SquadronName + DefenderSquadron.Airbase = AIRBASE:FindByName( AirbaseName ) + self:E( { Airbase = DefenderSquadron.Airbase } ) + self:E( { AirbaseObject = DefenderSquadron.Airbase:GetDCSObject() } ) + + DefenderSquadron.Spawn = {} + if type( SpawnTemplates ) == "string" then + local SpawnTemplate = SpawnTemplates + self.DefenderSpawns[SpawnTemplate] = self.DefenderSpawns[SpawnTemplate] or SPAWN:New( SpawnTemplate ):InitCleanUp( 30 ) + DefenderSquadron.Spawn[1] = self.DefenderSpawns[SpawnTemplate] + else + for TemplateID, SpawnTemplate in pairs( SpawnTemplates ) do + self.DefenderSpawns[SpawnTemplate] = self.DefenderSpawns[SpawnTemplate] or SPAWN:New( SpawnTemplate ):InitCleanUp( 30 ) + DefenderSquadron.Spawn[#DefenderSquadron.Spawn+1] = self.DefenderSpawns[SpawnTemplate] + end + end + DefenderSquadron.Resources = Resources + + self:SetSquadronOverhead( SquadronName, 1 ) + self:SetSquadronTakeoffFromParkingHot( SquadronName ) + + return self + end + + --- Get an item from the Squadron table. + -- @param #AI_A2A_DISPATCHER self + -- @return #table + function AI_A2A_DISPATCHER:GetSquadron( SquadronName ) + local DefenderSquadron = self.DefenderSquadrons[SquadronName] + + if not DefenderSquadron then + error( "Unknown Squadron:" .. SquadronName ) + end + + return DefenderSquadron + end + + + --- + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The squadron name. + -- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{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_A2A_DISPATCHER + function AI_A2A_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, 2, 180, 600, 1 ) + + return self + end + + --- + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The squadron name. + -- @return #AI_A2A_DISPATCHER + function AI_A2A_DISPATCHER:SetSquadronCapInterval( SquadronName, CapLimit, LowInterval, HighInterval, Probability ) + + 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 + Cap.HighInterval = HighInterval + Cap.Probability = Probability + Cap.CapLimit = CapLimit + Cap.Scheduler = Cap.Scheduler or SCHEDULER:New( self ) + local Scheduler = Cap.Scheduler -- Core.Scheduler#SCHEDULER + local Variance = ( HighInterval - LowInterval ) / 2 + local Median = LowInterval + Variance + local Randomization = Variance / Median + Scheduler:Schedule(self, self.SchedulerCAP, { SquadronName }, Median, Median, Randomization ) + else + error( "This squadron does not exist:" .. SquadronName ) + end + + end + + --- + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The squadron name. + -- @return #AI_A2A_DISPATCHER + function AI_A2A_DISPATCHER:GetCAPDelay( SquadronName ) + + 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 + return math.random( Cap.LowInterval, Cap.HighInterval ) + else + error( "This squadron does not exist:" .. SquadronName ) + end + end + + --- + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The squadron name. + -- @return #table DefenderSquadron + function AI_A2A_DISPATCHER:CanCAP( SquadronName ) + 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.Resources > 0 then + + local Cap = DefenderSquadron.Cap + if Cap then + local CapCount = self:CountCapAirborne( SquadronName ) + if CapCount < Cap.CapLimit then + local Probability = math.random() + if Probability <= Cap.Probability then + return DefenderSquadron + end + end + end + end + return nil + end + + + --- + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The squadron name. + -- @return #table DefenderSquadron + function AI_A2A_DISPATCHER:CanGCI( SquadronName ) + 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.Resources > 0 then + local Gci = DefenderSquadron.Gci + if Gci then + return DefenderSquadron + end + end + return nil + end + + + --- + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The squadron name. + -- @param #number EngageMinSpeed The minimum speed at which the gci can be executed. + -- @param #number EngageMaxSpeed The maximum speed at which the gci can be executed. + -- @return #AI_A2A_DISPATCHER + function AI_A2A_DISPATCHER:SetSquadronGci( SquadronName, EngageMinSpeed, EngageMaxSpeed ) + + self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {} + self.DefenderSquadrons[SquadronName].Gci = self.DefenderSquadrons[SquadronName].Gci or {} + + local Intercept = self.DefenderSquadrons[SquadronName].Gci + Intercept.Name = SquadronName + Intercept.EngageMinSpeed = EngageMinSpeed + Intercept.EngageMaxSpeed = EngageMaxSpeed + end + + --- Defines the amount of extra planes that will take-off as part of the defense system. + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The name of the squadron. + -- @param #number Overhead The %-tage of Units that dispatching command will allocate to intercept in surplus of detected amount of units. + -- The default overhead is 1, so equal balance. The @{#AI_A2A_DISPATCHER.SetOverhead}() method can be used to tweak the defense strength, + -- taking into account the plane types of the squadron. For example, a MIG-31 with full long-distance A2A missiles payload, may still be less effective than a F-15C with short missiles... + -- So in this case, one may want to use the Overhead method to allocate more defending planes as the amount of detected attacking planes. + -- The overhead must be given as a decimal value with 1 as the neutral value, which means that Overhead values: + -- + -- * Higher than 1, will increase the defense unit amounts. + -- * Lower than 1, will decrease the defense unit amounts. + -- + -- The amount of defending units is calculated by multiplying the amount of detected attacking planes as part of the detected group + -- multiplied by the Overhead and rounded up to the smallest integer. + -- + -- The Overhead value set for a Squadron, can be programmatically adjusted (by using this SetOverhead method), to adjust the defense overhead during mission execution. + -- + -- See example below. + -- + -- @usage: + -- + -- local Dispatcher = AI_A2A_DISPATCHER:New( ... ) + -- + -- -- An overhead of 1,5 with 1 planes detected, will allocate 2 planes ( 1 * 1,5 ) = 1,5 => rounded up gives 2. + -- -- An overhead of 1,5 with 2 planes detected, will allocate 3 planes ( 2 * 1,5 ) = 3 => rounded up gives 3. + -- -- An overhead of 1,5 with 3 planes detected, will allocate 5 planes ( 3 * 1,5 ) = 4,5 => rounded up gives 5 planes. + -- -- An overhead of 1,5 with 4 planes detected, will allocate 6 planes ( 4 * 1,5 ) = 6 => rounded up gives 6 planes. + -- + -- Dispatcher:SetSquadronOverhead( 1,5 ) + -- + -- + -- @return #AI_A2A_DISPATCHER + function AI_A2A_DISPATCHER:SetSquadronOverhead( SquadronName, Overhead ) + + local DefenderSquadron = self:GetSquadron( SquadronName ) + DefenderSquadron.Overhead = Overhead + + return self + end + + --- + -- @param #AI_A2A_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. + -- @usage: + -- + -- local Dispatcher = AI_A2A_DISPATCHER:New( ... ) + -- Dispatcher:SetSquadronGrouping( "SquadronName", 2 ) + -- + -- + -- @return #AI_A2A_DISPATCHER + function AI_A2A_DISPATCHER:SetSquadronGrouping( SquadronName, Grouping ) + + local DefenderSquadron = self:GetSquadron( SquadronName ) + DefenderSquadron.Grouping = Grouping + + return self + end + + --- Defines the method at which new flights will spawn and take-off as part of the defense system. + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The name of the squadron. + -- @param #number Takeoff From the airbase hot, from the airbase cold, in the air, from the runway. + -- @usage: + -- + -- local Dispatcher = AI_A2A_DISPATCHER:New( ... ) + -- + -- -- Let new flights take-off in the air. + -- Dispatcher:SetSquadronTakeoff( "SquadronName", AI_A2A_Dispatcher.Takeoff.Air ) + -- + -- -- Let new flights take-off from the runway. + -- Dispatcher:SetSquadronTakeoff( "SquadronName", AI_A2A_Dispatcher.Takeoff.Runway ) + -- + -- -- Let new flights take-off from the airbase hot. + -- Dispatcher:SetSquadronTakeoff( "SquadronName", AI_A2A_Dispatcher.Takeoff.Hot ) + -- + -- -- Let new flights take-off from the airbase cold. + -- Dispatcher:SetSquadronTakeoff( "SquadronName", AI_A2A_Dispatcher.Takeoff.Cold ) + -- + -- + -- @return #AI_A2A_DISPATCHER + -- + function AI_A2A_DISPATCHER:SetSquadronTakeoff( SquadronName, Takeoff ) + + local DefenderSquadron = self:GetSquadron( SquadronName ) + DefenderSquadron.Takeoff = Takeoff + + return self + end + + + --- Gets the method at which new flights will spawn and take-off as part of the defense system. + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The name of the squadron. + -- @return #number Takeoff From the airbase hot, from the airbase cold, in the air, from the runway. + -- @usage: + -- + -- local Dispatcher = AI_A2A_DISPATCHER:New( ... ) + -- + -- -- Let new flights take-off in the air. + -- local TakeoffMethod = Dispatcher:GetSquadronTakeoff( "SquadronName" ) + -- if TakeOffMethod == , AI_A2A_Dispatcher.Takeoff.InAir then + -- ... + -- end + -- + function AI_A2A_DISPATCHER:GetSquadronTakeoff( SquadronName ) + + local DefenderSquadron = self:GetSquadron( SquadronName ) + return DefenderSquadron.Takeoff + end + + + --- Sets flights to take-off in the air, as part of the defense system. + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The name of the squadron. + -- @usage: + -- + -- local Dispatcher = AI_A2A_DISPATCHER:New( ... ) + -- + -- -- Let new flights take-off in the air. + -- Dispatcher:SetSquadronTakeoffInAir( "SquadronName" ) + -- + -- @return #AI_A2A_DISPATCHER + -- + function AI_A2A_DISPATCHER:SetSquadronTakeoffInAir( SquadronName ) + + self:SetSquadronTakeoff( SquadronName, AI_A2A_DISPATCHER.Takeoff.Air ) + + return self + end + + + --- Sets flights to take-off from the runway, as part of the defense system. + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The name of the squadron. + -- @usage: + -- + -- local Dispatcher = AI_A2A_DISPATCHER:New( ... ) + -- + -- -- Let new flights take-off in the air. + -- Dispatcher:SetSquadronTakeoffFromRunway( "SquadronName" ) + -- + -- @return #AI_A2A_DISPATCHER + -- + function AI_A2A_DISPATCHER:SetSquadronTakeoffFromRunway( SquadronName ) + + self:SetSquadronTakeoff( SquadronName, AI_A2A_DISPATCHER.Takeoff.Runway ) + + return self + end + + + --- Sets flights to take-off from the airbase at a hot location, as part of the defense system. + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The name of the squadron. + -- @usage: + -- + -- local Dispatcher = AI_A2A_DISPATCHER:New( ... ) + -- + -- -- Let new flights take-off in the air. + -- Dispatcher:SetSquadronTakeoffFromParkingHot( "SquadronName" ) + -- + -- @return #AI_A2A_DISPATCHER + -- + function AI_A2A_DISPATCHER:SetSquadronTakeoffFromParkingHot( SquadronName ) + + self:SetSquadronTakeoff( SquadronName, AI_A2A_DISPATCHER.Takeoff.Hot ) + + return self + end + + --- Sets flights to take-off from the airbase at a cold location, as part of the defense system. + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The name of the squadron. + -- @usage: + -- + -- local Dispatcher = AI_A2A_DISPATCHER:New( ... ) + -- + -- -- Let new flights take-off in the air. + -- Dispatcher:SetSquadronTakeoffFromParkingCold( "SquadronName" ) + -- + -- @return #AI_A2A_DISPATCHER + -- + function AI_A2A_DISPATCHER:SetSquadronTakeoffFromParkingCold( SquadronName ) + + self:SetSquadronTakeoff( SquadronName, AI_A2A_DISPATCHER.Takeoff.Cold ) + + return self + end + + + --- Defines the method at which flights will land and despawn as part of the defense system. + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The name of the squadron. + -- @param #number Landing The landing method which can be NearAirbase, AtRunway, AtEngineShutdown + -- @usage: + -- + -- local Dispatcher = AI_A2A_DISPATCHER:New( ... ) + -- + -- -- Let new flights take-off in the air. + -- Dispatcher:SetSquadronLanding( "SquadronName", AI_A2A_Dispatcher.Landing.NearAirbase ) + -- + -- -- Let new flights take-off from the runway. + -- Dispatcher:SetSquadronLanding( "SquadronName", AI_A2A_Dispatcher.Landing.AtRunway ) + -- + -- -- Let new flights take-off from the airbase hot. + -- Dispatcher:SetSquadronLanding( "SquadronName", AI_A2A_Dispatcher.Landing.AtEngineShutdown ) + -- + -- @return #AI_A2A_DISPATCHER + function AI_A2A_DISPATCHER:SetSquadronLanding( SquadronName, Landing ) + + local DefenderSquadron = self:GetSquadron( SquadronName ) + DefenderSquadron.Landing = Landing + + return self + end + + + --- Gets the method at which flights will land and despawn as part of the defense system. + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The name of the squadron. + -- @return #number Landing The landing method which can be NearAirbase, AtRunway, AtEngineShutdown + -- @usage: + -- + -- local Dispatcher = AI_A2A_DISPATCHER:New( ... ) + -- + -- -- Let new flights take-off in the air. + -- local LandingMethod = Dispatcher:GetSquadronLanding( "SquadronName", AI_A2A_Dispatcher.Landing.NearAirbase ) + -- if LandingMethod == AI_A2A_Dispatcher.Landing.NearAirbase then + -- ... + -- end + -- + function AI_A2A_DISPATCHER:GetSquadronLanding( SquadronName ) + + local DefenderSquadron = self:GetSquadron( SquadronName ) + return DefenderSquadron.Landing + end + + + --- Sets flights to land and despawn near the airbase in the air, as part of the defense system. + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The name of the squadron. + -- @usage: + -- + -- local Dispatcher = AI_A2A_DISPATCHER:New( ... ) + -- + -- -- Let flights land in the air and despawn. + -- Dispatcher:SetSquadronLandingNearAirbase( "SquadronName" ) + -- + -- @return #AI_A2A_DISPATCHER + function AI_A2A_DISPATCHER:SetSquadronLandingNearAirbase( SquadronName ) + + self:SetSquadronLanding( SquadronName, AI_A2A_DISPATCHER.Landing.NearAirbase ) + + return self + end + + + --- Sets flights to land and despawn at the runway, as part of the defense system. + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The name of the squadron. + -- @usage: + -- + -- local Dispatcher = AI_A2A_DISPATCHER:New( ... ) + -- + -- -- Let flights land at the runway and despawn. + -- Dispatcher:SetSquadronLandingAtRunway( "SquadronName" ) + -- + -- @return #AI_A2A_DISPATCHER + function AI_A2A_DISPATCHER:SetSquadronLandingAtRunway( SquadronName ) + + self:SetSquadronLanding( SquadronName, AI_A2A_DISPATCHER.Landing.AtRunway ) + + return self + end + + + --- Sets flights to land and despawn at engine shutdown, as part of the defense system. + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The name of the squadron. + -- @usage: + -- + -- local Dispatcher = AI_A2A_DISPATCHER:New( ... ) + -- + -- -- Let flights land and despawn at engine shutdown. + -- Dispatcher:SetSquadronLandingAtEngineShutdown( "SquadronName" ) + -- + -- @return #AI_A2A_DISPATCHER + function AI_A2A_DISPATCHER:SetSquadronLandingAtEngineShutdown( SquadronName ) + + self:SetSquadronLanding( SquadronName, AI_A2A_DISPATCHER.Landing.AtEngineShutdown ) + + return self + end + + + --- @param #AI_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:AddDefenderToSquadron( Squadron, Defender ) + self.Defenders = self.Defenders or {} + local DefenderName = Defender:GetName() + self.Defenders[ DefenderName ] = Squadron + Squadron.Resources = Squadron.Resources - Defender:GetSize() + self:F( { DefenderName = DefenderName, SquadronResources = Squadron.Resources } ) + end + + --- @param #AI_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:RemoveDefenderFromSquadron( Squadron, Defender ) + self.Defenders = self.Defenders or {} + local DefenderName = Defender:GetName() + Squadron.Resources = Squadron.Resources + Defender:GetSize() + self.Defenders[ DefenderName ] = nil + self:F( { DefenderName = DefenderName, SquadronResources = Squadron.Resources } ) + end + + function AI_A2A_DISPATCHER:GetSquadronFromDefender( Defender ) + self.Defenders = self.Defenders or {} + local DefenderName = Defender:GetName() + self:F( { DefenderName = DefenderName } ) + return self.Defenders[ DefenderName ] + end + + + --- Creates an SWEEP task when there are targets for it. + -- @param #AI_A2A_DISPATCHER self + -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem + -- @return Set#SET_UNIT TargetSetUnit: The target set of units. + -- @return #nil If there are no targets to be set. + function AI_A2A_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_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:CountCapAirborne( SquadronName ) + + local CapCount = 0 + + local DefenderSquadron = self.DefenderSquadrons[SquadronName] + if DefenderSquadron then + for AIGroup, DefenderTask in pairs( self:GetDefenderTasks() ) do + if DefenderTask.Type == "CAP" 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! + if DefenderTask.Fsm:Is( "Patrolling" ) or DefenderTask.Fsm:Is( "Engaging" ) then + CapCount = CapCount + 1 + end + end + end + end + end + + return CapCount + end + + + --- + -- @param #AI_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:CountDefendersEngaged( Target ) + + -- First, count the active AIGroups Units, targetting the DetectedSet + local AIUnitCount = 0 + + local DefenderTasks = self:GetDefenderTasks() + for AIGroup, DefenderTask in pairs( DefenderTasks ) do + local AIGroup = AIGroup -- Wrapper.Group#GROUP + local DefenderTask = self:GetDefenderTaskTarget( AIGroup ) + if DefenderTask and DefenderTask.Index == Target.Index then + AIUnitCount = AIUnitCount + AIGroup:GetSize() + end + end + + return AIUnitCount + end + + --- + -- @param #AI_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:CountDefendersToBeEngaged( DetectedItem, DefenderCount ) + + local Friendlies = nil + + local DetectedSet = DetectedItem.Set + local DetectedCount = DetectedSet:Count() + + local AIFriendlies = self:GetAIFriendliesNearBy( DetectedItem ) + + for FriendlyDistance, AIFriendly in UTILS.spairs( AIFriendlies or {} ) do + -- We only allow to ENGAGE targets as long as the Units on both sides are balanced. + if DetectedCount > 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 TargetSet + 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_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:onafterCAP( From, Event, To, SquadronName ) + + 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 ) + + if DefenderSquadron then + + local Cap = DefenderSquadron.Cap + + if Cap then + + local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] + Spawn:InitGrouping( DefenderSquadron.Grouping ) + + local TakeoffMethod = self:GetSquadronTakeoff( SquadronName ) + local DefenderCAP = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod ) + self:AddDefenderToSquadron( DefenderSquadron, DefenderCAP ) + + if DefenderCAP then + + local Fsm = AI_A2A_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:Start() + Fsm:__Patrol( 1 ) + + self:SetDefenderTask( DefenderCAP, "CAP", Fsm ) + end + end + end + + end + + + --- + -- @param #AI_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:onafterENGAGE( From, Event, To, Target, AIGroups ) + + if AIGroups then + + for AIGroupID, AIGroup in pairs( AIGroups ) do + + local Fsm = self:GetDefenderTaskFsm( AIGroup ) + Fsm:__Engage( 1, Target.Set ) -- Engage on the TargetSetUnit + + self:SetDefenderTaskTarget( AIGroup, Target ) + + function Fsm:onafterRTB( AIGroup, From, Event, To ) + self:F({"CAP RTB"}) + self:GetParent(self).onafterRTB( self, AIGroup, From, Event, To ) + local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER + local AIGroup = self:GetControllable() + Dispatcher:ClearDefenderTaskTarget( AIGroup ) + end + + --- @param #AI_A2A_DISPATCHER self + function Fsm:onafterHome( Defender, From, Event, To ) + self:F({"CAP Home"}) + self:GetParent(self).onafterHome( self, Defender, From, Event, To ) + + local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER + local AIGroup = self:GetControllable() + local Squadron = Dispatcher:GetSquadronFromDefender( AIGroup ) + if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2A_DISPATCHER.Landing.NearAirbase then + Dispatcher:RemoveDefenderFromSquadron( Squadron, AIGroup ) + AIGroup:Destroy() + end + end + + end + end + end + + --- + -- @param #AI_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:onafterGCI( From, Event, To, Target, DefendersMissing, AIGroups ) + + local ClosestDistance = 0 + local ClosestDefenderSquadronName = nil + + local AttackerCount = Target.Set:Count() + local DefendersCount = 0 + + for AIGroupID, AIGroup in pairs( AIGroups or {} ) do + + local Fsm = self:GetDefenderTaskFsm( AIGroup ) + Fsm:__Engage( 1, Target.Set ) -- Engage on the TargetSetUnit + + self:SetDefenderTaskTarget( AIGroup, Target ) + + DefendersCount = DefendersCount + AIGroup:GetSize() + end + + DefendersCount = DefendersMissing + while( DefendersCount > 0 ) do + + for SquadronName, DefenderSquadron in pairs( self.DefenderSquadrons or {} ) do + for InterceptID, Intercept in pairs( DefenderSquadron.Gci or {} ) do + + local SpawnCoord = DefenderSquadron.Airbase:GetCoordinate() -- Core.Point#COORDINATE + local TargetCoord = Target.Set:GetFirst():GetCoordinate() + local Distance = SpawnCoord:Get2DDistance( TargetCoord ) + + if ClosestDistance == 0 or Distance < ClosestDistance then + ClosestDistance = Distance + ClosestDefenderSquadronName = SquadronName + end + end + end + + if ClosestDefenderSquadronName then + + local DefenderSquadron = self:CanGCI( ClosestDefenderSquadronName ) + + if DefenderSquadron then + + local Gci = self.DefenderSquadrons[ClosestDefenderSquadronName].Gci + + if Gci then + + local DefenderOverhead = DefenderSquadron.Overhead + local DefenderGrouping = DefenderSquadron.Grouping + local DefendersNeeded = math.ceil( DefendersCount * DefenderOverhead ) + + local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] + if DefenderGrouping then + Spawn:InitGrouping( ( DefenderGrouping < DefendersNeeded ) and DefenderGrouping or DefendersNeeded ) + else + Spawn:InitGrouping() + end + + local TakeoffMethod = self:GetSquadronTakeoff( ClosestDefenderSquadronName ) + local DefenderGCI = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod ) + self:F( { GCIDefender = DefenderGCI:GetName() } ) + + self:AddDefenderToSquadron( DefenderSquadron, DefenderGCI ) + + + if DefenderGCI then + + DefendersCount = DefendersCount - DefenderGCI:GetSize() + + local Fsm = AI_A2A_GCI:New( DefenderGCI, Gci.EngageMinSpeed, Gci.EngageMaxSpeed ) + Fsm:SetDispatcher( self ) + Fsm:SetHomeAirbase( DefenderSquadron.Airbase ) + Fsm:Start() + Fsm:__Engage( 1, Target.Set ) -- Engage on the TargetSetUnit + + + self:SetDefenderTask( DefenderGCI, "GCI", Fsm, Target ) + + + function Fsm:onafterRTB( Defender, From, Event, To ) + self:F({"GCI RTB"}) + self:GetParent(self).onafterRTB( self, Defender, From, Event, To ) + + local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER + local AIGroup = self:GetControllable() + Dispatcher:ClearDefenderTaskTarget( AIGroup ) + end + + --- @param #AI_A2A_DISPATCHER self + function Fsm:onafterHome( Defender, From, Event, To ) + self:F({"GCI Home"}) + self:GetParent(self).onafterHome( self, Defender, From, Event, To ) + + local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER + local AIGroup = self:GetControllable() + local Squadron = Dispatcher:GetSquadronFromDefender( AIGroup ) + if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2A_DISPATCHER.Landing.NearAirbase then + Dispatcher:RemoveDefenderFromSquadron( Squadron, AIGroup ) + AIGroup:Destroy() + end + end + end + end + end + end + end + end + + + + --- Creates an ENGAGE task when there are human friendlies airborne near the targets. + -- @param #AI_A2A_DISPATCHER self + -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem + -- @return Set#SET_UNIT TargetSetUnit: The target set of units. + -- @return #nil If there are no targets to be set. + function AI_A2A_DISPATCHER:EvaluateENGAGE( DetectedItem ) + self:F( { DetectedItem.ItemID } ) + + -- First, count the active AIGroups Units, targetting the DetectedSet + local DefenderCount = self:CountDefendersEngaged( DetectedItem ) + local DefenderGroups = self:CountDefendersToBeEngaged( DetectedItem, DefenderCount ) + + self:F( { DefenderCount = DefenderCount } ) + + -- Only allow ENGAGE when: + -- 1. There are friendly units near the detected attackers. + -- 2. There is sufficient fuel + -- 3. There is sufficient ammo + -- 4. The plane is not damaged + if DefenderGroups and DetectedItem.IsDetected == true then + + return DefenderGroups + end + + return nil, nil + end + + --- Creates an GCI task when there are targets for it. + -- @param #AI_A2A_DISPATCHER self + -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem + -- @return Set#SET_UNIT TargetSetUnit: The target set of units. + -- @return #nil If there are no targets to be set. + function AI_A2A_DISPATCHER:EvaluateGCI( Target ) + self:F( { Target.ItemID } ) + + local AttackerSet = Target.Set + local AttackerCount = AttackerSet:Count() + + -- First, count the active AIGroups Units, targetting the DetectedSet + local DefenderCount = self:CountDefendersEngaged( Target ) + local DefendersMissing = AttackerCount - DefenderCount + self:F( { AttackerCount = AttackerCount, DefenderCount = DefenderCount, DefendersMissing = DefendersMissing } ) + + local Friendlies = self:CountDefendersToBeEngaged( Target, DefenderCount ) + + if Target.IsDetected == true then + + return DefendersMissing, Friendlies + end + + return nil, nil + end + + + --- Assigns A2A AI Tasks in relation to the detected items. + -- @param #AI_A2A_DISPATCHER self + -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Detection#DETECTION_BASE} derived object. + -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. + function AI_A2A_DISPATCHER:ProcessDetected( Detection ) + + local AreaMsg = {} + local TaskMsg = {} + local ChangeMsg = {} + + local TaskReport = REPORT:New() + + + for AIGroup, DefenderTask in pairs( self:GetDefenderTasks() ) do + local AIGroup = AIGroup -- Wrapper.Group#GROUP + if not AIGroup:IsAlive() then + self:ClearDefenderTask( AIGroup ) + else + if DefenderTask.Target then + local Target = Detection:GetDetectedItem( DefenderTask.Target.Index ) + if not Target then + self:F( { "Removing obsolete Target:", DefenderTask.Target.Index } ) + self:ClearDefenderTaskTarget( AIGroup ) + + else + if DefenderTask.Target.Set then + if DefenderTask.Target.Set:Count() == 0 then + self:F( { "All Targets destroyed in Target, removing:", DefenderTask.Target.Index } ) + self:ClearDefenderTaskTarget( AIGroup ) + end + end + end + end + end + end + + local Report = REPORT:New( "\nTactical Overview" ) + + -- Now that all obsolete tasks are removed, loop through the detected targets. + for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do + + local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem + local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT + local DetectedCount = DetectedSet:Count() + local DetectedZone = DetectedItem.Zone + + self:F( { "Target ID", DetectedItem.ItemID } ) + DetectedSet:Flush() + + local DetectedID = DetectedItem.ID + local DetectionIndex = DetectedItem.Index + local DetectedItemChanged = DetectedItem.Changed + + do + local Friendlies = self:EvaluateENGAGE( DetectedItem ) -- Returns a SetUnit if there are targets to be GCIed... + if Friendlies then + self:F( { AIGroups = Friendlies } ) + self:ENGAGE( DetectedItem, Friendlies ) + end + end + + do + local DefendersMissing, Friendlies = self:EvaluateGCI( DetectedItem ) + if DefendersMissing then + self:F( { DefendersMissing = DefendersMissing } ) + self:GCI( DetectedItem, DefendersMissing, Friendlies ) + end + end + + -- Show tactical situation + Report:Add( string.format( "\n - Target %s ( %s ): %s" , DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:GetObjectNames() ) ) + for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do + local Defender = Defender -- Wrapper.Group#GROUP + if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then + Report:Add( string.format( " - %s ( %s - %s ) %s", Defender:GetName(), DefenderTask.Type, DefenderTask.Fsm:GetState(), Defender:HasTask() == true and "Executing" or "Idle" ) ) + end + end + end + + Report:Add( "\n - No Targets:") + local TaskCount = 0 + for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do + TaskCount = TaskCount + 1 + local Defender = Defender -- Wrapper.Group#GROUP + if not DefenderTask.Target then + local DefenderHasTask = Defender:HasTask() + Report:Add( string.format( " - %s ( %s - %s ) %s", Defender:GetName(), DefenderTask.Type, DefenderTask.Fsm:GetState(), Defender:HasTask() == true and "Executing" or "Idle" ) ) + end + end + Report:Add( string.format( "\n - %d Tasks", TaskCount ) ) + + self:T( Report:Text( "\n" ) ) + trigger.action.outText( Report:Text( "\n" ), 25 ) + + return true + end + +end + +do + + --- Calculates which HUMAN friendlies are nearby the area + -- @param #AI_A2A_DISPATCHER self + -- @param DetectedItem + -- @return #number, Core.CommandCenter#REPORT + function AI_A2A_DISPATCHER:GetPlayerFriendliesNearBy( DetectedItem ) + + local DetectedSet = DetectedItem.Set + local PlayersNearBy = self.Detection:GetPlayersNearBy( DetectedItem ) + + local PlayerTypes = {} + local PlayersCount = 0 + + if PlayersNearBy then + local DetectedTreatLevel = DetectedSet:CalculateThreatLevelA2G() + for PlayerUnitName, PlayerUnitData in pairs( PlayersNearBy ) do + local PlayerUnit = PlayerUnitData -- Wrapper.Unit#UNIT + local PlayerName = PlayerUnit:GetPlayerName() + --self:E( { PlayerName = PlayerName, PlayerUnit = PlayerUnit } ) + if PlayerUnit:IsAirPlane() and PlayerName ~= nil then + local FriendlyUnitThreatLevel = PlayerUnit:GetThreatLevel() + PlayersCount = PlayersCount + 1 + local PlayerType = PlayerUnit:GetTypeName() + PlayerTypes[PlayerName] = PlayerType + if DetectedTreatLevel < FriendlyUnitThreatLevel + 2 then + end + end + end + + end + + --self:E( { PlayersCount = PlayersCount } ) + + local PlayerTypesReport = REPORT:New() + + if PlayersCount > 0 then + for PlayerName, PlayerType in pairs( PlayerTypes ) do + PlayerTypesReport:Add( string.format('"%s" in %s', PlayerName, PlayerType ) ) + end + else + PlayerTypesReport:Add( "-" ) + end + + + return PlayersCount, PlayerTypesReport + end + + --- Calculates which friendlies are nearby the area + -- @param #AI_A2A_DISPATCHER self + -- @param DetectedItem + -- @return #number, Core.CommandCenter#REPORT + function AI_A2A_DISPATCHER:GetFriendliesNearBy( Target ) + + local DetectedSet = Target.Set + local FriendlyUnitsNearBy = self.Detection:GetFriendliesNearBy( Target ) + + local FriendlyTypes = {} + local FriendliesCount = 0 + + if FriendlyUnitsNearBy then + local DetectedTreatLevel = DetectedSet:CalculateThreatLevelA2G() + for FriendlyUnitName, FriendlyUnitData in pairs( FriendlyUnitsNearBy ) do + local FriendlyUnit = FriendlyUnitData -- Wrapper.Unit#UNIT + if FriendlyUnit:IsAirPlane() then + local FriendlyUnitThreatLevel = FriendlyUnit:GetThreatLevel() + FriendliesCount = FriendliesCount + 1 + local FriendlyType = FriendlyUnit:GetTypeName() + FriendlyTypes[FriendlyType] = FriendlyTypes[FriendlyType] and ( FriendlyTypes[FriendlyType] + 1 ) or 1 + if DetectedTreatLevel < FriendlyUnitThreatLevel + 2 then + end + end + end + + end + + --self:E( { FriendliesCount = FriendliesCount } ) + + local FriendlyTypesReport = REPORT:New() + + if FriendliesCount > 0 then + for FriendlyType, FriendlyTypeCount in pairs( FriendlyTypes ) do + FriendlyTypesReport:Add( string.format("%d of %s", FriendlyTypeCount, FriendlyType ) ) + end + else + FriendlyTypesReport:Add( "-" ) + end + + + return FriendliesCount, FriendlyTypesReport + end + + --- + -- @param AI_A2A_DISPATCHER + -- @param #string SquadronName The squadron name. + function AI_A2A_DISPATCHER:SchedulerCAP( SquadronName ) + self:CAP( SquadronName ) + end + +end \ No newline at end of file diff --git a/Moose Development/Moose/AI/AI_A2A_Gci.lua b/Moose Development/Moose/AI/AI_A2A_Gci.lua new file mode 100644 index 000000000..60da2645c --- /dev/null +++ b/Moose Development/Moose/AI/AI_A2A_Gci.lua @@ -0,0 +1,462 @@ +--- **AI** -- **Execute Ground Controlled Interception (GCI).** +-- +-- ![Banner Image](..\Presentations\AI_GCI\Dia1.JPG) +-- +-- === +-- +-- AI A2A_INTEREPT class makes AI Groups execute an Intercept. +-- +-- There are the following types of GCI classes defined: +-- +-- * @{#AI_A2A_GCI}: Perform a GCI in a zone. +-- +-- ==== +-- +-- ### Author: **Sven Van de Velde (FlightControl)** +-- +-- ### Contributions: +-- +-- ==== +-- +-- @module AI_A2A_GCI + + +--BASE:TraceClass("AI_A2A_GCI") + + +--- @type AI_A2A_GCI +-- @extends AI.AI_A2A#AI_A2A + + +--- # AI_A2A_GCI class, extends @{AI_A2A#AI_A2A} +-- +-- The AI_A2A_GCI class implements the core functions to intercept intruders. The Engage function will intercept intruders. +-- +-- ![Process](..\Presentations\AI_GCI\Dia3.JPG) +-- +-- The AI_A2A_GCI is assigned a @{Group} and this must be done before the AI_A2A_GCI process can be started using the **Start** event. +-- +-- ![Process](..\Presentations\AI_GCI\Dia4.JPG) +-- +-- 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. +-- +-- ![Process](..\Presentations\AI_GCI\Dia5.JPG) +-- +-- This cycle will continue. +-- +-- ![Process](..\Presentations\AI_GCI\Dia6.JPG) +-- +-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event. +-- +-- ![Process](..\Presentations\AI_GCI\Dia9.JPG) +-- +-- When enemies are detected, the AI will automatically engage the enemy. +-- +-- ![Process](..\Presentations\AI_GCI\Dia10.JPG) +-- +-- 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. +-- +-- ![Process](..\Presentations\AI_GCI\Dia13.JPG) +-- +-- ## 1. AI_A2A_GCI constructor +-- +-- * @{#AI_A2A_GCI.New}(): Creates a new AI_A2A_GCI object. +-- +-- ## 2. AI_A2A_GCI is a FSM +-- +-- ![Process](..\Presentations\AI_GCI\Dia2.JPG) +-- +-- ### 2.1 AI_A2A_GCI 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_A2A_GCI Events +-- +-- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. +-- * **@{#AI_A2A_GCI.Engage}**: Let the AI engage the bogeys. +-- * **@{#AI_A2A_GCI.Abort}**: Aborts the engagement and return patrolling in the patrol zone. +-- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. +-- * **@{#AI_A2A_GCI.Destroy}**: The AI has destroyed a bogey @{Unit}. +-- * **@{#AI_A2A_GCI.Destroyed}**: The AI has destroyed all bogeys @{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 +-- +-- ![Range](..\Presentations\AI_GCI\Dia11.JPG) +-- +-- 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_GCI#AI_A2A_GCI.SetEngageRange}() to define that range. +-- +-- ## 4. Set the Zone of Engagement +-- +-- ![Zone](..\Presentations\AI_GCI\Dia12.JPG) +-- +-- An optional @{Zone} can be set, +-- that will define when the AI will engage with the detected airborne enemy targets. +-- Use the method @{AI_Cap#AI_A2A_GCI.SetEngageZone}() to define that Zone. +-- +-- === +-- +-- @field #AI_A2A_GCI +AI_A2A_GCI = { + ClassName = "AI_A2A_GCI", +} + + + +--- Creates a new AI_A2A_GCI object +-- @param #AI_A2A_GCI self +-- @param Wrapper.Group#GROUP AIGroup +-- @return #AI_A2A_GCI +function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed ) + + -- Inherits from BASE + local self = BASE:Inherit( self, AI_A2A:New( AIGroup ) ) -- #AI_A2A_GCI + + self.Accomplished = false + self.Engaging = false + + self.EngageMinSpeed = EngageMinSpeed + self.EngageMaxSpeed = EngageMaxSpeed + self.PatrolMinSpeed = EngageMinSpeed + self.PatrolMaxSpeed = EngageMaxSpeed + + self.PatrolAltType = "RADIO" + + self:AddTransition( { "Started", "Engaging", "Returning" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI. + + --- OnBefore Transition Handler for Event Engage. + -- @function [parent=#AI_A2A_GCI] OnBeforeEngage + -- @param #AI_A2A_GCI self + -- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI] OnAfterEngage + -- @param #AI_A2A_GCI self + -- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI] Engage + -- @param #AI_A2A_GCI self + + --- Asynchronous Event Trigger for Event Engage. + -- @function [parent=#AI_A2A_GCI] __Engage + -- @param #AI_A2A_GCI self + -- @param #number Delay The delay in seconds. + +--- OnLeave Transition Handler for State Engaging. +-- @function [parent=#AI_A2A_GCI] OnLeaveEngaging +-- @param #AI_A2A_GCI self +-- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI] OnEnterEngaging +-- @param #AI_A2A_GCI self +-- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI. + + --- OnBefore Transition Handler for Event Fired. + -- @function [parent=#AI_A2A_GCI] OnBeforeFired + -- @param #AI_A2A_GCI self + -- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI] OnAfterFired + -- @param #AI_A2A_GCI self + -- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI] Fired + -- @param #AI_A2A_GCI self + + --- Asynchronous Event Trigger for Event Fired. + -- @function [parent=#AI_A2A_GCI] __Fired + -- @param #AI_A2A_GCI self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI. + + --- OnBefore Transition Handler for Event Destroy. + -- @function [parent=#AI_A2A_GCI] OnBeforeDestroy + -- @param #AI_A2A_GCI self + -- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI] OnAfterDestroy + -- @param #AI_A2A_GCI self + -- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI] Destroy + -- @param #AI_A2A_GCI self + + --- Asynchronous Event Trigger for Event Destroy. + -- @function [parent=#AI_A2A_GCI] __Destroy + -- @param #AI_A2A_GCI self + -- @param #number Delay The delay in seconds. + + + self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI. + + --- OnBefore Transition Handler for Event Abort. + -- @function [parent=#AI_A2A_GCI] OnBeforeAbort + -- @param #AI_A2A_GCI self + -- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI] OnAfterAbort + -- @param #AI_A2A_GCI self + -- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI] Abort + -- @param #AI_A2A_GCI self + + --- Asynchronous Event Trigger for Event Abort. + -- @function [parent=#AI_A2A_GCI] __Abort + -- @param #AI_A2A_GCI self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI. + + --- OnBefore Transition Handler for Event Accomplish. + -- @function [parent=#AI_A2A_GCI] OnBeforeAccomplish + -- @param #AI_A2A_GCI self + -- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI] OnAfterAccomplish + -- @param #AI_A2A_GCI self + -- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI] Accomplish + -- @param #AI_A2A_GCI self + + --- Asynchronous Event Trigger for Event Accomplish. + -- @function [parent=#AI_A2A_GCI] __Accomplish + -- @param #AI_A2A_GCI self + -- @param #number Delay The delay in seconds. + + return self +end + + +--- onafter State Transition for Event Patrol. +-- @param #AI_A2A_GCI self +-- @param Wrapper.Group#GROUP AIGroup 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_A2A_GCI:onafterEngage( AIGroup, From, Event, To ) + + self:HandleEvent( EVENTS.Dead ) + +end + +-- todo: need to fix this global function + +--- @param Wrapper.Group#GROUP AIControllable +function AI_A2A_GCI.InterceptRoute( AIControllable ) + + AIControllable:T( "NewEngageRoute" ) + local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cap#AI_A2A_GCI + EngageZone:__Engage( 0.5 ) +end + +--- @param #AI_A2A_GCI self +-- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI:onbeforeEngage( AIGroup, From, Event, To ) + + if self.Accomplished == true then + return false + end +end + +--- @param #AI_A2A_GCI self +-- @param Wrapper.Group#GROUP AIGroup 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_A2A_GCI:onafterAbort( AIGroup, From, Event, To ) + AIGroup:ClearTasks() + self:Return() + self:__RTB( 0.5 ) +end + + +--- @param #AI_A2A_GCI self +-- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI:onafterEngage( AIGroup, From, Event, To, AttackSetUnit ) + + self:F( { AIGroup, From, Event, To, AttackSetUnit} ) + + self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT + + local FirstAttackUnit = self.AttackSetUnit:GetFirst() + + if FirstAttackUnit then + + if AIGroup:IsAlive() then + + local EngageRoute = {} + + --- Calculate the target route point. + + local CurrentCoord = AIGroup:GetCoordinate() + + local ToTargetCoord = self.AttackSetUnit:GetFirst():GetCoordinate() + self:SetTargetDistance( ToTargetCoord ) -- For RTB status check + + 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 ):RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + ToTargetSpeed, + true + ) + + self:F( { Angle = ToInterceptAngle, ToTargetSpeed = ToTargetSpeed } ) + self:T2( { self.EngageMinSpeed, self.EngageMaxSpeed, ToTargetSpeed } ) + + EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint + + AIGroup:OptionROEOpenFire() + AIGroup:OptionROTPassiveDefense() + + local AttackTasks = {} + + for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do + local AttackUnit = AttackUnit -- Wrapper.Unit#UNIT + self:T( { "Intercepting Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsAir() } ) + if AttackUnit:IsAlive() and AttackUnit:IsAir() then + AttackTasks[#AttackTasks+1] = AIGroup:TaskAttackUnit( AttackUnit ) + end + end + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + AIGroup:WayPointInitialize( EngageRoute ) + + + if #AttackTasks == 0 then + self:E("No targets found -> Going RTB") + self:Return() + self:__RTB( 0.5 ) + else + AttackTasks[#AttackTasks+1] = AIGroup:TaskFunction( 1, #AttackTasks, "AI_A2A_GCI.InterceptRoute" ) + AttackTasks[#AttackTasks+1] = AIGroup:TaskOrbitCircle( 4000, self.EngageMinSpeed ) + EngageRoute[1].task = AIGroup:TaskCombo( AttackTasks ) + + --- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ... + AIGroup:SetState( AIGroup, "EngageZone", self ) + end + + --- NOW ROUTE THE GROUP! + AIGroup:WayPointExecute( 1, 0 ) + + end + else + self:E("No targets found -> Going RTB") + self:Return() + self:__RTB( 0.5 ) + end +end + +--- @param #AI_A2A_GCI self +-- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI:onafterAccomplish( AIGroup, From, Event, To ) + self.Accomplished = true + self:SetDetectionOff() +end + +--- @param #AI_A2A_GCI self +-- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_GCI:onafterDestroy( AIGroup, From, Event, To, EventData ) + + if EventData.IniUnit then + self.AttackUnits[EventData.IniUnit] = nil + end +end + +--- @param #AI_A2A_GCI self +-- @param Core.Event#EVENTDATA EventData +function AI_A2A_GCI: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 diff --git a/Moose Development/Moose/AI/AI_A2A_Patrol.lua b/Moose Development/Moose/AI/AI_A2A_Patrol.lua new file mode 100644 index 000000000..110991d19 --- /dev/null +++ b/Moose Development/Moose/AI/AI_A2A_Patrol.lua @@ -0,0 +1,381 @@ +--- **AI** -- **Air Patrolling or Staging.** +-- +-- ![Banner Image](..\Presentations\AI_PATROL\Dia1.JPG) +-- +-- === +-- +-- AI PATROL classes makes AI Controllables execute an Patrol. +-- +-- There are the following types of PATROL classes defined: +-- +-- * @{#AI_A2A_PATROL}: Perform a PATROL in a zone. +-- +-- ==== +-- +-- # Demo Missions +-- +-- ### [AI_PATROL Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/PAT%20-%20Patrolling) +-- +-- ### [AI_PATROL Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/PAT%20-%20Patrolling) +-- +-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- +-- ==== +-- +-- # YouTube Channel +-- +-- ### [AI_PATROL YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl35HvYZKA6G22WMt7iI3zky) +-- +-- ==== +-- +-- ### Author: **Sven Van de Velde (FlightControl)** +-- ### Contributions: +-- +-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) +-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Testing and API concept review. +-- +-- ==== +-- +-- @module AI_A2A_Patrol + + +--- @type AI_A2A_PATROL +-- @extends AI.AI_A2A#AI_A2A + +--- # AI_A2A_PATROL class, extends @{Fsm#FSM_CONTROLLABLE} +-- +-- The AI_A2A_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group}. +-- +-- ![Process](..\Presentations\AI_PATROL\Dia3.JPG) +-- +-- The AI_A2A_PATROL is assigned a @{Group} and this must be done before the AI_A2A_PATROL process can be started using the **Start** event. +-- +-- ![Process](..\Presentations\AI_PATROL\Dia4.JPG) +-- +-- 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. +-- +-- ![Process](..\Presentations\AI_PATROL\Dia5.JPG) +-- +-- This cycle will continue. +-- +-- ![Process](..\Presentations\AI_PATROL\Dia6.JPG) +-- +-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event. +-- +-- ![Process](..\Presentations\AI_PATROL\Dia9.JPG) +-- +---- Note that the enemy is not engaged! To model enemy engagement, either tailor the **Detected** event, or +-- use derived AI_ classes to model AI offensive or defensive behaviour. +-- +-- ![Process](..\Presentations\AI_PATROL\Dia10.JPG) +-- +-- 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. +-- +-- ![Process](..\Presentations\AI_PATROL\Dia11.JPG) +-- +-- ## 1. AI_A2A_PATROL constructor +-- +-- * @{#AI_A2A_PATROL.New}(): Creates a new AI_A2A_PATROL object. +-- +-- ## 2. AI_A2A_PATROL is a FSM +-- +-- ![Process](..\Presentations\AI_PATROL\Dia2.JPG) +-- +-- ### 2.1. AI_A2A_PATROL States +-- +-- * **None** ( Group ): The process is not started yet. +-- * **Patrolling** ( Group ): The AI is patrolling the Patrol Zone. +-- * **Returning** ( Group ): The AI is returning to Base. +-- * **Stopped** ( Group ): The process is stopped. +-- * **Crashed** ( Group ): The AI has crashed or is dead. +-- +-- ### 2.2. AI_A2A_PATROL Events +-- +-- * **Start** ( Group ): Start the process. +-- * **Stop** ( Group ): Stop the process. +-- * **Route** ( Group ): Route the AI to a new random 3D point within the Patrol Zone. +-- * **RTB** ( Group ): Route the AI to the home base. +-- * **Detect** ( Group ): The AI is detecting targets. +-- * **Detected** ( Group ): The AI has detected new targets. +-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. +-- +-- ## 3. Set or Get the AI controllable +-- +-- * @{#AI_A2A_PATROL.SetControllable}(): Set the AIControllable. +-- * @{#AI_A2A_PATROL.GetControllable}(): Get the AIControllable. +-- +-- ## 4. Set the Speed and Altitude boundaries of the AI controllable +-- +-- * @{#AI_A2A_PATROL.SetSpeed}(): Set the patrol speed boundaries of the AI, for the next patrol. +-- * @{#AI_A2A_PATROL.SetAltitude}(): Set altitude boundaries of the AI, for the next patrol. +-- +-- ## 5. Manage the detection process of the AI controllable +-- +-- The detection process of the AI controllable can be manipulated. +-- Detection requires an amount of CPU power, which has an impact on your mission performance. +-- Only put detection on when absolutely necessary, and the frequency of the detection can also be set. +-- +-- * @{#AI_A2A_PATROL.SetDetectionOn}(): Set the detection on. The AI will detect for targets. +-- * @{#AI_A2A_PATROL.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased. +-- +-- The detection frequency can be set with @{#AI_A2A_PATROL.SetDetectionInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection. +-- Use the method @{#AI_A2A_PATROL.GetDetectedUnits}() to obtain a list of the @{Unit}s detected by the AI. +-- +-- The detection can be filtered to potential targets in a specific zone. +-- Use the method @{#AI_A2A_PATROL.SetDetectionZone}() to set the zone where targets need to be detected. +-- Note that when the zone is too far away, or the AI is not heading towards the zone, or the AI is too high, no targets may be detected +-- according the weather conditions. +-- +-- ## 6. Manage the "out of fuel" in the AI_A2A_PATROL +-- +-- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base. +-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated. +-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, +-- while a new AI is targetted to the AI_A2A_PATROL. +-- Once the time is finished, the old AI will return to the base. +-- Use the method @{#AI_A2A_PATROL.ManageFuel}() to have this proces in place. +-- +-- ## 7. Manage "damage" behaviour of the AI in the AI_A2A_PATROL +-- +-- When the AI is damaged, it is required that a new AIControllable is started. However, damage cannon be foreseen early on. +-- Therefore, when the damage treshold is reached, the AI will return immediately to the home base (RTB). +-- Use the method @{#AI_A2A_PATROL.ManageDamage}() to have this proces in place. +-- +-- === +-- +-- @field #AI_A2A_PATROL +AI_A2A_PATROL = { + ClassName = "AI_A2A_PATROL", +} + +--- Creates a new AI_A2A_PATROL object +-- @param #AI_A2A_PATROL self +-- @param Wrapper.Group#GROUP AIGroup +-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. +-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @return #AI_A2A_PATROL self +-- @usage +-- -- Define a new AI_A2A_PATROL Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h. +-- PatrolZone = ZONE:New( 'PatrolZone' ) +-- PatrolSpawn = SPAWN:New( 'Patrol Group' ) +-- PatrolArea = AI_A2A_PATROL:New( PatrolZone, 3000, 6000, 600, 900 ) +function AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) + + -- Inherits from BASE + local self = BASE:Inherit( self, AI_A2A:New( AIGroup ) ) -- #AI_A2A_PATROL + + self.PatrolZone = PatrolZone + self.PatrolFloorAltitude = PatrolFloorAltitude + self.PatrolCeilingAltitude = PatrolCeilingAltitude + self.PatrolMinSpeed = PatrolMinSpeed + self.PatrolMaxSpeed = PatrolMaxSpeed + + -- defafult PatrolAltType to "RADIO" if not specified + self.PatrolAltType = PatrolAltType or "RADIO" + + self:AddTransition( "Started", "Patrol", "Patrolling" ) + +--- OnBefore Transition Handler for Event Patrol. +-- @function [parent=#AI_A2A_PATROL] OnBeforePatrol +-- @param #AI_A2A_PATROL self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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 Patrol. +-- @function [parent=#AI_A2A_PATROL] OnAfterPatrol +-- @param #AI_A2A_PATROL self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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 Patrol. +-- @function [parent=#AI_A2A_PATROL] Patrol +-- @param #AI_A2A_PATROL self + +--- Asynchronous Event Trigger for Event Patrol. +-- @function [parent=#AI_A2A_PATROL] __Patrol +-- @param #AI_A2A_PATROL self +-- @param #number Delay The delay in seconds. + +--- OnLeave Transition Handler for State Patrolling. +-- @function [parent=#AI_A2A_PATROL] OnLeavePatrolling +-- @param #AI_A2A_PATROL self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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 Patrolling. +-- @function [parent=#AI_A2A_PATROL] OnEnterPatrolling +-- @param #AI_A2A_PATROL self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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( "Patrolling", "Route", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_PATROL. + +--- OnBefore Transition Handler for Event Route. +-- @function [parent=#AI_A2A_PATROL] OnBeforeRoute +-- @param #AI_A2A_PATROL self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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 Route. +-- @function [parent=#AI_A2A_PATROL] OnAfterRoute +-- @param #AI_A2A_PATROL self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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 Route. +-- @function [parent=#AI_A2A_PATROL] Route +-- @param #AI_A2A_PATROL self + +--- Asynchronous Event Trigger for Event Route. +-- @function [parent=#AI_A2A_PATROL] __Route +-- @param #AI_A2A_PATROL self +-- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_PATROL. + + return self +end + + + + +--- Sets (modifies) the minimum and maximum speed of the patrol. +-- @param #AI_A2A_PATROL self +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @return #AI_A2A_PATROL self +function AI_A2A_PATROL:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed ) + self:F2( { PatrolMinSpeed, PatrolMaxSpeed } ) + + self.PatrolMinSpeed = PatrolMinSpeed + self.PatrolMaxSpeed = PatrolMaxSpeed +end + + + +--- Sets the floor and ceiling altitude of the patrol. +-- @param #AI_A2A_PATROL self +-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @return #AI_A2A_PATROL self +function AI_A2A_PATROL:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude ) + self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } ) + + self.PatrolFloorAltitude = PatrolFloorAltitude + self.PatrolCeilingAltitude = PatrolCeilingAltitude +end + + +--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings. +-- @param #AI_A2A_PATROL self +-- @return #AI_A2A_PATROL self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_A2A_PATROL:onafterPatrol( Controllable, From, Event, To ) + self:F2() + + self:ClearTargetDistance() + + self:__Route( 1 ) + + self.Controllable:OnReSpawn( + function( PatrolGroup ) + self:E( "ReSpawn" ) + self:__Reset( 1 ) + self:__Route( 5 ) + end + ) +end + + + +--- @param Wrapper.Group#GROUP AIGroup +-- This statis method is called from the route path within the last task at the last waaypoint of the Controllable. +-- Note that this method is required, as triggers the next route when patrolling for the Controllable. +function AI_A2A_PATROL.PatrolRoute( AIGroup ) + + local _AI_A2A_Patrol = AIGroup:GetState( AIGroup, "AI_A2A_PATROL" ) -- #AI_A2A_PATROL + _AI_A2A_Patrol:Route() +end + + +--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings. +-- @param #AI_A2A_PATROL self +-- @param Wrapper.Group#GROUP AIGroup The AIGroup 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_A2A_PATROL:onafterRoute( AIGroup, From, Event, To ) + + self:F2() + + -- When RTB, don't allow anymore the routing. + if From == "RTB" then + return + end + + + if AIGroup:IsAlive() then + + local PatrolRoute = {} + + --- Calculate the target route point. + + local CurrentCoord = AIGroup:GetCoordinate() + + local ToTargetCoord = self.PatrolZone:GetRandomPointVec2() + self:SetTargetDistance( ToTargetCoord ) -- For RTB status check + + local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed ) + + --- Create a route point of type air. + local ToPatrolRoutePoint = ToTargetCoord:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + ToTargetSpeed, + true + ) + + PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + AIGroup:WayPointInitialize( PatrolRoute ) + + local Tasks = {} + Tasks[#Tasks+1] = AIGroup:TaskFunction( 1, 1, "AI_A2A_PATROL.PatrolRoute" ) + + PatrolRoute[1].task = AIGroup:TaskCombo( Tasks ) + + --- Do a trick, link the NewPatrolRoute function of the PATROLGROUP object to the AIControllable in a temporary variable ... + AIGroup:SetState( AIGroup, "AI_A2A_PATROL", self ) + + --- NOW ROUTE THE GROUP! + AIGroup:WayPointExecute( 1, 2 ) + end + +end + diff --git a/Moose Development/Moose/AI/AI_Patrol.lua b/Moose Development/Moose/AI/AI_Patrol.lua index c391ce4cd..286332c87 100644 --- a/Moose Development/Moose/AI/AI_Patrol.lua +++ b/Moose Development/Moose/AI/AI_Patrol.lua @@ -38,6 +38,7 @@ -- -- @module AI_Patrol + --- AI_PATROL_ZONE class -- @type AI_PATROL_ZONE -- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. diff --git a/Moose Development/Moose/AI/AI_SWEEP.lua b/Moose Development/Moose/AI/AI_SWEEP.lua new file mode 100644 index 000000000..1d14674c3 --- /dev/null +++ b/Moose Development/Moose/AI/AI_SWEEP.lua @@ -0,0 +1,565 @@ +--- **AI** -- **Execute Combat Air Patrol (CAP).** +-- +-- ![Banner Image](..\Presentations\AI_CAP\Dia1.JPG) +-- +-- === +-- +-- AI CAP classes makes AI Controllables execute a Combat Air Patrol. +-- +-- There are the following types of CAP classes defined: +-- +-- * @{#AI_CAP_ZONE}: Perform a CAP in a zone. +-- +-- ==== +-- +-- # Demo Missions +-- +-- ### [AI_CAP Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAP%20-%20Combat%20Air%20Patrol) +-- +-- ### [AI_CAP Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAP%20-%20Combat%20Air%20Patrol) +-- +-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) +-- +-- ==== +-- +-- # YouTube Channel +-- +-- ### [AI_CAP YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1YCyPxJgoZn-CfhwyeW65L) +-- +-- ==== +-- +-- ### Author: **Sven Van de Velde (FlightControl)** +-- +-- ### Contributions: +-- +-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing. +-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Concept, Advice & Testing. +-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision. +-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing. +-- * **[Delta99](https://forums.eagle.ru/member.php?u=125166): Testing. +-- +-- ==== +-- +-- @module AI_Cap + + +--- @type AI_CAP_ZONE +-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling. +-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed. +-- @extends AI.AI_Patrol#AI_PATROL_ZONE + + +--- # AI_CAP_ZONE class, extends @{AI_CAP#AI_PATROL_ZONE} +-- +-- The AI_CAP_ZONE class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group} +-- and automatically engage any airborne enemies that are within a certain range or within a certain zone. +-- +-- ![Process](..\Presentations\AI_CAP\Dia3.JPG) +-- +-- The AI_CAP_ZONE is assigned a @{Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event. +-- +-- ![Process](..\Presentations\AI_CAP\Dia4.JPG) +-- +-- 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. +-- +-- ![Process](..\Presentations\AI_CAP\Dia5.JPG) +-- +-- This cycle will continue. +-- +-- ![Process](..\Presentations\AI_CAP\Dia6.JPG) +-- +-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event. +-- +-- ![Process](..\Presentations\AI_CAP\Dia9.JPG) +-- +-- When enemies are detected, the AI will automatically engage the enemy. +-- +-- ![Process](..\Presentations\AI_CAP\Dia10.JPG) +-- +-- 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. +-- +-- ![Process](..\Presentations\AI_CAP\Dia13.JPG) +-- +-- ## 1. AI_CAP_ZONE constructor +-- +-- * @{#AI_CAP_ZONE.New}(): Creates a new AI_CAP_ZONE object. +-- +-- ## 2. AI_CAP_ZONE is a FSM +-- +-- ![Process](..\Presentations\AI_CAP\Dia2.JPG) +-- +-- ### 2.1 AI_CAP_ZONE 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_CAP_ZONE Events +-- +-- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone. +-- * **@{#AI_CAP_ZONE.Engage}**: Let the AI engage the bogeys. +-- * **@{#AI_CAP_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone. +-- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. +-- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. +-- * **@{#AI_CAP_ZONE.Destroy}**: The AI has destroyed a bogey @{Unit}. +-- * **@{#AI_CAP_ZONE.Destroyed}**: The AI has destroyed all bogeys @{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 +-- +-- ![Range](..\Presentations\AI_CAP\Dia11.JPG) +-- +-- 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_CAP#AI_CAP_ZONE.SetEngageRange}() to define that range. +-- +-- ## 4. Set the Zone of Engagement +-- +-- ![Zone](..\Presentations\AI_CAP\Dia12.JPG) +-- +-- An optional @{Zone} can be set, +-- that will define when the AI will engage with the detected airborne enemy targets. +-- Use the method @{AI_Cap#AI_CAP_ZONE.SetEngageZone}() to define that Zone. +-- +-- === +-- +-- @field #AI_CAP_ZONE +AI_CAP_ZONE = { + ClassName = "AI_CAP_ZONE", +} + + + +--- Creates a new AI_CAP_ZONE object +-- @param #AI_CAP_ZONE self +-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. +-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h. +-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @return #AI_CAP_ZONE self +function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) + + -- Inherits from BASE + local self = BASE:Inherit( self, AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_CAP_ZONE + + self.Accomplished = false + self.Engaging = false + + self:AddTransition( { "Patrolling", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE. + + --- OnBefore Transition Handler for Event Engage. + -- @function [parent=#AI_CAP_ZONE] OnBeforeEngage + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE] OnAfterEngage + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE] Engage + -- @param #AI_CAP_ZONE self + + --- Asynchronous Event Trigger for Event Engage. + -- @function [parent=#AI_CAP_ZONE] __Engage + -- @param #AI_CAP_ZONE self + -- @param #number Delay The delay in seconds. + +--- OnLeave Transition Handler for State Engaging. +-- @function [parent=#AI_CAP_ZONE] OnLeaveEngaging +-- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE] OnEnterEngaging +-- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE. + + --- OnBefore Transition Handler for Event Fired. + -- @function [parent=#AI_CAP_ZONE] OnBeforeFired + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE] OnAfterFired + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE] Fired + -- @param #AI_CAP_ZONE self + + --- Asynchronous Event Trigger for Event Fired. + -- @function [parent=#AI_CAP_ZONE] __Fired + -- @param #AI_CAP_ZONE self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE. + + --- OnBefore Transition Handler for Event Destroy. + -- @function [parent=#AI_CAP_ZONE] OnBeforeDestroy + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE] OnAfterDestroy + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE] Destroy + -- @param #AI_CAP_ZONE self + + --- Asynchronous Event Trigger for Event Destroy. + -- @function [parent=#AI_CAP_ZONE] __Destroy + -- @param #AI_CAP_ZONE self + -- @param #number Delay The delay in seconds. + + + self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE. + + --- OnBefore Transition Handler for Event Abort. + -- @function [parent=#AI_CAP_ZONE] OnBeforeAbort + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE] OnAfterAbort + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE] Abort + -- @param #AI_CAP_ZONE self + + --- Asynchronous Event Trigger for Event Abort. + -- @function [parent=#AI_CAP_ZONE] __Abort + -- @param #AI_CAP_ZONE self + -- @param #number Delay The delay in seconds. + + self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE. + + --- OnBefore Transition Handler for Event Accomplish. + -- @function [parent=#AI_CAP_ZONE] OnBeforeAccomplish + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE] OnAfterAccomplish + -- @param #AI_CAP_ZONE self + -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE] Accomplish + -- @param #AI_CAP_ZONE self + + --- Asynchronous Event Trigger for Event Accomplish. + -- @function [parent=#AI_CAP_ZONE] __Accomplish + -- @param #AI_CAP_ZONE self + -- @param #number Delay The delay in seconds. + + return self +end + + +--- Set the Engage Zone which defines where the AI will engage bogies. +-- @param #AI_CAP_ZONE self +-- @param Core.Zone#ZONE EngageZone The zone where the AI is performing CAP. +-- @return #AI_CAP_ZONE self +function AI_CAP_ZONE: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_CAP_ZONE self +-- @param #number EngageRange The Engage Range. +-- @return #AI_CAP_ZONE self +function AI_CAP_ZONE:SetEngageRange( EngageRange ) + self:F2() + + if EngageRange then + self.EngageRange = EngageRange + else + self.EngageRange = nil + end +end + +--- onafter State Transition for Event Start. +-- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE:onafterStart( Controllable, From, Event, To ) + + -- Call the parent Start event handler + self:GetParent(self).onafterStart( self, Controllable, From, Event, To ) + self:HandleEvent( EVENTS.Dead ) + +end + +-- todo: need to fix this global function + +--- @param Wrapper.Controllable#CONTROLLABLE AIControllable +function _NewEngageCapRoute( AIControllable ) + + AIControllable:T( "NewEngageRoute" ) + local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cap#AI_CAP_ZONE + EngageZone:__Engage( 1 ) +end + +--- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE:onbeforeEngage( Controllable, From, Event, To ) + + if self.Accomplished == true then + return false + end +end + +--- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE:onafterDetected( Controllable, From, Event, To ) + + if From ~= "Engaging" then + + local Engage = false + + for DetectedUnit, Detected in pairs( self.DetectedUnits ) do + + local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT + self:T( DetectedUnit ) + if DetectedUnit:IsAlive() and DetectedUnit:IsAir() then + Engage = true + break + end + end + + if Engage == true then + self:E( 'Detected -> Engaging' ) + self:__Engage( 1 ) + end + end +end + + +--- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE:onafterAbort( Controllable, From, Event, To ) + Controllable:ClearTasks() + self:__Route( 1 ) +end + + + + +--- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE:onafterEngage( Controllable, From, Event, To ) + + if Controllable:IsAlive() then + + local EngageRoute = {} + + --- Calculate the current route point. + local CurrentVec2 = self.Controllable:GetVec2() + + --TODO: Create GetAltitude function for GROUP, and delete GetUnit(1). + local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude() + local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) + local ToEngageZoneSpeed = self.PatrolMaxSpeed + local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + ToEngageZoneSpeed, + true + ) + + EngageRoute[#EngageRoute+1] = CurrentRoutePoint + + + --- Find a random 2D point in PatrolZone. + local ToTargetVec2 = self.PatrolZone:GetRandomVec2() + self:T2( ToTargetVec2 ) + + --- Define Speed and Altitude. + local ToTargetAltitude = math.random( self.EngageFloorAltitude, self.EngageCeilingAltitude ) + local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed ) + self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } ) + + --- Obtain a 3D @{Point} from the 2D point + altitude. + local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y ) + + --- Create a route point of type air. + local ToPatrolRoutePoint = ToTargetPointVec3:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + ToTargetSpeed, + true + ) + + EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint + + Controllable:OptionROEOpenFire() + Controllable:OptionROTPassiveDefense() + + local AttackTasks = {} + + for DetectedUnit, Detected in pairs( self.DetectedUnits ) do + local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT + self:T( { DetectedUnit, DetectedUnit:IsAlive(), DetectedUnit:IsAir() } ) + if DetectedUnit:IsAlive() and DetectedUnit:IsAir() then + if self.EngageZone then + if DetectedUnit:IsInZone( self.EngageZone ) then + self:E( {"Within Zone and Engaging ", DetectedUnit } ) + AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit ) + end + else + if self.EngageRange then + if DetectedUnit:GetPointVec3():Get2DDistance(Controllable:GetPointVec3() ) <= self.EngageRange then + self:E( {"Within Range and Engaging", DetectedUnit } ) + AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit ) + end + else + AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit ) + end + end + else + self.DetectedUnits[DetectedUnit] = nil + end + end + + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... + self.Controllable:WayPointInitialize( EngageRoute ) + + + if #AttackTasks == 0 then + self:E("No targets found -> Going back to Patrolling") + self:__Abort( 1 ) + self:__Route( 1 ) + self:SetDetectionActivated() + else + EngageRoute[1].task = Controllable:TaskCombo( AttackTasks ) + + --- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ... + self.Controllable:SetState( self.Controllable, "EngageZone", self ) + + self.Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageCapRoute" ) + + self:SetDetectionDeactivated() + end + + --- NOW ROUTE THE GROUP! + self.Controllable:WayPointExecute( 1, 2 ) + + end +end + +--- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE:onafterAccomplish( Controllable, From, Event, To ) + self.Accomplished = true + self:SetDetectionOff() +end + +--- @param #AI_CAP_ZONE self +-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable 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_CAP_ZONE:onafterDestroy( Controllable, From, Event, To, EventData ) + + if EventData.IniUnit then + self.DetectedUnits[EventData.IniUnit] = nil + end +end + +--- @param #AI_CAP_ZONE self +-- @param Core.Event#EVENTDATA EventData +function AI_CAP_ZONE:OnEventDead( EventData ) + self:F( { "EventDead", EventData } ) + + if EventData.IniDCSUnit then + if self.DetectedUnits and self.DetectedUnits[EventData.IniUnit] then + self:__Destroy( 1, EventData ) + end + end +end diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index e06eaf308..8a8e345b1 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -703,7 +703,7 @@ end --- Set tracing for a class -- @param #BASE self -- @param #string Class -function BASE:TraceClass( Class ) +function --BASE:TraceClass( Class ) _TraceClass[Class] = true _TraceClassMethod[Class] = {} self:E( "Tracing class " .. Class ) @@ -713,7 +713,7 @@ end -- @param #BASE self -- @param #string Class -- @param #string Method -function BASE:TraceClassMethod( Class, Method ) +function --BASE:TraceClassMethod( Class, Method ) if not _TraceClassMethod[Class] then _TraceClassMethod[Class] = {} _TraceClassMethod[Class].Method = {} diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index e46a985f7..3d7c331fa 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -983,7 +983,7 @@ function EVENT:onEvent( Event ) -- There is an EventFunction defined, so call the EventFunction. if Event.IniObjectCategory ~= 3 then - self:E( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } ) + self:F2( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } ) end local Result, Value = xpcall( function() @@ -997,7 +997,7 @@ function EVENT:onEvent( Event ) -- Now call the default event function. if Event.IniObjectCategory ~= 3 then - self:E( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } ) + self:F2( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } ) end local Result, Value = xpcall( diff --git a/Moose Development/Moose/Core/Fsm.lua b/Moose Development/Moose/Core/Fsm.lua index 67d495999..6d47cc158 100644 --- a/Moose Development/Moose/Core/Fsm.lua +++ b/Moose Development/Moose/Core/Fsm.lua @@ -396,7 +396,7 @@ do -- FSM Transition.Event = Event Transition.To = To - self:T( Transition ) + self:T2( Transition ) self._Transitions[Transition] = Transition self:_eventmap( self.Events, Transition ) @@ -534,7 +534,7 @@ do -- FSM local __Event = "__" .. EventStructure.Event self[Event] = self[Event] or self:_create_transition(Event) self[__Event] = self[__Event] or self:_delayed_transition(Event) - self:T( "Added methods: " .. Event .. ", " .. __Event ) + self:T2( "Added methods: " .. Event .. ", " .. __Event ) Events[Event] = self.Events[Event] or { map = {} } self:_add_to_map( Events[Event].map, EventStructure ) @@ -569,7 +569,7 @@ do -- FSM return errmsg end if self[handler] then - self:T( "Calling " .. handler ) + self:T2( "Calling " .. handler ) self._EventSchedules[EventName] = nil local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler ) return Value diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index 755bcd971..e632f38fc 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -87,7 +87,7 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory ) self.MessageDuration = MessageDuration or 5 self.MessageTime = timer.getTime() - self.MessageText = MessageText + self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1) self.MessageSent = false self.MessageGroup = false diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 05309b052..18da277e7 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -138,12 +138,13 @@ do -- COORDINATE ClassName = "COORDINATE", } + --- COORDINATE constructor. -- @param #COORDINATE self -- @param Dcs.DCSTypes#Distance x The x coordinate of the Vec3 point, pointing to the North. -- @param Dcs.DCSTypes#Distance y The y coordinate of the Vec3 point, pointing to the Right. -- @param Dcs.DCSTypes#Distance z The z coordinate of the Vec3 point, pointing to the Right. - -- @return Core.Point#COORDINATE + -- @return #COORDINATE function COORDINATE:New( x, y, z ) local self = BASE:Inherit( self, BASE:New() ) -- #COORDINATE @@ -177,7 +178,7 @@ do -- COORDINATE --- Create a new COORDINATE object from Vec3 coordinates. -- @param #COORDINATE self -- @param Dcs.DCSTypes#Vec3 Vec3 The Vec3 point. - -- @return Core.Point#COORDINATE + -- @return #COORDINATE function COORDINATE:NewFromVec3( Vec3 ) local self = self:New( Vec3.x, Vec3.y, Vec3.z ) -- #COORDINATE diff --git a/Moose Development/Moose/Core/ScheduleDispatcher.lua b/Moose Development/Moose/Core/ScheduleDispatcher.lua index 179019c14..51358dee4 100644 --- a/Moose Development/Moose/Core/ScheduleDispatcher.lua +++ b/Moose Development/Moose/Core/ScheduleDispatcher.lua @@ -62,7 +62,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr -- Initialize the ObjectSchedulers array, which is a weakly coupled table. -- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array. - self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } ) -- or {} + self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } ) if Scheduler.MasterObject then self.ObjectSchedulers[self.CallID] = Scheduler @@ -101,13 +101,13 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr Scheduler = self.PersistentSchedulers[CallID] end - self:T3( { Scheduler = Scheduler } ) + --self:T3( { Scheduler = Scheduler } ) if Scheduler then local Schedule = self.Schedule[Scheduler][CallID] - self:T3( { Schedule = Schedule } ) + --self:T3( { Schedule = Schedule } ) local ScheduleObject = Scheduler.SchedulerObject --local ScheduleObjectName = Scheduler.SchedulerObject:GetNameAndClassID() @@ -145,7 +145,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr ( Randomize * Repeat / 2 ) ) + 0.01 - self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } ) + --self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } ) return ScheduleTime -- returns the next time the function needs to be called. else self:Stop( Scheduler, CallID ) @@ -154,7 +154,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr self:Stop( Scheduler, CallID ) end else - self:E( "Scheduled obscolete call for CallID: " .. CallID ) + self:E( "Scheduled obsolete call for CallID: " .. CallID ) end return nil diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index ad8c69b67..6844d5e62 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -84,11 +84,6 @@ function SET_BASE:New( Database ) self.TimeInterval = 0.001 self.Set = {} - - self.List = {} - self.List.__index = self.List - self.List = setmetatable( { Count = 0 }, self.List ) - self.Index = {} self.CallScheduler = SCHEDULER:New( self ) @@ -126,24 +121,8 @@ end function SET_BASE:Add( ObjectName, Object ) self:F( ObjectName ) - local t = { _ = Object } - - if self.List.last then - self.List.last._next = t - t._prev = self.List.last - self.List.last = t - else - -- this is the first node - self.List.first = t - self.List.last = t - end - - self.List.Count = self.List.Count + 1 - self.Set[ObjectName] = Object - table.insert( self.Index, ObjectName ) - end --- Adds a @{Base#BASE} object in the @{Set#SET_BASE}, using the Object Name as the index. @@ -166,43 +145,19 @@ end -- @param #string ObjectName function SET_BASE:Remove( ObjectName ) - local t = self.Set[ObjectName] + local Object = self.Set[ObjectName] - self:F3( { ObjectName, t } ) + self:F3( { ObjectName, Object } ) - if t then - if t._next then - if t._prev then - t._next._prev = t._prev - t._prev._next = t._next - else - -- this was the first node - t._next._prev = nil - self.List._first = t._next - end - elseif t._prev then - -- this was the last node - t._prev._next = nil - self.List._last = t._prev - else - -- this was the only node - self.List._first = nil - self.List._last = nil - end - - t._next = nil - t._prev = nil - self.List.Count = self.List.Count - 1 - + if Object then for Index, Key in ipairs( self.Index ) do if Key == ObjectName then table.remove( self.Index, Index ) + self.Set[ObjectName] = nil break end end - self.Set[ObjectName] = nil - end end @@ -214,19 +169,16 @@ end function SET_BASE:Get( ObjectName ) self:F( ObjectName ) - local t = self.Set[ObjectName] - - self:T3( { ObjectName, t } ) - - return t + local Object = self.Set[ObjectName] + self:T3( { ObjectName, Object } ) + return Object end --- Gets the first object from the @{Set#SET_BASE} and derived classes. -- @param #SET_BASE self -- @return Core.Base#BASE function SET_BASE:GetFirst() - self:F() local ObjectName = self.Index[1] local FirstObject = self.Set[ObjectName] @@ -238,7 +190,6 @@ end -- @param #SET_BASE self -- @return Core.Base#BASE function SET_BASE:GetLast() - self:F() local ObjectName = self.Index[#self.Index] local LastObject = self.Set[ObjectName] @@ -250,12 +201,9 @@ end -- @param #SET_BASE self -- @return Core.Base#BASE function SET_BASE:GetRandom() - self:F() local RandomItem = self.Set[self.Index[math.random(#self.Index)]] - self:T3( { RandomItem } ) - return RandomItem end @@ -265,7 +213,7 @@ end -- @return #number Count function SET_BASE:Count() - return #self.Index or 0 + return self.Index and #self.Index or 0 end @@ -603,6 +551,20 @@ function SET_BASE:IsIncludeObject( Object ) return true end +--- Gets a string with all the object names. +-- @param #SET_BASE self +-- @return #string A string with the names of the objects. +function SET_BASE:GetObjectNames() + self:F3() + + local ObjectNames = "" + for ObjectName, Object in pairs( self.Set ) do + ObjectNames = ObjectNames .. ObjectName .. ", " + end + + return ObjectNames +end + --- Flushes the current SET_BASE contents in the log ... (for debugging reasons). -- @param #SET_BASE self -- @return #string A string with the names of the objects. diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 5256401d6..2285531f1 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -37,6 +37,10 @@ -- -- @module Detection +----BASE:TraceClass("DETECTION_BASE") +----BASE:TraceClass("DETECTION_AREAS") +----BASE:TraceClass("DETECTION_UNITS") +----BASE:TraceClass("DETECTION_TYPES") do -- DETECTION_BASE @@ -607,7 +611,7 @@ do -- DETECTION_BASE if self.AcceptZones then for AcceptZoneID, AcceptZone in pairs( self.AcceptZones ) do local AcceptZone = AcceptZone -- Core.Zone#ZONE_BASE - if AcceptZone:IsPointVec2InZone( DetectedObjectVec2 ) == false then + if AcceptZone:IsVec2InZone( DetectedObjectVec2 ) == false then DetectionAccepted = false end end @@ -755,6 +759,25 @@ do -- DETECTION_BASE return self end + + --- Forget a Unit from a DetectionItem + -- @param #DETECTION_BASE self + -- @param #string UnitName The UnitName that needs to be forgotten from the DetectionItem Sets. + -- @return #DETECTION_BASE + function DETECTION_BASE:ForgetDetectedUnit( UnitName ) + self:F2() + + local DetectedItems = self:GetDetectedItems() + + for DetectedItemIndex, DetectedItem in pairs( DetectedItems ) do + local DetectedSet = self:GetDetectedSet( DetectedItemIndex ) + if DetectedSet then + DetectedSet:RemoveUnitsByName( UnitName ) + end + end + + return self + end --- Make a DetectionSet table. This function will be overridden in the derived clsses. -- @param #DETECTION_BASE self @@ -1144,6 +1167,7 @@ do -- DETECTION_BASE local DetectedItem = ReportGroupData.DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem local DetectedSet = ReportGroupData.DetectedItem.Set local DetectedUnit = DetectedSet:GetFirst() -- Wrapper.Unit#UNIT + local CenterCoord = DetectedUnit:GetCoordinate() local ReportSetGroup = ReportGroupData.ReportSetGroup local EnemyCoalition = DetectedUnit:GetCoalition() @@ -1154,12 +1178,14 @@ do -- DETECTION_BASE local EnemyUnitName = DetectedUnit:GetName() local FoundUnitInReportSetGroup = ReportSetGroup:FindGroup( FoundUnitGroupName ) ~= nil - self:T3( { "Friendlies search:", FoundUnitName, FoundUnitCoalition, EnemyUnitName, EnemyCoalition, FoundUnitInReportSetGroup } ) + self:F( { "Friendlies search:", FoundUnitName, FoundUnitCoalition, EnemyUnitName, EnemyCoalition, FoundUnitInReportSetGroup } ) if FoundUnitCoalition ~= EnemyCoalition and FoundUnitInReportSetGroup == false then DetectedItem.FriendliesNearBy = DetectedItem.FriendliesNearBy or {} - DetectedItem.FriendliesNearBy[FoundUnitName] = UNIT:Find( FoundDCSUnit ) - return false + local FriendlyUnit = UNIT:Find( FoundDCSUnit ) + local Distance = CenterCoord:Get2DDistance( FriendlyUnit:GetCoordinate() ) + DetectedItem.FriendliesNearBy[Distance] = FriendlyUnit + return true end return true diff --git a/Moose Development/Moose/Functional/Spawn.lua b/Moose Development/Moose/Functional/Spawn.lua index 862cc6f07..8ad718194 100644 --- a/Moose Development/Moose/Functional/Spawn.lua +++ b/Moose Development/Moose/Functional/Spawn.lua @@ -37,6 +37,7 @@ -- -- @module Spawn +----BASE:TraceClass("SPAWN") --- SPAWN Class @@ -264,6 +265,14 @@ SPAWN = { } +--- Enumerator for spawns at airbases +-- @type SPAWN.Takeoff +-- @extends Wrapper.Group#GROUP.Takeoff + +--- @field #SPAWN.Takeoff Takeoff +SPAWN.Takeoff = GROUP.Takeoff + + --- @type SPAWN.SpawnZoneTable -- @list SpawnZone @@ -299,6 +308,7 @@ function SPAWN:New( SpawnTemplatePrefix ) self.SpawnUnControlled = false self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. self.DelayOnOff = false -- No intial delay when spawning the first group. + self.Grouping = nil -- No grouping self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. else @@ -343,6 +353,7 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix ) self.SpawnUnControlled = false self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name. self.DelayOnOff = false -- No intial delay when spawning the first group. + self.Grouping = nil self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned. else @@ -509,6 +520,20 @@ function SPAWN:InitRandomizeTemplate( SpawnTemplatePrefixTable ) return self end +--- When spawning a new group, make the grouping of the units according the InitGrouping setting. +-- @param #SPAWN self +-- @param #number Grouping Indicates the maximum amount of units in the group. +-- @return #SPAWN +function SPAWN:InitGrouping( Grouping ) -- R2.2 + self:F( { self.SpawnTemplatePrefix, Grouping } ) + + self.SpawnGrouping = Grouping + + return self +end + + + --TODO: Add example. --- This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types. -- @param #SPAWN self @@ -957,6 +982,64 @@ function SPAWN:OnSpawnGroup( SpawnCallBackFunction, ... ) return self end +--- Will spawn a group at an airbase. +-- This method is mostly advisable to be used if you want to simulate spawning units at an airbase. +-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn. +-- You can use the returned group to further define the route to be followed. +-- @param #SPAWN self +-- @param Wrapper.Airbase#AIRBASE Airbase The @{Airbase} where to spawn the group. +-- @param #SPAWN.Takeoff Takeoff (optional) The location and takeoff method. Default is Hot. +-- @return Wrapper.Group#GROUP that was spawned. +-- @return #nil Nothing was spawned. +function SPAWN:SpawnAtAirbase( Airbase, Takeoff ) -- R2.2 + self:F( { self.SpawnTemplatePrefix, Airbase } ) + + local PointVec3 = Airbase:GetPointVec3() + self:T2(PointVec3) + + Takeoff = Takeoff or SPAWN.Takeoff.Hot + + if self:_GetSpawnIndex( self.SpawnIndex + 1 ) then + + local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate + + if SpawnTemplate then + + self:T( { "Current point of ", self.SpawnTemplatePrefix, Airbase } ) + + -- Translate the position of the Group Template to the Vec3. + for UnitID = 1, #SpawnTemplate.units do + self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) + local UnitTemplate = SpawnTemplate.units[UnitID] + local SX = UnitTemplate.x + local SY = UnitTemplate.y + local BX = SpawnTemplate.route.points[1].x + local BY = SpawnTemplate.route.points[1].y + local TX = PointVec3.x + ( SX - BX ) + local TY = PointVec3.z + ( SY - BY ) + SpawnTemplate.units[UnitID].x = TX + SpawnTemplate.units[UnitID].y = TY + SpawnTemplate.units[UnitID].alt = PointVec3.y + self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y ) + end + + SpawnTemplate.route.points[1].x = PointVec3.x + SpawnTemplate.route.points[1].y = PointVec3.z + SpawnTemplate.route.points[1].alt = Airbase.y + SpawnTemplate.route.points[1].type = GROUPTEMPLATE.Takeoff[Takeoff] + SpawnTemplate.route.points[1].airdromeId = Airbase:GetID() + + SpawnTemplate.x = PointVec3.x + SpawnTemplate.y = PointVec3.z + + return self:SpawnWithIndex( self.SpawnIndex ) + end + end + + return nil +end + + --- Will spawn a group from a Vec3 in 3D space. -- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes. @@ -1112,6 +1195,19 @@ function SPAWN:InitUnControlled( UnControlled ) end +--- Get the Coordinate of the Group that is Late Activated as the template for the SPAWN object. +-- @param #SPAWN self +-- @return Core.Point#COORDINATE The Coordinate +function SPAWN:GetCoordinate() + + local LateGroup = GROUP:FindByName( self.SpawnTemplatePrefix ) + if LateGroup then + return LateGroup:GetCoordinate() + end + + return nil +end + --- Will return the SpawnGroupName either with with a specific count number or without any count. -- @param #SPAWN self @@ -1370,7 +1466,7 @@ end -- @param #string SpawnTemplatePrefix -- @param #number SpawnIndex -- @return #SPAWN self -function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) +function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) --R2.2 self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } ) local SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix ) @@ -1385,6 +1481,23 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) SpawnTemplate.visible = false end + if self.SpawnGrouping then + local UnitAmount = #SpawnTemplate.units + self:F( { UnitAmount = UnitAmount, SpawnGrouping = self.SpawnGrouping } ) + if UnitAmount > self.SpawnGrouping then + for UnitID = self.SpawnGrouping + 1, UnitAmount do + SpawnTemplate.units[UnitID] = nil + end + else + if UnitAmount < self.SpawnGrouping then + for UnitID = UnitAmount + 1, self.SpawnGrouping do + SpawnTemplate.units[UnitID] = UTILS.DeepCopy( SpawnTemplate.units[1] ) + SpawnTemplate.units[UnitID].unitId = nil + end + end + end + end + if self.SpawnInitKeepUnitNames == false then for UnitID = 1, #SpawnTemplate.units do SpawnTemplate.units[UnitID].name = string.format( SpawnTemplate.name .. '-%02d', UnitID ) diff --git a/Moose Development/Moose/Tasking/DetectionManager.lua b/Moose Development/Moose/Tasking/DetectionManager.lua index 097a5c95b..0812459af 100644 --- a/Moose Development/Moose/Tasking/DetectionManager.lua +++ b/Moose Development/Moose/Tasking/DetectionManager.lua @@ -70,7 +70,60 @@ do -- DETECTION MANAGER self:SetStartState( "Stopped" ) self:AddTransition( "Stopped", "Start", "Started" ) + + --- Start Handler OnBefore for DETECTION_MANAGER + -- @function [parent=#DETECTION_MANAGER] OnBeforeStart + -- @param #DETECTION_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @return #boolean + + --- Start Handler OnAfter for DETECTION_MANAGER + -- @function [parent=#DETECTION_MANAGER] OnAfterStart + -- @param #DETECTION_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + + --- Start Trigger for DETECTION_MANAGER + -- @function [parent=#DETECTION_MANAGER] Start + -- @param #DETECTION_MANAGER self + + --- Start Asynchronous Trigger for DETECTION_MANAGER + -- @function [parent=#DETECTION_MANAGER] __Start + -- @param #DETECTION_MANAGER self + -- @param #number Delay + + + self:AddTransition( "Started", "Stop", "Stopped" ) + + --- Stop Handler OnBefore for DETECTION_MANAGER + -- @function [parent=#DETECTION_MANAGER] OnBeforeStop + -- @param #DETECTION_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @return #boolean + + --- Stop Handler OnAfter for DETECTION_MANAGER + -- @function [parent=#DETECTION_MANAGER] OnAfterStop + -- @param #DETECTION_MANAGER self + -- @param #string From + -- @param #string Event + -- @param #string To + + --- Stop Trigger for DETECTION_MANAGER + -- @function [parent=#DETECTION_MANAGER] Stop + -- @param #DETECTION_MANAGER self + + --- Stop Asynchronous Trigger for DETECTION_MANAGER + -- @function [parent=#DETECTION_MANAGER] __Stop + -- @param #DETECTION_MANAGER self + -- @param #number Delay + + self:AddTransition( "Started", "Report", "Started" ) self:SetReportInterval( 30 ) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 0416e9d9f..cce57959b 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -303,3 +303,27 @@ function UTILS.DoString( s ) return false, err end end + +-- Here is a customized version of pairs, which I called spairs because it iterates over the table in a sorted order. +function UTILS.spairs( t, order ) + -- collect the keys + local keys = {} + for k in pairs(t) do keys[#keys+1] = k end + + -- if order function given, sort by it by passing the table and keys a, b, + -- otherwise just sort the keys + if order then + table.sort(keys, function(a,b) return order(t, a, b) end) + else + table.sort(keys) + end + + -- return the iterator function + local i = 0 + return function() + i = i + 1 + if keys[i] then + return keys[i], t[keys[i]] + end + end +end diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 6d0900e33..cb08574e9 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -47,7 +47,7 @@ -- the first letter of the method is also capitalized. So, by example, the DCS Airbase method @{DCSWrapper.Airbase#Airbase.getName}() -- is implemented in the AIRBASE class as @{#AIRBASE.GetName}(). -- --- @field #AIRBASE +-- @field #AIRBASE AIRBASE AIRBASE = { ClassName="AIRBASE", CategoryName = { @@ -57,6 +57,31 @@ AIRBASE = { }, } +--- @field Caucasus +AIRBASE.Caucasus = { + ["Gelendzhik"] = "Gelendzhik", + ["Krasnodar_Pashkovsky"] = "Krasnodar-Pashkovsky", + ["Sukhumi_Babushara"] = "Sukhumi-Babushara", + ["Gudauta"] = "Gudauta", + ["Batumi"] = "Batumi", + ["Senaki_Kolkhi"] = "Senaki-Kolkhi", + ["Kobuleti"] = "Kobuleti", + ["Kutaisi"] = "Kutaisi", + ["Tbilisi_Lochini"] = "Tbilisi-Lochini", + ["Soganlug"] = "Soganlug", + ["Vaziani"] = "Vaziani", + ["Anapa_Vityazevo"] = "Anapa-Vityazevo", + ["Krasnodar_Center"] = "Krasnodar-Center", + ["Novorossiysk"] = "Novorossiysk", + ["Krymsk"] = "Krymsk", + ["Maykop_Khanskaya"] = "Maykop-Khanskaya", + ["Sochi_Adler"] = "Sochi-Adler", + ["Mineralnye_Vody"] = "Mineralnye Vody", + ["Nalchik"] = "Nalchik", + ["Mozdok"] = "Mozdok", + ["Beslan"] = "Beslan", + } + -- Registration. --- Create a new AIRBASE from DCSAirbase. diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 68cae7190..5ee4d7da8 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -152,7 +152,7 @@ CONTROLLABLE = { -- @param Dcs.DCSWrapper.Controllable#Controllable ControllableName The DCS Controllable name -- @return #CONTROLLABLE self function CONTROLLABLE:New( ControllableName ) - local self = BASE:Inherit( self, POSITIONABLE:New( ControllableName ) ) + local self = BASE:Inherit( self, POSITIONABLE:New( ControllableName ) ) -- #CONTROLLABLE self:F2( ControllableName ) self.ControllableName = ControllableName @@ -166,12 +166,10 @@ end -- @param #CONTROLLABLE self -- @return Dcs.DCSController#Controller function CONTROLLABLE:_GetController() - self:F2( { self.ControllableName } ) local DCSControllable = self:GetDCSObject() if DCSControllable then local ControllableController = DCSControllable:getController() - self:T3( ControllableController ) return ControllableController end @@ -230,6 +228,36 @@ function CONTROLLABLE:GetLife() return nil end +--- Returns the initial health. +-- @param #CONTROLLABLE self +-- @return #number The controllable health value (unit or group average). +-- @return #nil The controllable is not existing or alive. +function CONTROLLABLE:GetLife0() + self:F2( self.ControllableName ) + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + local UnitLife = 0 + local Units = self:GetUnits() + if #Units == 1 then + local Unit = Units[1] -- Wrapper.Unit#UNIT + UnitLife = Unit:GetLife0() + else + local UnitLifeTotal = 0 + for UnitID, Unit in pairs( Units ) do + local Unit = Unit -- Wrapper.Unit#UNIT + UnitLifeTotal = UnitLifeTotal + Unit:GetLife0() + end + UnitLife = UnitLifeTotal / #Units + end + return UnitLife + end + + return nil +end + + -- Tasks @@ -300,14 +328,13 @@ end -- @param #CONTROLLABLE self -- @return Wrapper.Controllable#CONTROLLABLE self function CONTROLLABLE:SetTask( DCSTask, WaitTime ) - self:F2( { DCSTask } ) + self:F2( { DCSTask = DCSTask } ) local DCSControllable = self:GetDCSObject() if DCSControllable then local Controller = self:_GetController() - self:T3( Controller ) -- When a controllable SPAWNs, it takes about a second to get the controllable in the simulator. Setting tasks to unspawned controllables provides unexpected results. -- Therefore we schedule the functions to set the mission and options for the Controllable. @@ -325,6 +352,24 @@ function CONTROLLABLE:SetTask( DCSTask, WaitTime ) return nil end +--- Checking the Task Queue of the controllable. Returns false if no task is on the queue. true if there is a task. +-- @param #CONTROLLABLE self +-- @return Wrapper.Controllable#CONTROLLABLE self +function CONTROLLABLE:HasTask() --R2.2 + + local HasTaskResult = false + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + + local Controller = self:_GetController() + HasTaskResult = Controller:hasTask() + end + + return HasTaskResult +end + --- Return a condition section for a controlled task. -- @param #CONTROLLABLE self @@ -389,7 +434,7 @@ function CONTROLLABLE:TaskCombo( DCSTasks ) } for TaskID, Task in ipairs( DCSTasks ) do - self:E( Task ) + self:T( Task ) end self:T3( { DCSTaskCombo } ) @@ -588,7 +633,7 @@ function CONTROLLABLE:TaskAttackUnit( AttackUnit, GroupAttack, WeaponExpend, Att } } - self:E( DCSTask ) + self:T3( DCSTask ) return DCSTask end @@ -2183,6 +2228,57 @@ function CONTROLLABLE:OptionROTVertical() return nil end + +--- Set RTB on bingo fuel. +-- @param #CONTROLLABLE self +-- @param #boolean RTB true if RTB on bingo fuel (default), false if no RTB on bingo fuel. +-- Warning! When you switch this option off, the airborne group will continue to fly until all fuel has been consumed, and will crash. +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionRTBBingoFuel( RTB ) --R2.2 + self:F2( { self.ControllableName } ) + + RTB = RTB or true + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + + if self:IsAir() then + Controller:setOption( AI.Option.Air.id.RTB_ON_BINGO, RTB ) + end + + return self + end + + return nil +end + + +--- Set RTB on ammo. +-- @param #CONTROLLABLE self +-- @param #boolean WeaponsFlag Weapons.flag enumerator. +-- @return #CONTROLLABLE self +function CONTROLLABLE:OptionRTBAmmo( WeaponsFlag ) + self:F2( { self.ControllableName } ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local Controller = self:_GetController() + + if self:IsAir() then + Controller:setOption( AI.Option.GROUND.id.RTB_ON_OUT_OF_AMMO, WeaponsFlag ) + end + + return self + end + + return nil +end + + + + + --- Retrieve the controllable mission and allow to place function hooks within the mission waypoint plan. -- Use the method @{Controllable#CONTROLLABLE:WayPointFunction} to define the hook functions for specific waypoints. -- Use the method @{Controllable@CONTROLLABLE:WayPointExecute) to start the execution of the new mission plan. @@ -2250,7 +2346,7 @@ function CONTROLLABLE:TaskFunction( WayPoint, WayPointIndex, FunctionString, Fun ), WayPointIndex ) - self:T3( DCSTask ) + self:T( DCSTask ) return DCSTask diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index e78e5eb8e..403a52a2c 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -91,6 +91,25 @@ GROUP = { ClassName = "GROUP", } + +--- Enumerator for location at airbases +-- @type GROUP.Takeoff +GROUP.Takeoff = { + Air = 1, + Runway = 2, + Hot = 3, + Cold = 4, +} + +GROUPTEMPLATE = {} + +GROUPTEMPLATE.Takeoff = { + [GROUP.Takeoff.Air] = "Turning Point", + [GROUP.Takeoff.Runway] = "TakeOff", + [GROUP.Takeoff.Hot] = "TakeOffParkingHot", + [GROUP.Takeoff.Cold] = "TakeOffParking", +} + --- Create a new GROUP from a DCSGroup -- @param #GROUP self -- @param Dcs.DCSWrapper.Group#Group GroupName The DCS Group name diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index c949da431..fbe5421b0 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -31,7 +31,18 @@ -- -- The POSITIONABLE class provides the following functions to construct a POSITIONABLE instance: -- --- * @{Positionable#POSITIONABLE.New}(): Create a POSITIONABLE instance. +-- * @{#POSITIONABLE.New}(): Create a POSITIONABLE instance. +-- +-- ## Get the current speed +-- +-- There are 3 methods that can be used to determine the speed. +-- Use @{#POSITIONABLE.GetVelocityKMH}() to retrieve the current speed in km/h. Use @{#POSITIONABLE.GetVelocityMPS}() to retrieve the speed in meters per second. +-- The method @{#POSITIONABLE.GetVelocity}() returns the speed vector (a Vec3). +-- +-- ## Get the current altitude +-- +-- Altitude can be retrieved using the method @{#POSITIONABLE.GetHeight}() and returns the current altitude in meters from the orthonormal plane. +-- -- -- @field #POSITIONABLE POSITIONABLE = { @@ -371,6 +382,25 @@ function POSITIONABLE:GetVelocityKMH() return nil end +--- Returns the POSITIONABLE velocity in meters per second. +-- @param Wrapper.Positionable#POSITIONABLE self +-- @return #number The velocity in meters per second. +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:GetVelocityMPS() + self:F2( self.PositionableName ) + + local DCSPositionable = self:GetDCSObject() + + if DCSPositionable then + local VelocityVec3 = self:GetVelocity() + local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec + self:T3( Velocity ) + return Velocity + end + + return nil +end + --- Returns the message text with the callsign embedded (if there is one). -- @param #POSITIONABLE self diff --git a/Moose Mission Setup/Moose.files b/Moose Mission Setup/Moose.files index 55aba83d6..e708d9016 100644 --- a/Moose Mission Setup/Moose.files +++ b/Moose Mission Setup/Moose.files @@ -41,6 +41,11 @@ Functional/Detection.lua Functional/Designate.lua AI/AI_Balancer.lua +AI/AI_A2A.lua +AI/AI_A2A_Patrol.lua +AI/AI_A2A_Cap.lua +AI/AI_A2A_Gci.lua +AI/AI_A2A_Dispatcher.lua AI/AI_Patrol.lua AI/AI_Cap.lua AI/AI_Cas.lua diff --git a/Moose Mission Setup/Moose.lua b/Moose Mission Setup/Moose.lua index 0e64ca6af..a8c9d24a3 100644 --- a/Moose Mission Setup/Moose.lua +++ b/Moose Mission Setup/Moose.lua @@ -1,5 +1,5 @@ env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20170522_1100' ) +env.info( 'Moose Generation Timestamp: 20170612_0516' ) local base = _G @@ -60,6 +60,11 @@ __Moose.Include( 'Functional/AirbasePolice.lua' ) __Moose.Include( 'Functional/Detection.lua' ) __Moose.Include( 'Functional/Designate.lua' ) __Moose.Include( 'AI/AI_Balancer.lua' ) +__Moose.Include( 'AI/AI_A2A.lua' ) +__Moose.Include( 'AI/AI_A2A_Patrol.lua' ) +__Moose.Include( 'AI/AI_A2A_Cap.lua' ) +__Moose.Include( 'AI/AI_A2A_Gci.lua' ) +__Moose.Include( 'AI/AI_A2A_Dispatcher.lua' ) __Moose.Include( 'AI/AI_Patrol.lua' ) __Moose.Include( 'AI/AI_Cap.lua' ) __Moose.Include( 'AI/AI_Cas.lua' ) diff --git a/Utils/Slate Documentation Generator/bin/TreeHierarchy.csv b/Utils/Slate Documentation Generator/bin/TreeHierarchy.csv index fbf810e65..90e2e74d1 100644 --- a/Utils/Slate Documentation Generator/bin/TreeHierarchy.csv +++ b/Utils/Slate Documentation Generator/bin/TreeHierarchy.csv @@ -39,3 +39,5 @@ @K=function, @M=Designate, @N=OnAfterStatus, @P=DESIGNATE , @F=../../../MOOSE/Moose Development/Moose\Functional\Designate.lua, @C=15822, @K=function, @M=Designate, @N=Status, @P=DESIGNATE , @F=../../../MOOSE/Moose Development/Moose\Functional\Designate.lua, @C=16043, @K=function, @M=Designate, @N=__Status, @P=DESIGNATE , @F=../../../MOOSE/Moose Development/Moose\Functional\Designate.lua, @C=16166, +@K=function, @M=AI_A2A_Dispatcher, @N=onafterHome, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\AI\AI_A2A_Dispatcher.lua, @C=65028, +@K=function, @M=AI_A2A_Dispatcher, @N=onafterHome, @P=Fsm, @F=../../../MOOSE/Moose Development/Moose\AI\AI_A2A_Dispatcher.lua, @C=69237, diff --git a/docs/Documentation/AI_A2A.html b/docs/Documentation/AI_A2A.html new file mode 100644 index 000000000..c29b58938 --- /dev/null +++ b/docs/Documentation/AI_A2A.html @@ -0,0 +1,1822 @@ + + + + + + +
+
+ +
+
+
+
+ +
+

Module AI_A2A

+ +

AI -- AI A2A Air Patrolling or Staging.

+ +
+ +

Author: Sven Van de Velde (FlightControl)

+

Contributions:

+ +
    +
  • Dutch_Baron: Working together with James has resulted in the creation of the AI_BALANCER class.
  • +
+ + +

James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) + * Pikey: Testing and API concept review.

+ +
+ + +

Global(s)

+ + + + + +
AI_A2A +

AI_A2A class, extends Fsm#FSM_CONTROLLABLE

+ +

The AI_A2A class implements the core functions to operate an AI Group A2A tasking.

+
+

Type AI_A2A

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AI_A2A.CheckStatus + +
AI_A2A:ClearTargetDistance() + +
AI_A2A:GetDispatcher() + +
AI_A2A.HomeAirbase + +
AI_A2A:ManageDamage(PatrolDamageTreshold) +

When the AI is damaged beyond a certain treshold, it is required that the AI returns to the home base.

+
AI_A2A:ManageFuel(PatrolFuelTresholdPercentage, PatrolOutOfFuelOrbitTime) +

When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.

+
AI_A2A:New(AIGroup) +

Creates a new AI_A2A object

+
AI_A2A:OnAfterRTB(Controllable, From, Event, To) +

OnAfter Transition Handler for Event RTB.

+
AI_A2A:OnAfterStart(From, Event, To) +

Start Handler OnAfter for AI_A2A

+
AI_A2A:OnAfterStatus(Controllable, From, Event, To) +

OnAfter Transition Handler for Event Status.

+
AI_A2A:OnAfterStop(Controllable, From, Event, To) +

OnAfter Transition Handler for Event Stop.

+
AI_A2A:OnBeforeRTB(Controllable, From, Event, To) +

OnBefore Transition Handler for Event RTB.

+
AI_A2A:OnBeforeStart(From, Event, To) +

Start Handler OnBefore for AI_A2A

+
AI_A2A:OnBeforeStatus(Controllable, From, Event, To) +

OnBefore Transition Handler for Event Status.

+
AI_A2A:OnBeforeStop(Controllable, From, Event, To) +

OnBefore Transition Handler for Event Stop.

+
AI_A2A:OnCrash(EventData) + +
AI_A2A:OnEjection(EventData) + +
AI_A2A:OnEnterReturning(Controllable, From, Event, To) +

OnEnter Transition Handler for State Returning.

+
AI_A2A:OnEnterStopped(Controllable, From, Event, To) +

OnEnter Transition Handler for State Stopped.

+
AI_A2A:OnLeaveReturning(Controllable, From, Event, To) +

OnLeave Transition Handler for State Returning.

+
AI_A2A:OnLeaveStopped(Controllable, From, Event, To) +

OnLeave Transition Handler for State Stopped.

+
AI_A2A:OnPilotDead(EventData) + +
AI_A2A.PatrolCeilingAltitude + +
AI_A2A.PatrolDamageTreshold + +
AI_A2A.PatrolFloorAltitude + +
AI_A2A.PatrolFuelTresholdPercentage + +
AI_A2A.PatrolManageDamage + +
AI_A2A.PatrolManageFuel + +
AI_A2A.PatrolMaxSpeed + +
AI_A2A.PatrolMinSpeed + +
AI_A2A.PatrolOutOfFuelOrbitTime + +
AI_A2A:RTB() +

Synchronous Event Trigger for Event RTB.

+
AI_A2A.RTBRoute(AIGroup) + +
AI_A2A:SetAltitude(PatrolFloorAltitude, PatrolCeilingAltitude) +

Sets the floor and ceiling altitude of the patrol.

+
AI_A2A:SetDispatcher(Dispatcher) + +
AI_A2A:SetHomeAirbase(HomeAirbase) +

Sets the home airbase.

+
AI_A2A:SetSpeed(PatrolMinSpeed, PatrolMaxSpeed) +

Sets (modifies) the minimum and maximum speed of the patrol.

+
AI_A2A:SetStatusOff() +

Set the status checking off.

+
AI_A2A:SetTargetDistance(Coordinate) + +
AI_A2A:Start() +

Start Trigger for AI_A2A

+
AI_A2A:Status() +

Synchronous Event Trigger for Event Status.

+
AI_A2A:Stop() +

Synchronous Event Trigger for Event Stop.

+
AI_A2A:__RTB(Delay) +

Asynchronous Event Trigger for Event RTB.

+
AI_A2A:__Start(Delay) +

Start Asynchronous Trigger for AI_A2A

+
AI_A2A:__Status(Delay) +

Asynchronous Event Trigger for Event Status.

+
AI_A2A:__Stop(Delay) +

Asynchronous Event Trigger for Event Stop.

+
AI_A2A:onafterDead() + +
AI_A2A:onafterHome(AIGroup, From, Event, To) + +
AI_A2A:onafterRTB(AIGroup, From, Event, To) + +
AI_A2A:onafterStart(Controllable, From, Event, To) +

Defines a new patrol route using the Process_PatrolZone parameters and settings.

+
AI_A2A:onafterStatus() + +
AI_A2A:onbeforeStatus() + +
+ +

Global(s)

+
+
+ + #AI_A2A + +AI_A2A + +
+
+ +

AI_A2A class, extends Fsm#FSM_CONTROLLABLE

+ +

The AI_A2A class implements the core functions to operate an AI Group A2A tasking.

+ + + + +

AI_A2A constructor

+ + + +

2. AI_A2A is a FSM

+ +

Process

+ +

2.1. AI_A2A States

+ +
    +
  • None ( Group ): The process is not started yet.
  • +
  • Patrolling ( Group ): The AI is patrolling the Patrol Zone.
  • +
  • Returning ( Group ): The AI is returning to Base.
  • +
  • Stopped ( Group ): The process is stopped.
  • +
  • Crashed ( Group ): The AI has crashed or is dead.
  • +
+ +

2.2. AI_A2A Events

+ +
    +
  • Start ( Group ): Start the process.
  • +
  • Stop ( Group ): Stop the process.
  • +
  • Route ( Group ): Route the AI to a new random 3D point within the Patrol Zone.
  • +
  • RTB ( Group ): Route the AI to the home base.
  • +
  • Detect ( Group ): The AI is detecting targets.
  • +
  • Detected ( Group ): The AI has detected new targets.
  • +
  • Status ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
  • +
+ +

3. Set or Get the AI controllable

+ + + + +
+
+

Type AI_A2A

+

Field(s)

+
+
+ + #boolean + +AI_A2A.CheckStatus + +
+
+ + + +
+
+
+
+ + +AI_A2A:ClearTargetDistance() + +
+
+ + + +
+
+
+
+ + +AI_A2A:GetDispatcher() + +
+
+ + + +
+
+
+
+ + + +AI_A2A.HomeAirbase + +
+
+ + + +
+
+
+
+ + +AI_A2A:ManageDamage(PatrolDamageTreshold) + +
+
+ +

When the AI is damaged beyond a certain treshold, it is required that the AI returns to the home base.

+ + +

However, damage cannot be foreseen early on. +Therefore, when the damage treshold is reached, +the AI will return immediately to the home base (RTB). +Note that for groups, the average damage of the complete group will be calculated. +So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage treshold will be 0.25.

+ +

Parameter

+
    +
  • + +

    #number PatrolDamageTreshold : +The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.

    + +
  • +
+

Return value

+ +

#AI_A2A: +self

+ +
+
+
+
+ + +AI_A2A:ManageFuel(PatrolFuelTresholdPercentage, PatrolOutOfFuelOrbitTime) + +
+
+ +

When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.

+ + +

Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated. +When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_A2A. +Once the time is finished, the old AI will return to the base.

+ +

Parameters

+
    +
  • + +

    #number PatrolFuelTresholdPercentage : +The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.

    + +
  • +
  • + +

    #number PatrolOutOfFuelOrbitTime : +The amount of seconds the out of fuel AIControllable will orbit before returning to the base.

    + +
  • +
+

Return value

+ +

#AI_A2A: +self

+ +
+
+
+
+ + +AI_A2A:New(AIGroup) + +
+
+ +

Creates a new AI_A2A object

+ +

Parameter

+ +

Return value

+ +

#AI_A2A:

+ + +
+
+
+
+ + +AI_A2A:OnAfterRTB(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event RTB.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A:OnAfterStart(From, Event, To) + +
+
+ +

Start Handler OnAfter for AI_A2A

+ +

Parameters

+
    +
  • + +

    #string From :

    + +
  • +
  • + +

    #string Event :

    + +
  • +
  • + +

    #string To :

    + +
  • +
+
+
+
+
+ + +AI_A2A:OnAfterStatus(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Status.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A:OnAfterStop(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Stop.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A:OnBeforeRTB(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event RTB.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A:OnBeforeStart(From, Event, To) + +
+
+ +

Start Handler OnBefore for AI_A2A

+ +

Parameters

+
    +
  • + +

    #string From :

    + +
  • +
  • + +

    #string Event :

    + +
  • +
  • + +

    #string To :

    + +
  • +
+

Return value

+ +

#boolean:

+ + +
+
+
+
+ + +AI_A2A:OnBeforeStatus(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Status.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A:OnBeforeStop(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Stop.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A:OnCrash(EventData) + +
+
+ + + +

Parameter

+ +
+
+
+
+ + +AI_A2A:OnEjection(EventData) + +
+
+ + + +

Parameter

+ +
+
+
+
+ + +AI_A2A:OnEnterReturning(Controllable, From, Event, To) + +
+
+ +

OnEnter Transition Handler for State Returning.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A:OnEnterStopped(Controllable, From, Event, To) + +
+
+ +

OnEnter Transition Handler for State Stopped.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A:OnLeaveReturning(Controllable, From, Event, To) + +
+
+ +

OnLeave Transition Handler for State Returning.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A:OnLeaveStopped(Controllable, From, Event, To) + +
+
+ +

OnLeave Transition Handler for State Stopped.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A:OnPilotDead(EventData) + +
+
+ + + +

Parameter

+ +
+
+
+
+ + + +AI_A2A.PatrolCeilingAltitude + +
+
+ + + +
+
+
+
+ + + +AI_A2A.PatrolDamageTreshold + +
+
+ + + +
+
+
+
+ + + +AI_A2A.PatrolFloorAltitude + +
+
+ + + +
+
+
+
+ + + +AI_A2A.PatrolFuelTresholdPercentage + +
+
+ + + +
+
+
+
+ + #boolean + +AI_A2A.PatrolManageDamage + +
+
+ + + +
+
+
+
+ + #boolean + +AI_A2A.PatrolManageFuel + +
+
+ + + +
+
+
+
+ + + +AI_A2A.PatrolMaxSpeed + +
+
+ + + +
+
+
+
+ + + +AI_A2A.PatrolMinSpeed + +
+
+ + + +
+
+
+
+ + + +AI_A2A.PatrolOutOfFuelOrbitTime + +
+
+ + + +
+
+
+
+ + +AI_A2A:RTB() + +
+
+ +

Synchronous Event Trigger for Event RTB.

+ +
+
+
+
+ + +AI_A2A.RTBRoute(AIGroup) + +
+
+ + + +

Parameter

+ +
+
+
+
+ + +AI_A2A:SetAltitude(PatrolFloorAltitude, PatrolCeilingAltitude) + +
+
+ +

Sets the floor and ceiling altitude of the patrol.

+ +

Parameters

+
    +
  • + +

    Dcs.DCSTypes#Altitude PatrolFloorAltitude : +The lowest altitude in meters where to execute the patrol.

    + +
  • +
  • + +

    Dcs.DCSTypes#Altitude PatrolCeilingAltitude : +The highest altitude in meters where to execute the patrol.

    + +
  • +
+

Return value

+ +

#AI_A2A: +self

+ +
+
+
+
+ + +AI_A2A:SetDispatcher(Dispatcher) + +
+
+ + + +

Parameter

+
    +
  • + +

    Dispatcher :

    + +
  • +
+
+
+
+
+ + +AI_A2A:SetHomeAirbase(HomeAirbase) + +
+
+ +

Sets the home airbase.

+ +

Parameter

+ +

Return value

+ +

#AI_A2A: +self

+ +
+
+
+
+ + +AI_A2A:SetSpeed(PatrolMinSpeed, PatrolMaxSpeed) + +
+
+ +

Sets (modifies) the minimum and maximum speed of the patrol.

+ +

Parameters

+ +

Return value

+ +

#AI_A2A: +self

+ +
+
+
+
+ + +AI_A2A:SetStatusOff() + +
+
+ +

Set the status checking off.

+ +

Return value

+ +

#AI_A2A: +self

+ +
+
+
+
+ + +AI_A2A:SetTargetDistance(Coordinate) + +
+
+ + + +

Parameter

+
    +
  • + +

    Coordinate :

    + +
  • +
+
+
+
+
+ + +AI_A2A:Start() + +
+
+ +

Start Trigger for AI_A2A

+ +
+
+
+
+ + +AI_A2A:Status() + +
+
+ +

Synchronous Event Trigger for Event Status.

+ +
+
+
+
+ + +AI_A2A:Stop() + +
+
+ +

Synchronous Event Trigger for Event Stop.

+ +
+
+
+
+ + +AI_A2A:__RTB(Delay) + +
+
+ +

Asynchronous Event Trigger for Event RTB.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A:__Start(Delay) + +
+
+ +

Start Asynchronous Trigger for AI_A2A

+ +

Parameter

+
    +
  • + +

    #number Delay :

    + +
  • +
+
+
+
+
+ + +AI_A2A:__Status(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Status.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A:__Stop(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Stop.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A:onafterDead() + +
+
+ + + +
+
+
+
+ + +AI_A2A:onafterHome(AIGroup, From, Event, To) + +
+
+ + + +

Parameters

+ +
+
+
+
+ + +AI_A2A:onafterRTB(AIGroup, From, Event, To) + +
+
+ + + +

Parameters

+ +
+
+
+
+ + +AI_A2A:onafterStart(Controllable, From, Event, To) + +
+
+ +

Defines a new patrol route using the Process_PatrolZone parameters and settings.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#AI_A2A: +self

+ +
+
+
+
+ + +AI_A2A:onafterStatus() + +
+
+ + + +
+
+
+
+ + +AI_A2A:onbeforeStatus() + +
+
+ + + +
+
+ +
+ +
+ + diff --git a/docs/Documentation/AI_A2A_Cap.html b/docs/Documentation/AI_A2A_Cap.html new file mode 100644 index 000000000..e16f6b1ec --- /dev/null +++ b/docs/Documentation/AI_A2A_Cap.html @@ -0,0 +1,1712 @@ + + + + + + +
+
+ +
+
+
+
+ +
+

Module AI_A2A_Cap

+ +

AI -- Execute Combat Air Patrol (CAP).

+ +

Banner Image

+ +
+ +

AI CAP classes makes AI Controllables execute a Combat Air Patrol.

+ + + +

There are the following types of CAP classes defined:

+ + + +
+ +

Author: Sven Van de Velde (FlightControl)

+ +

Contributions:

+ + + +
+ + +

Global(s)

+ + + + + +
AI_A2A_CAP +

AIA2ACAP class, extends AICAP#AIPATROL_ZONE

+ +

The AIA2ACAP class implements the core functions to patrol a Zone by an AI Controllable or Group +and automatically engage any airborne enemies that are within a certain range or within a certain zone.

+
+

Type AI_A2A_CAP

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AI_A2A_CAP:Abort() +

Synchronous Event Trigger for Event Abort.

+
AI_A2A_CAP:Accomplish() +

Synchronous Event Trigger for Event Accomplish.

+
AI_A2A_CAP.Accomplished + +
AI_A2A_CAP.AttackRoute(AIGroup) + +
AI_A2A_CAP.AttackSetUnit + +
AI_A2A_CAP:Destroy() +

Synchronous Event Trigger for Event Destroy.

+
AI_A2A_CAP:Engage() +

Synchronous Event Trigger for Event Engage.

+
AI_A2A_CAP.EngageMaxSpeed + +
AI_A2A_CAP.EngageMinSpeed + +
AI_A2A_CAP.EngageRange + +
AI_A2A_CAP.EngageZone + +
AI_A2A_CAP.Engaging + +
AI_A2A_CAP:Fired() +

Synchronous Event Trigger for Event Fired.

+
AI_A2A_CAP:New(AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType) +

Creates a new AIA2ACAP object

+
AI_A2A_CAP:OnAfterAbort(Controllable, From, Event, To) +

OnAfter Transition Handler for Event Abort.

+
AI_A2A_CAP:OnAfterAccomplish(Controllable, From, Event, To) +

OnAfter Transition Handler for Event Accomplish.

+
AI_A2A_CAP:OnAfterDestroy(Controllable, From, Event, To) +

OnAfter Transition Handler for Event Destroy.

+
AI_A2A_CAP:OnAfterEngage(Controllable, From, Event, To) +

OnAfter Transition Handler for Event Engage.

+
AI_A2A_CAP:OnAfterFired(Controllable, From, Event, To) +

OnAfter Transition Handler for Event Fired.

+
AI_A2A_CAP:OnBeforeAbort(Controllable, From, Event, To) +

OnBefore Transition Handler for Event Abort.

+
AI_A2A_CAP:OnBeforeAccomplish(Controllable, From, Event, To) +

OnBefore Transition Handler for Event Accomplish.

+
AI_A2A_CAP:OnBeforeDestroy(Controllable, From, Event, To) +

OnBefore Transition Handler for Event Destroy.

+
AI_A2A_CAP:OnBeforeEngage(Controllable, From, Event, To) +

OnBefore Transition Handler for Event Engage.

+
AI_A2A_CAP:OnBeforeFired(Controllable, From, Event, To) +

OnBefore Transition Handler for Event Fired.

+
AI_A2A_CAP:OnEnterEngaging(Controllable, From, Event, To) +

OnEnter Transition Handler for State Engaging.

+
AI_A2A_CAP:OnEventDead(EventData) + +
AI_A2A_CAP:OnLeaveEngaging(Controllable, From, Event, To) +

OnLeave Transition Handler for State Engaging.

+
AI_A2A_CAP:SetEngageRange(EngageRange) +

Set the Engage Range when the AI will engage with airborne enemies.

+
AI_A2A_CAP:SetEngageZone(EngageZone) +

Set the Engage Zone which defines where the AI will engage bogies.

+
AI_A2A_CAP:__Abort(Delay) +

Asynchronous Event Trigger for Event Abort.

+
AI_A2A_CAP:__Accomplish(Delay) +

Asynchronous Event Trigger for Event Accomplish.

+
AI_A2A_CAP:__Destroy(Delay) +

Asynchronous Event Trigger for Event Destroy.

+
AI_A2A_CAP:__Engage(Delay) +

Asynchronous Event Trigger for Event Engage.

+
AI_A2A_CAP:__Fired(Delay) +

Asynchronous Event Trigger for Event Fired.

+
AI_A2A_CAP:onafterAbort(AIGroup, From, Event, To) + +
AI_A2A_CAP:onafterAccomplish(Controllable, From, Event, To) + +
AI_A2A_CAP:onafterDestroy(Controllable, From, Event, To, EventData) + +
AI_A2A_CAP:onafterEngage(AIGroup, From, Event, To, AttackSetUnit) + +
AI_A2A_CAP:onafterPatrol(AIGroup, From, Event, To) +

onafter State Transition for Event Patrol.

+
AI_A2A_CAP:onbeforeEngage(AIGroup, From, Event, To) + +
+ +

Global(s)

+
+
+ + #AI_A2A_CAP + +AI_A2A_CAP + +
+
+ +

AIA2ACAP class, extends AICAP#AIPATROL_ZONE

+ +

The AIA2ACAP class implements the core functions to patrol a Zone by an AI Controllable or Group +and automatically engage any airborne enemies that are within a certain range or within a certain zone.

+ + + +

Process

+ +

The AIA2ACAP is assigned a Group and this must be done before the AIA2ACAP process can be started using the Start event.

+ +

Process

+ +

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.

+ +

Process

+ +

This cycle will continue.

+ +

Process

+ +

During the patrol, the AI will detect enemy targets, which are reported through the Detected event.

+ +

Process

+ +

When enemies are detected, the AI will automatically engage the enemy.

+ +

Process

+ +

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.

+ +

Process

+ +

1. AIA2ACAP constructor

+ + + +

2. AIA2ACAP is a FSM

+ +

Process

+ +

2.1 AIA2ACAP 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 AIA2ACAP Events

+ + + +

3. Set the Range of Engagement

+ +

Range

+ +

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 AICAP#AIA2A_CAP.SetEngageRange() to define that range.

+ +

4. Set the Zone of Engagement

+ +

Zone

+ +

An optional Zone can be set, +that will define when the AI will engage with the detected airborne enemy targets. +Use the method AICap#AIA2A_CAP.SetEngageZone() to define that Zone.

+ +
+ + +
+
+

Type AI_A2A_Cap

+ +

Type AI_A2A_CAP

+

Field(s)

+
+
+ + +AI_A2A_CAP:Abort() + +
+
+ +

Synchronous Event Trigger for Event Abort.

+ +
+
+
+
+ + +AI_A2A_CAP:Accomplish() + +
+
+ +

Synchronous Event Trigger for Event Accomplish.

+ +
+
+
+
+ + #boolean + +AI_A2A_CAP.Accomplished + +
+
+ + + +
+
+
+
+ + +AI_A2A_CAP.AttackRoute(AIGroup) + +
+
+ + + +

Parameter

+ +
+
+
+
+ + Core.Set#SET_UNIT + +AI_A2A_CAP.AttackSetUnit + +
+
+ + + +
+
+
+
+ + +AI_A2A_CAP:Destroy() + +
+
+ +

Synchronous Event Trigger for Event Destroy.

+ +
+
+
+
+ + +AI_A2A_CAP:Engage() + +
+
+ +

Synchronous Event Trigger for Event Engage.

+ +
+
+
+
+ + + +AI_A2A_CAP.EngageMaxSpeed + +
+
+ + + +
+
+
+
+ + + +AI_A2A_CAP.EngageMinSpeed + +
+
+ + + +
+
+
+
+ + + +AI_A2A_CAP.EngageRange + +
+
+ + + +
+
+
+
+ + + +AI_A2A_CAP.EngageZone + +
+
+ + + +
+
+
+
+ + #boolean + +AI_A2A_CAP.Engaging + +
+
+ + + +
+
+
+
+ + +AI_A2A_CAP:Fired() + +
+
+ +

Synchronous Event Trigger for Event Fired.

+ +
+
+
+
+ + +AI_A2A_CAP:New(AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType) + +
+
+ +

Creates a new AIA2ACAP object

+ +

Parameters

+ +

Return value

+ +

#AIA2ACAP:

+ + +
+
+
+
+ + +AI_A2A_CAP:OnAfterAbort(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Abort.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:OnAfterAccomplish(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Accomplish.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:OnAfterDestroy(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Destroy.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:OnAfterEngage(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Engage.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:OnAfterFired(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Fired.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:OnBeforeAbort(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Abort.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A_CAP:OnBeforeAccomplish(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Accomplish.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A_CAP:OnBeforeDestroy(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Destroy.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A_CAP:OnBeforeEngage(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Engage.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A_CAP:OnBeforeFired(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Fired.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A_CAP:OnEnterEngaging(Controllable, From, Event, To) + +
+
+ +

OnEnter Transition Handler for State Engaging.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:OnEventDead(EventData) + +
+
+ + + +

Parameter

+ +
+
+
+
+ + +AI_A2A_CAP:OnLeaveEngaging(Controllable, From, Event, To) + +
+
+ +

OnLeave Transition Handler for State Engaging.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A_CAP:SetEngageRange(EngageRange) + +
+
+ +

Set the Engage Range when the AI will engage with airborne enemies.

+ +

Parameter

+
    +
  • + +

    #number EngageRange : +The Engage Range.

    + +
  • +
+

Return value

+ +

#AIA2ACAP: +self

+ +
+
+
+
+ + +AI_A2A_CAP:SetEngageZone(EngageZone) + +
+
+ +

Set the Engage Zone which defines where the AI will engage bogies.

+ +

Parameter

+
    +
  • + +

    Core.Zone#ZONE EngageZone : +The zone where the AI is performing CAP.

    + +
  • +
+

Return value

+ +

#AIA2ACAP: +self

+ +
+
+
+
+ + +AI_A2A_CAP:__Abort(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Abort.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:__Accomplish(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Accomplish.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:__Destroy(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Destroy.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:__Engage(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Engage.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:__Fired(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Fired.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:onafterAbort(AIGroup, From, Event, To) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE AIGroup : +The AI Group managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:onafterAccomplish(Controllable, From, Event, To) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:onafterDestroy(Controllable, From, Event, To, EventData) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
  • + +

    Core.Event#EVENTDATA EventData :

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:onafterEngage(AIGroup, From, Event, To, AttackSetUnit) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE AIGroup : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
  • + +

    AttackSetUnit :

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:onafterPatrol(AIGroup, From, Event, To) + +
+
+ +

onafter State Transition for Event Patrol.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE AIGroup : +The AI Group managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_CAP:onbeforeEngage(AIGroup, From, Event, To) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE AIGroup : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+ +
+ +
+ + diff --git a/docs/Documentation/AI_A2A_Dispatcher.html b/docs/Documentation/AI_A2A_Dispatcher.html new file mode 100644 index 000000000..ec26e3638 --- /dev/null +++ b/docs/Documentation/AI_A2A_Dispatcher.html @@ -0,0 +1,3159 @@ + + + + + + +
+
+ +
+
+
+
+ +
+

Module AI_A2A_Dispatcher

+ +

AI - The AIA2ADISPATCHER creates an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI.

+ + + +
+ +

Authors: Sven Van de Velde (FlightControl)

+
         **Stonehouse**
+
+ +

Contributions:

+ +
+ + +

Global(s)

+ + + + + +
AI_A2A_DISPATCHER +

AIA2ADISPATCHER class, extends Tasking#DETECTION_MANAGER

+ +

The #AIA2ADISPATCHER class is designed to create an automatic air defence system for a coalition.

+
+

Type AI_A2A_DISPATCHER

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AI_A2A_DISPATCHER:AddDefenderToSquadron(Squadron, Defender) + +
AI_A2A_DISPATCHER:CAP() +

CAP Trigger for AIA2ADISPATCHER

+
AI_A2A_DISPATCHER:CanCAP(SquadronName) + +
AI_A2A_DISPATCHER:CanGCI(SquadronName) + +
AI_A2A_DISPATCHER:ClearDefenderTask(Defender) + +
AI_A2A_DISPATCHER:ClearDefenderTaskTarget(Defender) + +
AI_A2A_DISPATCHER:CountCapAirborne(SquadronName) + +
AI_A2A_DISPATCHER:CountDefendersEngaged(Target) + +
AI_A2A_DISPATCHER:CountDefendersToBeEngaged(DetectedItem, DefenderCount) + +
AI_A2A_DISPATCHER.DefenderSpawns + +
AI_A2A_DISPATCHER.DefenderSquadrons + +
AI_A2A_DISPATCHER.DefenderTasks + +
AI_A2A_DISPATCHER.Defenders + +
AI_A2A_DISPATCHER.Detection + +
AI_A2A_DISPATCHER:ENGAGE() +

ENGAGE Trigger for AIA2ADISPATCHER

+
AI_A2A_DISPATCHER:EvaluateENGAGE(DetectedItem) +

Creates an ENGAGE task when there are human friendlies airborne near the targets.

+
AI_A2A_DISPATCHER:EvaluateGCI(DetectedItem, Target) +

Creates an GCI task when there are targets for it.

+
AI_A2A_DISPATCHER:EvaluateSWEEP(DetectedItem) +

Creates an SWEEP task when there are targets for it.

+
AI_A2A_DISPATCHER:GCI() +

GCI Trigger for AIA2ADISPATCHER

+
AI_A2A_DISPATCHER:GetAIFriendliesNearBy(DetectedItem) +

Calculates which AI friendlies are nearby the area

+
AI_A2A_DISPATCHER:GetCAPDelay(SquadronName) + +
AI_A2A_DISPATCHER:GetDefenderTask(Defender) + +
AI_A2A_DISPATCHER:GetDefenderTaskFsm(Defender) + +
AI_A2A_DISPATCHER:GetDefenderTaskTarget(Defender) + +
AI_A2A_DISPATCHER:GetDefenderTasks() + +
AI_A2A_DISPATCHER:GetFriendliesNearBy(DetectedItem, Target) +

Calculates which friendlies are nearby the area

+
AI_A2A_DISPATCHER:GetPlayerFriendliesNearBy(DetectedItem) +

Calculates which HUMAN friendlies are nearby the area

+
AI_A2A_DISPATCHER:GetSquadron(SquadronName) +

Get an item from the Squadron table.

+
AI_A2A_DISPATCHER:GetSquadronFromDefender(Defender) + +
AI_A2A_DISPATCHER:GetSquadronLanding(SquadronName) +

Gets the method at which flights will land and despawn as part of the defense system.

+
AI_A2A_DISPATCHER:GetSquadronTakeoff(SquadronName) +

Gets the method at which new flights will spawn and take-off as part of the defense system.

+
AI_A2A_DISPATCHER.Landing +

Defnes Landing location.

+
AI_A2A_DISPATCHER:New(The, DetectionSetGroup, GroupingRadius) +

AIA2ADISPATCHER constructor.

+
AI_A2A_DISPATCHER:OnAfterAssign(From, Event, To, Task, TaskUnit, PlayerName) +

OnAfter Transition Handler for Event Assign.

+
AI_A2A_DISPATCHER:OnAfterCAP(From, Event, To) +

CAP Handler OnAfter for AIA2ADISPATCHER

+
AI_A2A_DISPATCHER:OnAfterENGAGE(From, Event, To) +

ENGAGE Handler OnAfter for AIA2ADISPATCHER

+
AI_A2A_DISPATCHER:OnAfterGCI(From, Event, To) +

GCI Handler OnAfter for AIA2ADISPATCHER

+
AI_A2A_DISPATCHER:OnBeforeCAP(From, Event, To) +

CAP Handler OnBefore for AIA2ADISPATCHER

+
AI_A2A_DISPATCHER:OnBeforeENGAGE(From, Event, To) +

ENGAGE Handler OnBefore for AIA2ADISPATCHER

+
AI_A2A_DISPATCHER:OnBeforeGCI(From, Event, To) +

GCI Handler OnBefore for AIA2ADISPATCHER

+
AI_A2A_DISPATCHER:OnEventCrashOrDead(EventData) + +
AI_A2A_DISPATCHER:OnEventEngineShutdown(EventData) + +
AI_A2A_DISPATCHER:OnEventLand(EventData) + +
AI_A2A_DISPATCHER:ProcessDetected(Detection) +

Assigns A2A AI Tasks in relation to the detected items.

+
AI_A2A_DISPATCHER:RemoveDefenderFromSquadron(Squadron, Defender) + +
AI_A2A_DISPATCHER.SchedulerCAP(AI_A2A_DISPATCHER, SquadronName, self) + +
AI_A2A_DISPATCHER:SetBorderZone(BorderZone) +

Define a border area to simulate a cold war scenario.

+
AI_A2A_DISPATCHER:SetDefenderTask(Defender, Type, Fsm, Target) + +
AI_A2A_DISPATCHER:SetDefenderTaskTarget(AIGroup, Defender, Target) + +
AI_A2A_DISPATCHER:SetEngageRadius(FriendliesRadius) +

Define the radius to engage any target by airborne friendlies, which are executing cap or returning from an intercept mission.

+
AI_A2A_DISPATCHER:SetSquadron(SquadronName, AirbaseName, SpawnTemplates, Resources) + +
AI_A2A_DISPATCHER:SetSquadronCap(SquadronName, Zone, FloorAltitude, CeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, AltType) + +
AI_A2A_DISPATCHER:SetSquadronCapInterval(SquadronName, CapLimit, LowInterval, HighInterval, Probability) + +
AI_A2A_DISPATCHER:SetSquadronGci(SquadronName, EngageMinSpeed, EngageMaxSpeed) + +
AI_A2A_DISPATCHER:SetSquadronGrouping(SquadronName, Grouping) + +
AI_A2A_DISPATCHER:SetSquadronLanding(SquadronName, Landing) +

Defines the method at which flights will land and despawn as part of the defense system.

+
AI_A2A_DISPATCHER:SetSquadronLandingAtEngineShutdown(SquadronName) +

Sets flights to land and despawn at engine shutdown, as part of the defense system.

+
AI_A2A_DISPATCHER:SetSquadronLandingAtRunway(SquadronName) +

Sets flights to land and despawn at the runway, as part of the defense system.

+
AI_A2A_DISPATCHER:SetSquadronLandingNearAirbase(SquadronName) +

Sets flights to land and despawn near the airbase in the air, as part of the defense system.

+
AI_A2A_DISPATCHER:SetSquadronOverhead(SquadronName, Overhead) +

Defines the amount of extra planes that will take-off as part of the defense system.

+
AI_A2A_DISPATCHER:SetSquadronTakeoff(SquadronName, Takeoff) +

Defines the method at which new flights will spawn and take-off as part of the defense system.

+
AI_A2A_DISPATCHER:SetSquadronTakeoffFromParkingCold(SquadronName) +

Sets flights to take-off from the airbase at a cold location, as part of the defense system.

+
AI_A2A_DISPATCHER:SetSquadronTakeoffFromParkingHot(SquadronName) +

Sets flights to take-off from the airbase at a hot location, as part of the defense system.

+
AI_A2A_DISPATCHER:SetSquadronTakeoffFromRunway(SquadronName) +

Sets flights to take-off from the runway, as part of the defense system.

+
AI_A2A_DISPATCHER:SetSquadronTakeoffInAir(SquadronName) +

Sets flights to take-off in the air, as part of the defense system.

+
AI_A2A_DISPATCHER:SetTacticalDisplay(TacticalDisplay) +

Display a tactical report every 30 seconds about which aircraft are: + * Patrolling + * Engaging + * Returning + * Damaged + * Out of Fuel + * ...

+
AI_A2A_DISPATCHER.TacticalDisplay + +
AI_A2A_DISPATCHER.Takeoff + +
AI_A2A_DISPATCHER:__CAP(Delay) +

CAP Asynchronous Trigger for AIA2ADISPATCHER

+
AI_A2A_DISPATCHER:__ENGAGE(Delay) +

ENGAGE Asynchronous Trigger for AIA2ADISPATCHER

+
AI_A2A_DISPATCHER:__GCI(Delay) +

GCI Asynchronous Trigger for AIA2ADISPATCHER

+
AI_A2A_DISPATCHER:onafterCAP(From, Event, To, SquadronName) + +
AI_A2A_DISPATCHER:onafterENGAGE(From, Event, To, Target, AIGroups) + +
AI_A2A_DISPATCHER:onafterGCI(From, Event, To, Target, DefendersMissing, AIGroups) + +
+ +

Global(s)

+
+
+ + #AI_A2A_DISPATCHER + +AI_A2A_DISPATCHER + +
+
+ +

AIA2ADISPATCHER class, extends Tasking#DETECTION_MANAGER

+ +

The #AIA2ADISPATCHER class is designed to create an automatic air defence system for a coalition.

+ + +

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. +CAP flights will take off and proceed to designated CAP zones where they will remain on station until the ground radars direct them to intercept detected enemy aircraft or they run short of fuel and must return to base (RTB). When a CAP flight leaves their zone to perform an interception or return to base a new CAP flight will spawn to take their place. +If all CAP flights are engaged or RTB then additional GCI interceptors will scramble to intercept unengaged enemy aircraft under ground radar control. +With a little time and with a little work it provides the mission designer with a convincing and completely automatic air defence system. +In short it is a plug in very flexible and configurable air defence module for DCS World.

+ +

Note that in order to create a two way A2A defense system, two AIA2ADISPATCHER defense system may need to be created, for each coalition one. +This is a good implementation, because maybe in the future, more coalitions may become available in DCS world.

+ +

1. AIA2ADISPATCHER constructor:

+ +

The AIA2ADISPATCHER.New() method creates a new AIA2ADISPATCHER instance. +There are two parameters required, a Set#SET_GROUP that defines the Groups of the EWR network, and a radius in meters, that will be used to group the detected targets.

+ +

The AIA2ADISPATCHER.New() method is used to setup the EWR network and to define the grouping.

+ +

1.1. Define the EWR network:

+ +

Typically EWR networks are setup using 55G6 EWR, 1L13 EWR, Hawk sr and Patriot str ground based radar units. +These radars have different ranges and 55G6 EWR and 1L13 EWR radars are Eastern Bloc units (eg Russia, Ukraine, Georgia) while the Hawk and Patriot radars are Western (eg US). +Additionally, ANY other radar capable unit can be part of the EWR network! Also AWACS airborne units, planes, helicopters can help to detect targets, as long as they have radar. +The position of these units is very important as they need to provide enough coverage +to pick up enemy aircraft as they approach so that CAP and GCI flights can be tasked to intercept them. +Additionally in a hot war situation where the border is no longer respected the placement of radars has a big effect on how fast the war escalates. +For example if they are a long way forward and can detect enemy planes on the ground and taking off +they will start to vector CAP and GCI flights to attack them straight away which will immediately draw a response from the other coalition. +Having the radars further back will mean a slower escalation because fewer targets will be detected and +therefore less CAP and GCI flights will spawn and this will tend to make just the border area active rather than a melee over the whole map. +It all depends on what the desired effect is.

+ +

EWR networks are dynamically constructed, that is, they form part of the Set#SET_GROUP object that is given as the input parameter of the AIA2ADISPATCHER class. +By defining in a smart way the names or name prefixes of the groups of EWR capable units, these units will be automatically added or deleted from the EWR network, +increasing or decreasing the radar coverage of the Early Warning System.

+ +

See the following example to setup an EWR network containing EWR stations and AWACS.

+ +
-- Define a SET_GROUP object that builds a collection of groups that define the EWR network.
+-- Here we build the network with all the groups that have a name starting with DF CCCP AWACS and DF CCCP EWR.
+DetectionSetGroup = SET_GROUP:New()
+DetectionSetGroup:FilterPrefixes( { "DF CCCP AWACS", "DF CCCP EWR" } )
+DetectionSetGroup:FilterStart()
+
+-- Setup the A2A dispatcher, and initialize it.
+A2ADispatcher = AI_A2A_DISPATCHER:New( DetectionSetGroup, 30000 )
+
+ +

The above example creates a SET_GROUP instance, and stores this in the variable (object) DetectionSetGroup. +DetectionSetGroup is then being configured to filter all active groups with a group name starting with DF CCCP AWACS or DF CCCP EWR to be included in the Set. +DetectionSetGroup is then being ordered to start the dynamic filtering. Note that any destroy or new spawn of a group with the above names will be removed or added to the Set. +The DetectionSetGroup variable is then passed to the AIA2ADISPATCHER.New() method to indicate the EWR network configuration and setup the A2A defense detection mechanism. +As a second parameter of the AIA2ADISPATCHER.New() method, 30000 indicates that detected targets need to be grouped within a radius of 30km. +The grouping radius should not be too small, but also depends on the types of planes and the era of the simulation. +Fast planes like in the 80s, need a larger radius than WWII planes.
+Typically I suggest to use 30000 for new generation planes and 10000 for older era aircraft.

+ +

Note that detected targets are constantly re-grouped, that is, when certain detected aircraft are moving further than the group radius, then these aircraft will become a separate +group being detected. This may result in additional GCI being started by the dispatcher! So don't make this value too small!

+ +

2. Set the engage radius:

+ +

Define the radius to engage any target by airborne friendlies, which are executing cap or returning from an intercept mission. +So, if there is a target area detected and reported, +then any friendlies that are airborne near this target area, +will be commanded to (re-)engage that target when available (if no other tasks were commanded). +For example, if 100000 is given as a value, then any friendly that is airborne within 100km from the detected target, +will be considered to receive the command to engage that target area. +You need to evaluate the value of this parameter carefully. +If too small, more intercept missions may be triggered upon detected target areas. +If too large, any airborne cap may not be able to reach the detected target area in time, because it is too far.

+ +

3. Set the borders:

+ +

According to the tactical and strategic design of the mission broadly decide the shape and extent of red and blue territories. +They should be laid out such that a border area is created between the two coalitions.

+ +

Define a border area to simulate a cold war scenario and use the method AIA2ADISPATCHER.SetBorderZone() to create a border zone for the dispatcher.

+ +

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. +If it’s a cold war then the borders of red and blue territory need to be defined using a zone object derived from Zone#ZONE_BASE. +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

+ +

4. Squadrons:

+ +

The AIA2ADISPATCHER works with Squadrons, that need to be defined using the different methods available.

+ +

Use the method AIA2ADISPATCHER.SetSquadron() to setup a new squadron active at an airfield, +while defining which plane types are being used by the squadron and how many resources are available.

+ +

Squadrons:

+ +
    +
  • Have name (string) that is the identifier or key of the squadron.
  • +
  • Have specific plane types.
  • +
  • Are located at one airbase.
  • +
  • Have a limited set of resources.
  • +
+ +

The name of the squadron given acts as the squadron key in the AIA2ADISPATCHER:Squadron...() methods.

+ +

Additionally, squadrons have specific configuration options to:

+ +
    +
  • Control how new aircraft are taking off from the airfield (in the air, cold, hot, at the runway).
  • +
  • Control how returning aircraft are landing at the airfield (in the air near the airbase, after landing, after engine shutdown).
  • +
  • Control the grouping of new aircraft spawned at the airfield. If there is more than one aircraft to be spawned, these may be grouped.
  • +
  • Control the overhead or defensive strength of the squadron. Depending on the types of planes and amount of resources, the mission designer can choose to increase or reduce the amount of planes spawned.
  • +
+ +

For performance and bug workaround reasons within DCS, squadrons have different methods to spawn new aircraft or land returning or damaged aircraft.

+ + +

4.1. Set squadron take-off methods

+ +

Use the various SetSquadronTakeoff... methods to control how squadrons are taking-off from the airfield:

+ + + +

Use these methods to fine-tune for specific airfields that are known to create bottlenecks, or have reduced airbase efficiency. +The more and the longer aircraft need to taxi at an airfield, the more risk there is that:

+ +
    +
  • aircraft will stop waiting for each other or for a landing aircraft before takeoff.
  • +
  • aircraft may get into a "dead-lock" situation, where two aircraft are blocking each other.
  • +
  • aircraft may collide at the airbase.
  • +
  • aircraft may be awaiting the landing of a plane currently in the air, but never lands ...
  • +
+ +

Currently within the DCS engine, the airfield traffic coordination is erroneous and contains a lot of bugs. +If you experience while testing problems with aircraft take-off or landing, please use one of the above methods as a solution to workaround these issues!

+ +

4.2. Set squadron landing methods

+ +

In analogy with takeoff, the landing methods are to control how squadrons land at the airfield:

+ + + +

You can use these methods to minimize the airbase coodination overhead and to increase the airbase efficiency. +When there are lots of aircraft returning for landing, at the same airbase, the takeoff process will be halted, which can cause a complete failure of the +A2A defense system, as no new CAP or GCI planes can takeoff. +Note that the method AIA2ADISPATCHER.SetSquadronLandingNearAirbase() will only work for returning aircraft, not for damaged or out of fuel aircraft. +Damaged or out-of-fuel aircraft are returning to the nearest friendly airbase and will land, and are out of control from ground control.

+ +

4.3. Set squadron grouping

+ +

Choices are 1, 2, 3 or 4 when CAP or GCI flights spawn. Use the method AIA2ADISPATCHER.SetSquadronGrouping() to set the amount of CAP or GCI flights that will take-off when spawned. +In the case of GCI, the AIA2ADISPATCHER.SetSquadronGrouping() method has additional behaviour. When there aren't enough CAP flights airborne, a GCI will be initiated for the remaining +targets to be engaged. Depending on the grouping parameter, the spawned flights for GCI are grouped into this setting.
+For example with a group setting of 2, if 3 targets are detected and cannot be engaged by CAP or any airborne flight, +a GCI needs to be started, the GCI flights will be grouped as follows: Group 1 of 2 flights and Group 2 of one flight!

+ +

The grouping value is set for a Squadron, and can be dynamically adjusted during mission execution, so to adjust the defense flights grouping when the tactical situation changes.

+ +

4.4. Balance or setup effectiveness of the air defenses in case of GCI

+ +

The effectiveness can be set with the overhead parameter. This is a number that is used to calculate the amount of Units that dispatching command will allocate to GCI in surplus of detected amount of units. +The default value of the overhead parameter is 1.0, which means equal balance.

+ +

However, depending on the (type of) aircraft (strength and payload) in the squadron and the amount of resources available, this parameter can be changed.

+ +

The AIA2ADISPATCHER.SetOverhead() method can be used to tweak the defense strength, +taking into account the plane types of the squadron.

+ +

For example, a MIG-31 with full long-distance A2A missiles payload, may still be less effective than a F-15C with short missiles... +So in this case, one may want to use the AIA2ADISPATCHER.SetOverhead() method to allocate more defending planes as the amount of detected attacking planes. +The overhead must be given as a decimal value with 1 as the neutral value, which means that overhead values:

+ +
    +
  • Higher than 1.0, for example 1.5, will increase the defense unit amounts. For 4 planes detected, 6 planes will be spawned.
  • +
  • Lower than 1, for example 0.75, will decrease the defense unit amounts. For 4 planes detected, only 3 planes will be spawned.
  • +
+ +

The amount of defending units is calculated by multiplying the amount of detected attacking planes as part of the detected group +multiplied by the Overhead and rounded up to the smallest integer.

+ +

The overhead value is set for a Squadron, and can be dynamically adjusted during mission execution, so to adjust the defense overhead when the tactical situation changes.

+ +

5. Setup a squadron for CAP

+ +

5.1. Set the CAP zones

+ +
    +
  • CAP zones are patrol areas where Combat Air Patrol (CAP) flights loiter until they either return to base due to low fuel or are assigned an interception task by ground control.

  • +
  • As the CAP flights wander around within the zone waiting to be tasked, these zones need to be large enough that the aircraft are not constantly turning + but do not have to be big and numerous enough to completely cover a border.

  • +
  • CAP zones can be of any type, and are derived from the Zone#ZONE_BASE class. Zones can be Zone#ZONE, Zone#ZONE_POLYGON, Zone#ZONE_UNIT, Zone#ZONE_GROUP, etc. + This allows to setup static, moving and/or complex zones wherein aircraft will perform the CAP.

  • +
  • Typically 20000-50000 metres width is used and they are spaced so that aircraft in the zone waiting for tasks don’t have to far to travel to protect their coalitions important targets. + These targets are chosen as part of the mission design and might be an important airfield or town etc. + Zone size is also determined somewhat by territory size, plane types + (eg WW2 aircraft might mean smaller zones or more zones because they are slower and take longer to intercept enemy aircraft).

  • +
  • In a cold war it is important to make sure a CAP zone doesn’t intrude into enemy territory as otherwise CAP flights will likely cross borders + and spark a full scale conflict which will escalate rapidly.

  • +
  • CAP flights do not need to be in the CAP zone before they are “on station” and ready for tasking.

  • +
  • Typically if a CAP flight is tasked and therefore leaves their zone empty while they go off and intercept their target another CAP flight will spawn to take their place.

  • +
+ +

The following example illustrates how CAP zones are coded:

+ +
 -- CAP Squadron execution.
+ CAPZoneEast = ZONE_POLYGON:New( "CAP Zone East", GROUP:FindByName( "CAP Zone East" ) )
+ A2ADispatcher:SetSquadronCap( "Mineralnye", CAPZoneEast, 4000, 10000, 500, 600, 800, 900 )
+ A2ADispatcher:SetSquadronCapInterval( "Mineralnye", 2, 30, 60, 1 )
+
+ CAPZoneWest = ZONE_POLYGON:New( "CAP Zone West", GROUP:FindByName( "CAP Zone West" ) )
+ A2ADispatcher:SetSquadronCap( "Sochi", CAPZoneWest, 4000, 8000, 600, 800, 800, 1200, "BARO" )
+ A2ADispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 )
+
+ CAPZoneMiddle = ZONE:New( "CAP Zone Middle")
+ A2ADispatcher:SetSquadronCap( "Maykop", CAPZoneMiddle, 4000, 8000, 600, 800, 800, 1200, "RADIO" )
+ A2ADispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 )
+
+ +

Note the different Zone MOOSE classes being used to create zones of different types. Please click the Zone link for more information about the different zone types. +Zones can be circles, can be setup in the mission editor using trigger zones, but can also be setup in the mission editor as polygons and in this case GROUP objects are being used!

+ +

5.2. Set the squadron to execute CAP:

+ +

The method AIA2ADISPATCHER.SetSquadronCap() defines a CAP execution for a squadron.

+ +

Setting-up a CAP zone also requires specific parameters:

+ +
    +
  • The minimum and maximum altitude
  • +
  • The minimum speed and maximum patrol speed
  • +
  • The minimum and maximum engage speed
  • +
  • The type of altitude measurement
  • +
+ +

These define how the squadron will perform the CAP while partrolling. Different terrain types requires different types of CAP.

+ +

The AIA2ADISPATCHER.SetSquadronCapInterval() 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":

+ +

A2ADispatcher:SetSquadronCap( "Sochi", CAPZoneWest, 4000, 8000, 600, 800, 800, 1200, "BARO" ) + A2ADispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 )

+ +

6. Setup a squadron for GCI:

+ +

The method AIA2ADISPATCHER.SetSquadronGci() defines a GCI execution for a squadron.

+ +

Setting-up a GCI readiness also requires specific parameters:

+ +
    +
  • The minimum speed and maximum patrol speed
  • +
+ +

Essentially this controls how many flights of GCI aircraft can be active at any time. +Note allowing large numbers of active GCI flights can adversely impact mission performance on low or medium specification hosts/servers. +GCI needs to be setup at strategic airbases. Too far will mean that the aircraft need to fly a long way to reach the intruders, +too short will mean that the intruders may have alraedy passed the ideal interception point!

+ +

For example, the following setup will create a GCI for squadron "Sochi":

+ +

A2ADispatcher:SetSquadronGci( "Mozdok", 900, 1200 )

+ +

7. User Guide:

+ +

8. Questionnaire:

+ +

8.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 +so that the 55G6 EWR radar unit is available to blue.
+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.

+ +

8.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.
  • +
  • Load outs should be appropriate to a CAP mission eg perhaps drop tanks for CAP flights and extra missiles for GCI flights.
  • +
  • These decisions will eventually lead to template aircraft units being placed as late activation units that the script will use as templates for spawning CAP and GCI flights. Up to 4 different aircraft configurations can be chosen for each coalition. The spawned aircraft will inherit the characteristics of the template aircraft.
  • +
  • The selected aircraft type must be able to perform the CAP tasking for the chosen country.
  • +
+ + + +
+
+

Type AI_A2A_Dispatcher

+ +

Type AI_A2A_DISPATCHER

+ +

AIA2ADISPATCHER class.

+ +

Field(s)

+
+
+ + +AI_A2A_DISPATCHER:AddDefenderToSquadron(Squadron, Defender) + +
+
+ + + +

Parameters

+
    +
  • + +

    Squadron :

    + +
  • +
  • + +

    Defender :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:CAP() + +
+
+ +

CAP Trigger for AIA2ADISPATCHER

+ +
+
+
+
+ + +AI_A2A_DISPATCHER:CanCAP(SquadronName) + +
+
+ + + +

Parameter

+
    +
  • + +

    #string SquadronName : +The squadron name.

    + +
  • +
+

Return value

+ +

#table: +DefenderSquadron

+ +
+
+
+
+ + +AI_A2A_DISPATCHER:CanGCI(SquadronName) + +
+
+ + + +

Parameter

+
    +
  • + +

    #string SquadronName : +The squadron name.

    + +
  • +
+

Return value

+ +

#table: +DefenderSquadron

+ +
+
+
+
+ + +AI_A2A_DISPATCHER:ClearDefenderTask(Defender) + +
+
+ + + +

Parameter

+
    +
  • + +

    Defender :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:ClearDefenderTaskTarget(Defender) + +
+
+ + + +

Parameter

+
    +
  • + +

    Defender :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:CountCapAirborne(SquadronName) + +
+
+ + + +

Parameter

+
    +
  • + +

    SquadronName :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:CountDefendersEngaged(Target) + +
+
+ + + +

Parameter

+
    +
  • + +

    Target :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:CountDefendersToBeEngaged(DetectedItem, DefenderCount) + +
+
+ + + +

Parameters

+
    +
  • + +

    DetectedItem :

    + +
  • +
  • + +

    DefenderCount :

    + +
  • +
+
+
+
+
+ + + +AI_A2A_DISPATCHER.DefenderSpawns + +
+
+ + + +
+
+
+
+ + + +AI_A2A_DISPATCHER.DefenderSquadrons + +
+
+ + + + +

The Defender Squadrons.

+ +
+
+
+
+ + + +AI_A2A_DISPATCHER.DefenderTasks + +
+
+ + + + +

The Defenders Tasks.

+ +
+
+
+
+ + +AI_A2A_DISPATCHER.Defenders + +
+
+ + + +
+
+
+
+ + Functional.Detection#DETECTION_AREAS + +AI_A2A_DISPATCHER.Detection + +
+
+ + + +
+
+
+
+ + +AI_A2A_DISPATCHER:ENGAGE() + +
+
+ +

ENGAGE Trigger for AIA2ADISPATCHER

+ +
+
+
+
+ + +AI_A2A_DISPATCHER:EvaluateENGAGE(DetectedItem) + +
+
+ +

Creates an ENGAGE task when there are human friendlies airborne near the targets.

+ +

Parameter

+ +

Return values

+
    +
  1. + +

    Set#SET_UNIT: +TargetSetUnit: The target set of units.

    + +
  2. +
  3. + +

    #nil: +If there are no targets to be set.

    + +
  4. +
+
+
+
+
+ + +AI_A2A_DISPATCHER:EvaluateGCI(DetectedItem, Target) + +
+
+ +

Creates an GCI task when there are targets for it.

+ +

Parameters

+ +

Return values

+
    +
  1. + +

    Set#SET_UNIT: +TargetSetUnit: The target set of units.

    + +
  2. +
  3. + +

    #nil: +If there are no targets to be set.

    + +
  4. +
+
+
+
+
+ + +AI_A2A_DISPATCHER:EvaluateSWEEP(DetectedItem) + +
+
+ +

Creates an SWEEP task when there are targets for it.

+ +

Parameter

+ +

Return values

+
    +
  1. + +

    Set#SET_UNIT: +TargetSetUnit: The target set of units.

    + +
  2. +
  3. + +

    #nil: +If there are no targets to be set.

    + +
  4. +
+
+
+
+
+ + +AI_A2A_DISPATCHER:GCI() + +
+
+ +

GCI Trigger for AIA2ADISPATCHER

+ +
+
+
+
+ + +AI_A2A_DISPATCHER:GetAIFriendliesNearBy(DetectedItem) + +
+
+ +

Calculates which AI friendlies are nearby the area

+ +

Parameter

+
    +
  • + +

    DetectedItem :

    + +
  • +
+

Return value

+ +

#number, Core.CommandCenter#REPORT:

+ + +
+
+
+
+ + +AI_A2A_DISPATCHER:GetCAPDelay(SquadronName) + +
+
+ + + +

Parameter

+
    +
  • + +

    #string SquadronName : +The squadron name.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +
+
+
+
+ + +AI_A2A_DISPATCHER:GetDefenderTask(Defender) + +
+
+ + + +

Parameter

+
    +
  • + +

    Defender :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:GetDefenderTaskFsm(Defender) + +
+
+ + + +

Parameter

+
    +
  • + +

    Defender :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:GetDefenderTaskTarget(Defender) + +
+
+ + + +

Parameter

+
    +
  • + +

    Defender :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:GetDefenderTasks() + +
+
+ + + +
+
+
+
+ + +AI_A2A_DISPATCHER:GetFriendliesNearBy(DetectedItem, Target) + +
+
+ +

Calculates which friendlies are nearby the area

+ +

Parameters

+
    +
  • + +

    DetectedItem :

    + +
  • +
  • + +

    Target :

    + +
  • +
+

Return value

+ +

#number, Core.CommandCenter#REPORT:

+ + +
+
+
+
+ + +AI_A2A_DISPATCHER:GetPlayerFriendliesNearBy(DetectedItem) + +
+
+ +

Calculates which HUMAN friendlies are nearby the area

+ +

Parameter

+
    +
  • + +

    DetectedItem :

    + +
  • +
+

Return value

+ +

#number, Core.CommandCenter#REPORT:

+ + +
+
+
+
+ + +AI_A2A_DISPATCHER:GetSquadron(SquadronName) + +
+
+ +

Get an item from the Squadron table.

+ +

Parameter

+
    +
  • + +

    SquadronName :

    + +
  • +
+

Return value

+ +

#table:

+ + +
+
+
+
+ + +AI_A2A_DISPATCHER:GetSquadronFromDefender(Defender) + +
+
+ + + +

Parameter

+
    +
  • + +

    Defender :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:GetSquadronLanding(SquadronName) + +
+
+ +

Gets the method at which flights will land and despawn as part of the defense system.

+ +

Parameter

+
    +
  • + +

    #string SquadronName : +The name of the squadron.

    + +
  • +
+

Return value

+ +

#number: +Landing The landing method which can be NearAirbase, AtRunway, AtEngineShutdown

+ +

Usage:

+

+
+  local Dispatcher = AI_A2A_DISPATCHER:New( ... )
+  
+  -- Let new flights take-off in the air.
+  local LandingMethod = Dispatcher:GetSquadronLanding( "SquadronName", AI_A2A_Dispatcher.Landing.NearAirbase )
+  if LandingMethod == AI_A2A_Dispatcher.Landing.NearAirbase then
+   ...
+  end
+
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:GetSquadronTakeoff(SquadronName) + +
+
+ +

Gets the method at which new flights will spawn and take-off as part of the defense system.

+ +

Parameter

+
    +
  • + +

    #string SquadronName : +The name of the squadron.

    + +
  • +
+

Return value

+ +

#number: +Takeoff From the airbase hot, from the airbase cold, in the air, from the runway.

+ +

Usage:

+

+
+  local Dispatcher = AI_A2A_DISPATCHER:New( ... )
+  
+  -- Let new flights take-off in the air.
+  local TakeoffMethod = Dispatcher:GetSquadronTakeoff( "SquadronName" )
+  if TakeOffMethod == , AI_A2A_Dispatcher.Takeoff.InAir then
+    ...
+  end
+  
+ +
+
+
+
+ + + +AI_A2A_DISPATCHER.Landing + +
+
+ +

Defnes Landing location.

+ +
+
+
+
+ + +AI_A2A_DISPATCHER:New(The, DetectionSetGroup, GroupingRadius) + +
+
+ +

AIA2ADISPATCHER constructor.

+ +

Parameters

+
    +
  • + +

    #string The : +Squadron Name. This name is used to control the squadron settings in the A2A dispatcher, and also in communication to human players.

    + +
  • +
  • + +

    Core.Set#SET_GROUP DetectionSetGroup : +The Set of group objects that will setup the Early Warning Radar network.

    + +
  • +
  • + +

    #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.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER: +self

+ +

Usage:

+
  
+  -- Set a new AI A2A Dispatcher object, based on an EWR network with a 6 km grouping radius.
+  
+
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:OnAfterAssign(From, Event, To, Task, TaskUnit, PlayerName) + +
+
+ +

OnAfter Transition Handler for Event Assign.

+ +

Parameters

+
    +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
  • + +

    Tasking.TaskA2A#AIA2A Task :

    + +
  • +
  • + +

    Wrapper.Unit#UNIT TaskUnit :

    + +
  • +
  • + +

    #string PlayerName :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:OnAfterCAP(From, Event, To) + +
+
+ +

CAP Handler OnAfter for AIA2ADISPATCHER

+ +

Parameters

+
    +
  • + +

    #string From :

    + +
  • +
  • + +

    #string Event :

    + +
  • +
  • + +

    #string To :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:OnAfterENGAGE(From, Event, To) + +
+
+ +

ENGAGE Handler OnAfter for AIA2ADISPATCHER

+ +

Parameters

+
    +
  • + +

    #string From :

    + +
  • +
  • + +

    #string Event :

    + +
  • +
  • + +

    #string To :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:OnAfterGCI(From, Event, To) + +
+
+ +

GCI Handler OnAfter for AIA2ADISPATCHER

+ +

Parameters

+
    +
  • + +

    #string From :

    + +
  • +
  • + +

    #string Event :

    + +
  • +
  • + +

    #string To :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:OnBeforeCAP(From, Event, To) + +
+
+ +

CAP Handler OnBefore for AIA2ADISPATCHER

+ +

Parameters

+
    +
  • + +

    #string From :

    + +
  • +
  • + +

    #string Event :

    + +
  • +
  • + +

    #string To :

    + +
  • +
+

Return value

+ +

#boolean:

+ + +
+
+
+
+ + +AI_A2A_DISPATCHER:OnBeforeENGAGE(From, Event, To) + +
+
+ +

ENGAGE Handler OnBefore for AIA2ADISPATCHER

+ +

Parameters

+
    +
  • + +

    #string From :

    + +
  • +
  • + +

    #string Event :

    + +
  • +
  • + +

    #string To :

    + +
  • +
+

Return value

+ +

#boolean:

+ + +
+
+
+
+ + +AI_A2A_DISPATCHER:OnBeforeGCI(From, Event, To) + +
+
+ +

GCI Handler OnBefore for AIA2ADISPATCHER

+ +

Parameters

+
    +
  • + +

    #string From :

    + +
  • +
  • + +

    #string Event :

    + +
  • +
  • + +

    #string To :

    + +
  • +
+

Return value

+ +

#boolean:

+ + +
+
+
+
+ + +AI_A2A_DISPATCHER:OnEventCrashOrDead(EventData) + +
+
+ + + +

Parameter

+ +
+
+
+
+ + +AI_A2A_DISPATCHER:OnEventEngineShutdown(EventData) + +
+
+ + + +

Parameter

+ +
+
+
+
+ + +AI_A2A_DISPATCHER:OnEventLand(EventData) + +
+
+ + + +

Parameter

+ +
+
+
+
+ + +AI_A2A_DISPATCHER:ProcessDetected(Detection) + +
+
+ +

Assigns A2A AI Tasks in relation to the detected items.

+ +

Parameter

+ +

Return value

+ +

#boolean: +Return true if you want the task assigning to continue... false will cancel the loop.

+ +
+
+
+
+ + +AI_A2A_DISPATCHER:RemoveDefenderFromSquadron(Squadron, Defender) + +
+
+ + + +

Parameters

+
    +
  • + +

    Squadron :

    + +
  • +
  • + +

    Defender :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER.SchedulerCAP(AI_A2A_DISPATCHER, SquadronName, self) + +
+
+ + + +

Parameters

+
    +
  • + +

    AIA2ADISPATCHER :

    + +
  • +
  • + +

    #string SquadronName : +The squadron name.

    + +
  • +
  • + +

    self :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:SetBorderZone(BorderZone) + +
+
+ +

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. +If it’s a cold war then the borders of red and blue territory need to be defined using a zone object derived from 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

+ +

Parameter

+
    +
  • + +

    Core.Zone#ZONE_BASE BorderZone : +An object derived from ZONE_BASE, that defines a zone between

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +

Usage:

+

+  -- Set a polygon zone as the border for the A2A dispatcher.
+  local BorderZone = ZONE_POLYGON( "CCCP Border", GROUP:FindByName( "CCCP Border" ) ) -- The GROUP object is a late activate helicopter unit.
+  Dispatcher:SetBorderZone( BorderZone )
+  
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:SetDefenderTask(Defender, Type, Fsm, Target) + +
+
+ + + +

Parameters

+
    +
  • + +

    Defender :

    + +
  • +
  • + +

    Type :

    + +
  • +
  • + +

    Fsm :

    + +
  • +
  • + +

    Target :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:SetDefenderTaskTarget(AIGroup, Defender, Target) + +
+
+ + + +

Parameters

+ +
+
+
+
+ + +AI_A2A_DISPATCHER:SetEngageRadius(FriendliesRadius) + +
+
+ +

Define the radius to engage any target by airborne friendlies, which are executing cap or returning from an intercept mission.

+ + +

So, if there is a target area detected and reported, +then any friendlies that are airborne near this target area, +will be commanded to (re-)engage that target when available (if no other tasks were commanded). +For example, if 100000 is given as a value, then any friendly that is airborne within 100km from the detected target, +will be considered to receive the command to engage that target area. +You need to evaluate the value of this parameter carefully. +If too small, more intercept missions may be triggered upon detected target areas. +If too large, any airborne cap may not be able to reach the detected target area in time, because it is too far.

+ +

Parameter

+
    +
  • + +

    #number FriendliesRadius : +The radius to report friendlies near the target.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +

Usage:

+

+  -- Set 100km as the radius to engage any target by airborne friendlies.
+  Dispatcher:InitDetectionFriendiesRadius( 100000 )
+  
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadron(SquadronName, AirbaseName, SpawnTemplates, Resources) + +
+
+ + + +

Parameters

+
    +
  • + +

    SquadronName :

    + +
  • +
  • + +

    AirbaseName :

    + +
  • +
  • + +

    SpawnTemplates :

    + +
  • +
  • + +

    Resources :

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadronCap(SquadronName, Zone, FloorAltitude, CeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, AltType) + +
+
+ + + +

Parameters

+
    +
  • + +

    #string SquadronName : +The squadron name.

    + +
  • +
  • + +

    Core.Zone#ZONE_BASE Zone : +The Zone object derived from Zone#ZONE_BASE that defines the zone wherein the CAP will be executed.

    + +
  • +
  • + +

    #number FloorAltitude : +The minimum altitude at which the cap can be executed.

    + +
  • +
  • + +

    #number CeilingAltitude : +the maximum altitude at which the cap can be executed.

    + +
  • +
  • + +

    #number PatrolMinSpeed : +The minimum speed at which the cap can be executed.

    + +
  • +
  • + +

    #number PatrolMaxSpeed : +The maximum speed at which the cap can be executed.

    + +
  • +
  • + +

    #number EngageMinSpeed : +The minimum speed at which the engage can be executed.

    + +
  • +
  • + +

    #number EngageMaxSpeed : +The maximum speed at which the engage can be executed.

    + +
  • +
  • + +

    #number AltType : +The altitude type, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadronCapInterval(SquadronName, CapLimit, LowInterval, HighInterval, Probability) + +
+
+ + + +

Parameters

+
    +
  • + +

    #string SquadronName : +The squadron name.

    + +
  • +
  • + +

    CapLimit :

    + +
  • +
  • + +

    LowInterval :

    + +
  • +
  • + +

    HighInterval :

    + +
  • +
  • + +

    Probability :

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadronGci(SquadronName, EngageMinSpeed, EngageMaxSpeed) + +
+
+ + + +

Parameters

+
    +
  • + +

    #string SquadronName : +The squadron name.

    + +
  • +
  • + +

    #number EngageMinSpeed : +The minimum speed at which the gci can be executed.

    + +
  • +
  • + +

    #number EngageMaxSpeed : +The maximum speed at which the gci can be executed.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadronGrouping(SquadronName, Grouping) + +
+
+ + + +

Parameters

+
    +
  • + +

    #string SquadronName : +The name of the squadron.

    + +
  • +
  • + +

    #number Grouping : +The level of grouping that will be applied of the CAP or GCI defenders.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +

Usage:

+

+
+  local Dispatcher = AI_A2A_DISPATCHER:New( ... )
+  Dispatcher:SetSquadronGrouping( "SquadronName", 2 )
+
+
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadronLanding(SquadronName, Landing) + +
+
+ +

Defines the method at which flights will land and despawn as part of the defense system.

+ +

Parameters

+
    +
  • + +

    #string SquadronName : +The name of the squadron.

    + +
  • +
  • + +

    #number Landing : +The landing method which can be NearAirbase, AtRunway, AtEngineShutdown

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +

Usage:

+

+
+  local Dispatcher = AI_A2A_DISPATCHER:New( ... )
+  
+  -- Let new flights take-off in the air.
+  Dispatcher:SetSquadronLanding( "SquadronName", AI_A2A_Dispatcher.Landing.NearAirbase )
+  
+  -- Let new flights take-off from the runway.
+  Dispatcher:SetSquadronLanding( "SquadronName", AI_A2A_Dispatcher.Landing.AtRunway )
+  
+  -- Let new flights take-off from the airbase hot.
+  Dispatcher:SetSquadronLanding( "SquadronName", AI_A2A_Dispatcher.Landing.AtEngineShutdown )
+
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadronLandingAtEngineShutdown(SquadronName) + +
+
+ +

Sets flights to land and despawn at engine shutdown, as part of the defense system.

+ +

Parameter

+
    +
  • + +

    #string SquadronName : +The name of the squadron.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +

Usage:

+

+
+  local Dispatcher = AI_A2A_DISPATCHER:New( ... )
+  
+  -- Let flights land and despawn at engine shutdown.
+  Dispatcher:SetSquadronLandingAtEngineShutdown( "SquadronName" )
+  
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadronLandingAtRunway(SquadronName) + +
+
+ +

Sets flights to land and despawn at the runway, as part of the defense system.

+ +

Parameter

+
    +
  • + +

    #string SquadronName : +The name of the squadron.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +

Usage:

+

+
+  local Dispatcher = AI_A2A_DISPATCHER:New( ... )
+  
+  -- Let flights land at the runway and despawn.
+  Dispatcher:SetSquadronLandingAtRunway( "SquadronName" )
+  
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadronLandingNearAirbase(SquadronName) + +
+
+ +

Sets flights to land and despawn near the airbase in the air, as part of the defense system.

+ +

Parameter

+
    +
  • + +

    #string SquadronName : +The name of the squadron.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +

Usage:

+

+
+  local Dispatcher = AI_A2A_DISPATCHER:New( ... )
+  
+  -- Let flights land in the air and despawn.
+  Dispatcher:SetSquadronLandingNearAirbase( "SquadronName" )
+  
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadronOverhead(SquadronName, Overhead) + +
+
+ +

Defines the amount of extra planes that will take-off as part of the defense system.

+ +

Parameters

+
    +
  • + +

    #string SquadronName : +The name of the squadron.

    + +
  • +
  • + +

    #number Overhead : +The %-tage of Units that dispatching command will allocate to intercept in surplus of detected amount of units. +The default overhead is 1, so equal balance. The AIA2ADISPATCHER.SetOverhead() method can be used to tweak the defense strength, +taking into account the plane types of the squadron. For example, a MIG-31 with full long-distance A2A missiles payload, may still be less effective than a F-15C with short missiles... +So in this case, one may want to use the Overhead method to allocate more defending planes as the amount of detected attacking planes. +The overhead must be given as a decimal value with 1 as the neutral value, which means that Overhead values:

    + +
      +
    • Higher than 1, will increase the defense unit amounts.
    • +
    • Lower than 1, will decrease the defense unit amounts.
    • +
    + +

    The amount of defending units is calculated by multiplying the amount of detected attacking planes as part of the detected group +multiplied by the Overhead and rounded up to the smallest integer.

    + +

    The Overhead value set for a Squadron, can be programmatically adjusted (by using this SetOverhead method), to adjust the defense overhead during mission execution.

    + +

    See example below. +

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +

Usage:

+

+
+  local Dispatcher = AI_A2A_DISPATCHER:New( ... )
+  
+  -- An overhead of 1,5 with 1 planes detected, will allocate 2 planes ( 1 * 1,5 ) = 1,5 => rounded up gives 2.
+  -- An overhead of 1,5 with 2 planes detected, will allocate 3 planes ( 2 * 1,5 ) = 3 =>  rounded up gives 3.
+  -- An overhead of 1,5 with 3 planes detected, will allocate 5 planes ( 3 * 1,5 ) = 4,5 => rounded up gives 5 planes.
+  -- An overhead of 1,5 with 4 planes detected, will allocate 6 planes ( 4 * 1,5 ) = 6  => rounded up gives 6 planes.
+  
+  Dispatcher:SetSquadronOverhead( 1,5 )
+
+
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadronTakeoff(SquadronName, Takeoff) + +
+
+ +

Defines the method at which new flights will spawn and take-off as part of the defense system.

+ +

Parameters

+
    +
  • + +

    #string SquadronName : +The name of the squadron.

    + +
  • +
  • + +

    #number Takeoff : +From the airbase hot, from the airbase cold, in the air, from the runway.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +

Usage:

+

+
+  local Dispatcher = AI_A2A_DISPATCHER:New( ... )
+  
+  -- Let new flights take-off in the air.
+  Dispatcher:SetSquadronTakeoff( "SquadronName", AI_A2A_Dispatcher.Takeoff.Air )
+  
+  -- Let new flights take-off from the runway.
+  Dispatcher:SetSquadronTakeoff( "SquadronName", AI_A2A_Dispatcher.Takeoff.Runway )
+  
+  -- Let new flights take-off from the airbase hot.
+  Dispatcher:SetSquadronTakeoff( "SquadronName", AI_A2A_Dispatcher.Takeoff.Hot )
+
+  -- Let new flights take-off from the airbase cold.
+  Dispatcher:SetSquadronTakeoff( "SquadronName", AI_A2A_Dispatcher.Takeoff.Cold )
+
+
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadronTakeoffFromParkingCold(SquadronName) + +
+
+ +

Sets flights to take-off from the airbase at a cold location, as part of the defense system.

+ +

Parameter

+
    +
  • + +

    #string SquadronName : +The name of the squadron.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +

Usage:

+

+
+  local Dispatcher = AI_A2A_DISPATCHER:New( ... )
+  
+  -- Let new flights take-off in the air.
+  Dispatcher:SetSquadronTakeoffFromParkingCold( "SquadronName" )
+  
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadronTakeoffFromParkingHot(SquadronName) + +
+
+ +

Sets flights to take-off from the airbase at a hot location, as part of the defense system.

+ +

Parameter

+
    +
  • + +

    #string SquadronName : +The name of the squadron.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +

Usage:

+

+
+  local Dispatcher = AI_A2A_DISPATCHER:New( ... )
+  
+  -- Let new flights take-off in the air.
+  Dispatcher:SetSquadronTakeoffFromParkingHot( "SquadronName" )
+  
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadronTakeoffFromRunway(SquadronName) + +
+
+ +

Sets flights to take-off from the runway, as part of the defense system.

+ +

Parameter

+
    +
  • + +

    #string SquadronName : +The name of the squadron.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +

Usage:

+

+
+  local Dispatcher = AI_A2A_DISPATCHER:New( ... )
+  
+  -- Let new flights take-off in the air.
+  Dispatcher:SetSquadronTakeoffFromRunway( "SquadronName" )
+  
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:SetSquadronTakeoffInAir(SquadronName) + +
+
+ +

Sets flights to take-off in the air, as part of the defense system.

+ +

Parameter

+
    +
  • + +

    #string SquadronName : +The name of the squadron.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +

Usage:

+

+
+  local Dispatcher = AI_A2A_DISPATCHER:New( ... )
+  
+  -- Let new flights take-off in the air.
+  Dispatcher:SetSquadronTakeoffInAir( "SquadronName" )
+  
+ +
+
+
+
+ + +AI_A2A_DISPATCHER:SetTacticalDisplay(TacticalDisplay) + +
+
+ +

Display a tactical report every 30 seconds about which aircraft are: + * Patrolling + * Engaging + * Returning + * Damaged + * Out of Fuel + * ...

+ +

Parameter

+
    +
  • + +

    #boolean TacticalDisplay : +Provide a value of true to display every 30 seconds a tactical overview.

    + +
  • +
+

Return value

+ +

#AIA2ADISPATCHER:

+ + +
+
+
+
+ + + +AI_A2A_DISPATCHER.TacticalDisplay + +
+
+ + + +
+
+
+
+ + #AI_A2A_DISPATCHER.Takeoff + +AI_A2A_DISPATCHER.Takeoff + +
+
+ + + +
+
+
+
+ + +AI_A2A_DISPATCHER:__CAP(Delay) + +
+
+ +

CAP Asynchronous Trigger for AIA2ADISPATCHER

+ +

Parameter

+
    +
  • + +

    #number Delay :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:__ENGAGE(Delay) + +
+
+ +

ENGAGE Asynchronous Trigger for AIA2ADISPATCHER

+ +

Parameter

+
    +
  • + +

    #number Delay :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:__GCI(Delay) + +
+
+ +

GCI Asynchronous Trigger for AIA2ADISPATCHER

+ +

Parameter

+
    +
  • + +

    #number Delay :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:onafterCAP(From, Event, To, SquadronName) + +
+
+ + + +

Parameters

+
    +
  • + +

    From :

    + +
  • +
  • + +

    Event :

    + +
  • +
  • + +

    To :

    + +
  • +
  • + +

    SquadronName :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:onafterENGAGE(From, Event, To, Target, AIGroups) + +
+
+ + + +

Parameters

+
    +
  • + +

    From :

    + +
  • +
  • + +

    Event :

    + +
  • +
  • + +

    To :

    + +
  • +
  • + +

    Target :

    + +
  • +
  • + +

    AIGroups :

    + +
  • +
+
+
+
+
+ + +AI_A2A_DISPATCHER:onafterGCI(From, Event, To, Target, DefendersMissing, AIGroups) + +
+
+ + + +

Parameters

+
    +
  • + +

    From :

    + +
  • +
  • + +

    Event :

    + +
  • +
  • + +

    To :

    + +
  • +
  • + +

    Target :

    + +
  • +
  • + +

    DefendersMissing :

    + +
  • +
  • + +

    AIGroups :

    + +
  • +
+
+
+ +

Type AI_A2A_DISPATCHER.Takeoff

+ +

Enumerator for spawns at airbases

+ + +
+ +
+ + diff --git a/docs/Documentation/AI_A2A_GCI.html b/docs/Documentation/AI_A2A_GCI.html new file mode 100644 index 000000000..c6d4b3b60 --- /dev/null +++ b/docs/Documentation/AI_A2A_GCI.html @@ -0,0 +1,1566 @@ + + + + + + +
+
+ +
+
+
+
+ +
+

Module AI_A2A_GCI

+ +

AI -- Execute Ground Controlled Interception (GCI).

+ +

Banner Image

+ +
+ +

AI A2A_INTEREPT class makes AI Groups execute an Intercept.

+ + + +

There are the following types of GCI classes defined:

+ + + +
+ +

Author: Sven Van de Velde (FlightControl)

+ +

Contributions:

+ +
+ + +

Global(s)

+ + + + + +
AI_A2A_GCI +

AIA2AGCI class, extends AIA2A#AIA2A

+ +

The AIA2AGCI class implements the core functions to intercept intruders.

+
+

Type AI_A2A_GCI

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AI_A2A_GCI:Abort() +

Synchronous Event Trigger for Event Abort.

+
AI_A2A_GCI:Accomplish() +

Synchronous Event Trigger for Event Accomplish.

+
AI_A2A_GCI.Accomplished + +
AI_A2A_GCI.AttackSetUnit + +
AI_A2A_GCI:Destroy() +

Synchronous Event Trigger for Event Destroy.

+
AI_A2A_GCI:Engage() +

Synchronous Event Trigger for Event Engage.

+
AI_A2A_GCI.EngageMaxSpeed + +
AI_A2A_GCI.EngageMinSpeed + +
AI_A2A_GCI.Engaging + +
AI_A2A_GCI:Fired() +

Synchronous Event Trigger for Event Fired.

+
AI_A2A_GCI.InterceptRoute(AIControllable) + +
AI_A2A_GCI:New(AIGroup, EngageMinSpeed, EngageMaxSpeed) +

Creates a new AIA2AGCI object

+
AI_A2A_GCI:OnAfterAbort(AIGroup, From, Event, To) +

OnAfter Transition Handler for Event Abort.

+
AI_A2A_GCI:OnAfterAccomplish(AIGroup, From, Event, To) +

OnAfter Transition Handler for Event Accomplish.

+
AI_A2A_GCI:OnAfterDestroy(AIGroup, From, Event, To) +

OnAfter Transition Handler for Event Destroy.

+
AI_A2A_GCI:OnAfterEngage(AIGroup, From, Event, To) +

OnAfter Transition Handler for Event Engage.

+
AI_A2A_GCI:OnAfterFired(AIGroup, From, Event, To) +

OnAfter Transition Handler for Event Fired.

+
AI_A2A_GCI:OnBeforeAbort(AIGroup, From, Event, To) +

OnBefore Transition Handler for Event Abort.

+
AI_A2A_GCI:OnBeforeAccomplish(AIGroup, From, Event, To) +

OnBefore Transition Handler for Event Accomplish.

+
AI_A2A_GCI:OnBeforeDestroy(AIGroup, From, Event, To) +

OnBefore Transition Handler for Event Destroy.

+
AI_A2A_GCI:OnBeforeEngage(AIGroup, From, Event, To) +

OnBefore Transition Handler for Event Engage.

+
AI_A2A_GCI:OnBeforeFired(AIGroup, From, Event, To) +

OnBefore Transition Handler for Event Fired.

+
AI_A2A_GCI:OnEnterEngaging(AIGroup, From, Event, To) +

OnEnter Transition Handler for State Engaging.

+
AI_A2A_GCI:OnEventDead(EventData) + +
AI_A2A_GCI:OnLeaveEngaging(AIGroup, From, Event, To) +

OnLeave Transition Handler for State Engaging.

+
AI_A2A_GCI.PatrolAltType + +
AI_A2A_GCI.PatrolMaxSpeed + +
AI_A2A_GCI.PatrolMinSpeed + +
AI_A2A_GCI:__Abort(Delay) +

Asynchronous Event Trigger for Event Abort.

+
AI_A2A_GCI:__Accomplish(Delay) +

Asynchronous Event Trigger for Event Accomplish.

+
AI_A2A_GCI:__Destroy(Delay) +

Asynchronous Event Trigger for Event Destroy.

+
AI_A2A_GCI:__Engage(Delay) +

Asynchronous Event Trigger for Event Engage.

+
AI_A2A_GCI:__Fired(Delay) +

Asynchronous Event Trigger for Event Fired.

+
AI_A2A_GCI:onafterAbort(AIGroup, From, Event, To) + +
AI_A2A_GCI:onafterAccomplish(AIGroup, From, Event, To) + +
AI_A2A_GCI:onafterDestroy(AIGroup, From, Event, To, EventData) + +
AI_A2A_GCI:onafterEngage(AIGroup, From, Event, To) +

onafter State Transition for Event Patrol.

+
AI_A2A_GCI:onbeforeEngage(AIGroup, From, Event, To) + +
+ +

Global(s)

+
+
+ + #AI_A2A_GCI + +AI_A2A_GCI + +
+
+ +

AIA2AGCI class, extends AIA2A#AIA2A

+ +

The AIA2AGCI class implements the core functions to intercept intruders.

+ + +

The Engage function will intercept intruders.

+ +

Process

+ +

The AIA2AGCI is assigned a Group and this must be done before the AIA2AGCI process can be started using the Start event.

+ +

Process

+ +

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.

+ +

Process

+ +

This cycle will continue.

+ +

Process

+ +

During the patrol, the AI will detect enemy targets, which are reported through the Detected event.

+ +

Process

+ +

When enemies are detected, the AI will automatically engage the enemy.

+ +

Process

+ +

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.

+ +

Process

+ +

1. AIA2AGCI constructor

+ + + +

2. AIA2AGCI is a FSM

+ +

Process

+ +

2.1 AIA2AGCI 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 AIA2AGCI Events

+ + + +

3. Set the Range of Engagement

+ +

Range

+ +

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 AIGCI#AIA2A_GCI.SetEngageRange() to define that range.

+ +

4. Set the Zone of Engagement

+ +

Zone

+ +

An optional Zone can be set, +that will define when the AI will engage with the detected airborne enemy targets. +Use the method AICap#AIA2A_GCI.SetEngageZone() to define that Zone.

+ +
+ + +
+
+

Type AI_A2A_GCI

+

Field(s)

+
+
+ + +AI_A2A_GCI:Abort() + +
+
+ +

Synchronous Event Trigger for Event Abort.

+ +
+
+
+
+ + +AI_A2A_GCI:Accomplish() + +
+
+ +

Synchronous Event Trigger for Event Accomplish.

+ +
+
+
+
+ + #boolean + +AI_A2A_GCI.Accomplished + +
+
+ + + +
+
+
+
+ + Core.Set#SET_UNIT + +AI_A2A_GCI.AttackSetUnit + +
+
+ + + +
+
+
+
+ + +AI_A2A_GCI:Destroy() + +
+
+ +

Synchronous Event Trigger for Event Destroy.

+ +
+
+
+
+ + +AI_A2A_GCI:Engage() + +
+
+ +

Synchronous Event Trigger for Event Engage.

+ +
+
+
+
+ + + +AI_A2A_GCI.EngageMaxSpeed + +
+
+ + + +
+
+
+
+ + + +AI_A2A_GCI.EngageMinSpeed + +
+
+ + + +
+
+
+
+ + #boolean + +AI_A2A_GCI.Engaging + +
+
+ + + +
+
+
+
+ + +AI_A2A_GCI:Fired() + +
+
+ +

Synchronous Event Trigger for Event Fired.

+ +
+
+
+
+ + +AI_A2A_GCI.InterceptRoute(AIControllable) + +
+
+ + + +

Parameter

+ +
+
+
+
+ + +AI_A2A_GCI:New(AIGroup, EngageMinSpeed, EngageMaxSpeed) + +
+
+ +

Creates a new AIA2AGCI object

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup :

    + +
  • +
  • + +

    EngageMinSpeed :

    + +
  • +
  • + +

    EngageMaxSpeed :

    + +
  • +
+

Return value

+ +

#AIA2AGCI:

+ + +
+
+
+
+ + +AI_A2A_GCI:OnAfterAbort(AIGroup, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Abort.

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:OnAfterAccomplish(AIGroup, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Accomplish.

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:OnAfterDestroy(AIGroup, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Destroy.

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:OnAfterEngage(AIGroup, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Engage.

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:OnAfterFired(AIGroup, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Fired.

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:OnBeforeAbort(AIGroup, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Abort.

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A_GCI:OnBeforeAccomplish(AIGroup, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Accomplish.

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A_GCI:OnBeforeDestroy(AIGroup, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Destroy.

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A_GCI:OnBeforeEngage(AIGroup, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Engage.

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A_GCI:OnBeforeFired(AIGroup, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Fired.

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A_GCI:OnEnterEngaging(AIGroup, From, Event, To) + +
+
+ +

OnEnter Transition Handler for State Engaging.

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:OnEventDead(EventData) + +
+
+ + + +

Parameter

+ +
+
+
+
+ + +AI_A2A_GCI:OnLeaveEngaging(AIGroup, From, Event, To) + +
+
+ +

OnLeave Transition Handler for State Engaging.

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + #string + +AI_A2A_GCI.PatrolAltType + +
+
+ + + +
+
+
+
+ + + +AI_A2A_GCI.PatrolMaxSpeed + +
+
+ + + +
+
+
+
+ + + +AI_A2A_GCI.PatrolMinSpeed + +
+
+ + + +
+
+
+
+ + +AI_A2A_GCI:__Abort(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Abort.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:__Accomplish(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Accomplish.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:__Destroy(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Destroy.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:__Engage(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Engage.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:__Fired(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Fired.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:onafterAbort(AIGroup, From, Event, To) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AI Group managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:onafterAccomplish(AIGroup, From, Event, To) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:onafterDestroy(AIGroup, From, Event, To, EventData) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
  • + +

    Core.Event#EVENTDATA EventData :

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:onafterEngage(AIGroup, From, Event, To) + +
+
+ +

onafter State Transition for Event Patrol.

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AI Group managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_GCI:onbeforeEngage(AIGroup, From, Event, To) + +
+
+ + + +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+ +
+ +
+ + diff --git a/docs/Documentation/AI_A2A_Patrol.html b/docs/Documentation/AI_A2A_Patrol.html new file mode 100644 index 000000000..a386ed968 --- /dev/null +++ b/docs/Documentation/AI_A2A_Patrol.html @@ -0,0 +1,1093 @@ + + + + + + +
+
+ +
+
+
+
+ +
+

Module AI_A2A_Patrol

+ +

AI -- Air Patrolling or Staging.

+ +

Banner Image

+ +
+ +

AI PATROL classes makes AI Controllables execute an Patrol.

+ + + +

There are the following types of PATROL classes defined:

+ + + +
+ +

Demo Missions

+ +

AI_PATROL Demo Missions source code

+ +

AI_PATROL Demo Missions, only for beta testers

+ +

ALL Demo Missions pack of the last release

+ +
+ +

YouTube Channel

+ +

AI_PATROL YouTube Channel

+ +
+ +

Author: Sven Van de Velde (FlightControl)

+

Contributions:

+ +
    +
  • Dutch_Baron: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
  • +
  • Pikey: Testing and API concept review.
  • +
+ +
+ + +

Global(s)

+ + + + + +
AI_A2A_PATROL +

AIA2APATROL class, extends Fsm#FSM_CONTROLLABLE

+ +

The AIA2APATROL class implements the core functions to patrol a Zone by an AI Controllable or Group.

+
+

Type AI_A2A_PATROL

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AI_A2A_PATROL:New(AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType) +

Creates a new AIA2APATROL object

+
AI_A2A_PATROL:OnAfterPatrol(Controllable, From, Event, To) +

OnAfter Transition Handler for Event Patrol.

+
AI_A2A_PATROL:OnAfterRoute(Controllable, From, Event, To) +

OnAfter Transition Handler for Event Route.

+
AI_A2A_PATROL:OnBeforePatrol(Controllable, From, Event, To) +

OnBefore Transition Handler for Event Patrol.

+
AI_A2A_PATROL:OnBeforeRoute(Controllable, From, Event, To) +

OnBefore Transition Handler for Event Route.

+
AI_A2A_PATROL:OnEnterPatrolling(Controllable, From, Event, To) +

OnEnter Transition Handler for State Patrolling.

+
AI_A2A_PATROL:OnLeavePatrolling(Controllable, From, Event, To) +

OnLeave Transition Handler for State Patrolling.

+
AI_A2A_PATROL:Patrol() +

Synchronous Event Trigger for Event Patrol.

+
AI_A2A_PATROL.PatrolAltType + +
AI_A2A_PATROL.PatrolCeilingAltitude + +
AI_A2A_PATROL.PatrolFloorAltitude + +
AI_A2A_PATROL.PatrolMaxSpeed + +
AI_A2A_PATROL.PatrolMinSpeed + +
AI_A2A_PATROL.PatrolRoute(AIGroup) + +
AI_A2A_PATROL.PatrolZone + +
AI_A2A_PATROL:Route() +

Synchronous Event Trigger for Event Route.

+
AI_A2A_PATROL:SetAltitude(PatrolFloorAltitude, PatrolCeilingAltitude) +

Sets the floor and ceiling altitude of the patrol.

+
AI_A2A_PATROL:SetSpeed(PatrolMinSpeed, PatrolMaxSpeed) +

Sets (modifies) the minimum and maximum speed of the patrol.

+
AI_A2A_PATROL:__Patrol(Delay) +

Asynchronous Event Trigger for Event Patrol.

+
AI_A2A_PATROL:__Route(Delay) +

Asynchronous Event Trigger for Event Route.

+
AI_A2A_PATROL:onafterPatrol(Controllable, From, Event, To) +

Defines a new patrol route using the Process_PatrolZone parameters and settings.

+
AI_A2A_PATROL:onafterRoute(AIGroup, From, Event, To) +

Defines a new patrol route using the Process_PatrolZone parameters and settings.

+
+ +

Global(s)

+
+
+ + #AI_A2A_PATROL + +AI_A2A_PATROL + +
+
+ +

AIA2APATROL class, extends Fsm#FSM_CONTROLLABLE

+ +

The AIA2APATROL class implements the core functions to patrol a Zone by an AI Controllable or Group.

+ + + +

Process

+ +

The AIA2APATROL is assigned a Group and this must be done before the AIA2APATROL process can be started using the Start event.

+ +

Process

+ +

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.

+ +

Process

+ +

This cycle will continue.

+ +

Process

+ +

During the patrol, the AI will detect enemy targets, which are reported through the Detected event.

+ +

Process

+ +

-- Note that the enemy is not engaged! To model enemy engagement, either tailor the Detected event, or +use derived AI_ classes to model AI offensive or defensive behaviour.

+ +

Process

+ +

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.

+ +

Process

+ +

1. AIA2APATROL constructor

+ + + +

2. AIA2APATROL is a FSM

+ +

Process

+ +

2.1. AIA2APATROL States

+ +
    +
  • None ( Group ): The process is not started yet.
  • +
  • Patrolling ( Group ): The AI is patrolling the Patrol Zone.
  • +
  • Returning ( Group ): The AI is returning to Base.
  • +
  • Stopped ( Group ): The process is stopped.
  • +
  • Crashed ( Group ): The AI has crashed or is dead.
  • +
+ +

2.2. AIA2APATROL Events

+ +
    +
  • Start ( Group ): Start the process.
  • +
  • Stop ( Group ): Stop the process.
  • +
  • Route ( Group ): Route the AI to a new random 3D point within the Patrol Zone.
  • +
  • RTB ( Group ): Route the AI to the home base.
  • +
  • Detect ( Group ): The AI is detecting targets.
  • +
  • Detected ( Group ): The AI has detected new targets.
  • +
  • Status ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
  • +
+ +

3. Set or Get the AI controllable

+ + + +

4. Set the Speed and Altitude boundaries of the AI controllable

+ + + +

5. Manage the detection process of the AI controllable

+ +

The detection process of the AI controllable can be manipulated. +Detection requires an amount of CPU power, which has an impact on your mission performance. +Only put detection on when absolutely necessary, and the frequency of the detection can also be set.

+ + + +

The detection frequency can be set with AIA2APATROL.SetDetectionInterval( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection. +Use the method AIA2APATROL.GetDetectedUnits() to obtain a list of the Units detected by the AI.

+ +

The detection can be filtered to potential targets in a specific zone. +Use the method AIA2APATROL.SetDetectionZone() to set the zone where targets need to be detected. +Note that when the zone is too far away, or the AI is not heading towards the zone, or the AI is too high, no targets may be detected +according the weather conditions.

+ +

6. Manage the "out of fuel" in the AIA2APATROL

+ +

When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base. +Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated. +When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, +while a new AI is targetted to the AIA2APATROL. +Once the time is finished, the old AI will return to the base. +Use the method AIA2APATROL.ManageFuel() to have this proces in place.

+ +

7. Manage "damage" behaviour of the AI in the AIA2APATROL

+ +

When the AI is damaged, it is required that a new AIControllable is started. However, damage cannon be foreseen early on. +Therefore, when the damage treshold is reached, the AI will return immediately to the home base (RTB). +Use the method AIA2APATROL.ManageDamage() to have this proces in place.

+ +
+ + +
+
+

Type AI_A2A_Patrol

+ +

Type AI_A2A_PATROL

+

Field(s)

+
+
+ + +AI_A2A_PATROL:New(AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType) + +
+
+ +

Creates a new AIA2APATROL object

+ +

Parameters

+ +

Return value

+ +

#AIA2APATROL: +self

+ +

Usage:

+
-- Define a new AI_A2A_PATROL Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
+PatrolZone = ZONE:New( 'PatrolZone' )
+PatrolSpawn = SPAWN:New( 'Patrol Group' )
+PatrolArea = AI_A2A_PATROL:New( PatrolZone, 3000, 6000, 600, 900 )
+ +
+
+
+
+ + +AI_A2A_PATROL:OnAfterPatrol(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Patrol.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_PATROL:OnAfterRoute(Controllable, From, Event, To) + +
+
+ +

OnAfter Transition Handler for Event Route.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_PATROL:OnBeforePatrol(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Patrol.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A_PATROL:OnBeforeRoute(Controllable, From, Event, To) + +
+
+ +

OnBefore Transition Handler for Event Route.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A_PATROL:OnEnterPatrolling(Controllable, From, Event, To) + +
+
+ +

OnEnter Transition Handler for State Patrolling.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+
+
+ + +AI_A2A_PATROL:OnLeavePatrolling(Controllable, From, Event, To) + +
+
+ +

OnLeave Transition Handler for State Patrolling.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#boolean: +Return false to cancel Transition.

+ +
+
+
+
+ + +AI_A2A_PATROL:Patrol() + +
+
+ +

Synchronous Event Trigger for Event Patrol.

+ +
+
+
+
+ + +AI_A2A_PATROL.PatrolAltType + +
+
+ + + + +

defafult PatrolAltType to "RADIO" if not specified

+ +
+
+
+
+ + + +AI_A2A_PATROL.PatrolCeilingAltitude + +
+
+ + + +
+
+
+
+ + + +AI_A2A_PATROL.PatrolFloorAltitude + +
+
+ + + +
+
+
+
+ + + +AI_A2A_PATROL.PatrolMaxSpeed + +
+
+ + + +
+
+
+
+ + + +AI_A2A_PATROL.PatrolMinSpeed + +
+
+ + + +
+
+
+
+ + +AI_A2A_PATROL.PatrolRoute(AIGroup) + +
+
+ + + +

Parameter

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +This statis method is called from the route path within the last task at the last waaypoint of the Controllable. +Note that this method is required, as triggers the next route when patrolling for the Controllable.

    + +
  • +
+
+
+
+
+ + + +AI_A2A_PATROL.PatrolZone + +
+
+ + + +
+
+
+
+ + +AI_A2A_PATROL:Route() + +
+
+ +

Synchronous Event Trigger for Event Route.

+ +
+
+
+
+ + +AI_A2A_PATROL:SetAltitude(PatrolFloorAltitude, PatrolCeilingAltitude) + +
+
+ +

Sets the floor and ceiling altitude of the patrol.

+ +

Parameters

+
    +
  • + +

    Dcs.DCSTypes#Altitude PatrolFloorAltitude : +The lowest altitude in meters where to execute the patrol.

    + +
  • +
  • + +

    Dcs.DCSTypes#Altitude PatrolCeilingAltitude : +The highest altitude in meters where to execute the patrol.

    + +
  • +
+

Return value

+ +

#AIA2APATROL: +self

+ +
+
+
+
+ + +AI_A2A_PATROL:SetSpeed(PatrolMinSpeed, PatrolMaxSpeed) + +
+
+ +

Sets (modifies) the minimum and maximum speed of the patrol.

+ +

Parameters

+ +

Return value

+ +

#AIA2APATROL: +self

+ +
+
+
+
+ + +AI_A2A_PATROL:__Patrol(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Patrol.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A_PATROL:__Route(Delay) + +
+
+ +

Asynchronous Event Trigger for Event Route.

+ +

Parameter

+
    +
  • + +

    #number Delay : +The delay in seconds.

    + +
  • +
+
+
+
+
+ + +AI_A2A_PATROL:onafterPatrol(Controllable, From, Event, To) + +
+
+ +

Defines a new patrol route using the Process_PatrolZone parameters and settings.

+ +

Parameters

+
    +
  • + +

    Wrapper.Controllable#CONTROLLABLE Controllable : +The Controllable Object managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+

Return value

+ +

#AIA2APATROL: +self

+ +
+
+
+
+ + +AI_A2A_PATROL:onafterRoute(AIGroup, From, Event, To) + +
+
+ +

Defines a new patrol route using the Process_PatrolZone parameters and settings.

+ +

Parameters

+
    +
  • + +

    Wrapper.Group#GROUP AIGroup : +The AIGroup managed by the FSM.

    + +
  • +
  • + +

    #string From : +The From State string.

    + +
  • +
  • + +

    #string Event : +The Event string.

    + +
  • +
  • + +

    #string To : +The To State string.

    + +
  • +
+
+
+ +
+ +
+ + diff --git a/docs/Documentation/AI_BAI.html b/docs/Documentation/AI_BAI.html index 3c95dd5f8..afa707ccf 100644 --- a/docs/Documentation/AI_BAI.html +++ b/docs/Documentation/AI_BAI.html @@ -17,6 +17,11 @@ index + + +
+
+ + + +CONTROLLABLE.TaskScheduler + +
+
+ + +
@@ -3315,6 +3528,37 @@ If WayPoints is given, then use the route.

Type DCSStopCondition

+

Type Vec2

+

Field(s)

+
+
+ + + +Vec2.x + +
+
+ + + +
+
+
+
+ + + +Vec2.y + +
+
+ + + +
+
+

Type list

diff --git a/docs/Documentation/DCSAirbase.html b/docs/Documentation/DCSAirbase.html index 3ac796e64..dcf1f5e56 100644 --- a/docs/Documentation/DCSAirbase.html +++ b/docs/Documentation/DCSAirbase.html @@ -17,6 +17,11 @@ index

Multiple Unit.Category entries can be given as a table and then these will be evaluated as an OR expression.

+ + + + DETECTION_BASE:ForgetDetectedUnit(UnitName) + +

Forget a Unit from a DetectionItem

@@ -2389,7 +2400,6 @@ The index of the DetectedItem.

- #number DETECTION_BASE.DetectedItemMax @@ -2547,7 +2557,7 @@ The index of the DetectedItem.

- + #number DETECTION_BASE.DetectionInterval @@ -2682,6 +2692,33 @@ cs.DCSUnit#Unit> FilterCategories The Categories entries

#DETECTION_BASE: self

+ +
+
+
+ + +DETECTION_BASE:ForgetDetectedUnit(UnitName) + +
+
+ +

Forget a Unit from a DetectionItem

+ +

Parameter

+
    +
  • + +

    #string UnitName : +The UnitName that needs to be forgotten from the DetectionItem Sets.

    + +
  • +
+

Return value

+ +

#DETECTION_BASE:

+ +
diff --git a/docs/Documentation/DetectionManager.html b/docs/Documentation/DetectionManager.html index 691620d5b..ffff150e6 100644 --- a/docs/Documentation/DetectionManager.html +++ b/docs/Documentation/DetectionManager.html @@ -17,6 +17,11 @@ index
+
+
+ + +DETECTION_MANAGER:OnAfterStart(From, Event, To) + +
+
+ +

Start Handler OnAfter for DETECTION_MANAGER

+ +

Parameters

+
    +
  • + +

    #string From :

    + +
  • +
  • + +

    #string Event :

    + +
  • +
  • + +

    #string To :

    + +
  • +
+
+
+
+
+ + +DETECTION_MANAGER:OnAfterStop(From, Event, To) + +
+
+ +

Stop Handler OnAfter for DETECTION_MANAGER

+ +

Parameters

+
    +
  • + +

    #string From :

    + +
  • +
  • + +

    #string Event :

    + +
  • +
  • + +

    #string To :

    + +
  • +
+
+
+
+
+ + +DETECTION_MANAGER:OnBeforeStart(From, Event, To) + +
+
+ +

Start Handler OnBefore for DETECTION_MANAGER

+ +

Parameters

+
    +
  • + +

    #string From :

    + +
  • +
  • + +

    #string Event :

    + +
  • +
  • + +

    #string To :

    + +
  • +
+

Return value

+ +

#boolean:

+ + +
+
+
+
+ + +DETECTION_MANAGER:OnBeforeStop(From, Event, To) + +
+
+ +

Stop Handler OnBefore for DETECTION_MANAGER

+ +

Parameters

+
    +
  • + +

    #string From :

    + +
  • +
  • + +

    #string Event :

    + +
  • +
  • + +

    #string To :

    + +
  • +
+

Return value

+ +

#boolean:

+ +
@@ -476,6 +663,32 @@ The interval in seconds when a report needs to be done.

#DETECTION_MANAGER: self

+ +
+
+
+ + +DETECTION_MANAGER:Start() + +
+
+ +

Start Trigger for DETECTION_MANAGER

+ +
+
+
+
+ + +DETECTION_MANAGER:Stop() + +
+
+ +

Stop Trigger for DETECTION_MANAGER

+
@@ -504,6 +717,48 @@ self

+ +
+
+
+ + +DETECTION_MANAGER:__Start(Delay) + +
+
+ +

Start Asynchronous Trigger for DETECTION_MANAGER

+ +

Parameter

+
    +
  • + +

    #number Delay :

    + +
  • +
+
+
+
+
+ + +DETECTION_MANAGER:__Stop(Delay) + +
+
+ +

Stop Asynchronous Trigger for DETECTION_MANAGER

+ +

Parameter

+
    +
  • + +

    #number Delay :

    + +
  • +
diff --git a/docs/Documentation/Escort.html b/docs/Documentation/Escort.html index 03f1da661..ebf59fcc1 100644 --- a/docs/Documentation/Escort.html +++ b/docs/Documentation/Escort.html @@ -17,6 +17,11 @@ index + +
+
+
+ + + +GROUPTEMPLATE + +
+
+ + +

Type Group

@@ -1985,6 +2044,20 @@ The country ID.

#table:

+ +
+
+
+ + #GROUP.Takeoff + +GROUP.Takeoff + +
+
+ + +
@@ -2011,6 +2084,68 @@ The country ID.

#GROUP:

+ +
+ +

Type GROUP.Takeoff

+ +

Enumerator for location at airbases

+ +

Field(s)

+
+
+ + #number + +GROUP.Takeoff.Air + +
+
+ + + +
+
+
+
+ + #number + +GROUP.Takeoff.Cold + +
+
+ + + +
+
+
+
+ + #number + +GROUP.Takeoff.Hot + +
+
+ + + +
+
+
+
+ + #number + +GROUP.Takeoff.Runway + +
+
+ + +
diff --git a/docs/Documentation/Identifiable.html b/docs/Documentation/Identifiable.html index 1e4978c18..bb4e93bce 100644 --- a/docs/Documentation/Identifiable.html +++ b/docs/Documentation/Identifiable.html @@ -17,6 +17,11 @@ index

Return value

-

Core.Point#COORDINATE:

+

#COORDINATE:

@@ -1744,7 +1749,7 @@ The Vec3 point.

Return value

-

Core.Point#COORDINATE:

+

#COORDINATE:

diff --git a/docs/Documentation/Positionable.html b/docs/Documentation/Positionable.html index b12cb6974..b38e91bd3 100644 --- a/docs/Documentation/Positionable.html +++ b/docs/Documentation/Positionable.html @@ -17,6 +17,11 @@ index
    +
  • AI_A2A
  • +
  • AI_A2A_Cap
  • +
  • AI_A2A_Dispatcher
  • +
  • AI_A2A_GCI
  • +
  • AI_A2A_Patrol
  • AI_Bai
  • AI_Balancer
  • AI_Cap
  • @@ -368,7 +373,8 @@ Nothing of this code should be modified without testing it thoroughly.

    -

    or {}

    +

    Initialize the ObjectSchedulers array, which is a weakly coupled table. + If the object used as the key is nil, then the garbage collector will remove the item from the Functions array.

    diff --git a/docs/Documentation/Scheduler.html b/docs/Documentation/Scheduler.html index 66da19f32..64e0a878f 100644 --- a/docs/Documentation/Scheduler.html +++ b/docs/Documentation/Scheduler.html @@ -17,6 +17,11 @@ index
diff --git a/docs/Documentation/SpawnStatic.html b/docs/Documentation/SpawnStatic.html index 78ec01d83..d8aa5e633 100644 --- a/docs/Documentation/SpawnStatic.html +++ b/docs/Documentation/SpawnStatic.html @@ -17,6 +17,11 @@ index