diff --git a/Moose Development/Moose/AI/AI_A2A.lua b/Moose Development/Moose/AI/AI_A2A.lua deleted file mode 100644 index f23fc006e..000000000 --- a/Moose Development/Moose/AI/AI_A2A.lua +++ /dev/null @@ -1,737 +0,0 @@ ---- **AI** -- (R2.2) - Models the process of air operations for airplanes. --- --- === --- --- ### Author: **FlightControl** --- --- === --- --- @module AI.AI_A2A --- @image MOOSE.JPG - ---BASE:TraceClass("AI_A2A") - - ---- @type AI_A2A --- @extends Core.Fsm#FSM_CONTROLLABLE - ---- The AI_A2A class implements the core functions to operate an AI @{Wrapper.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:SetFuelThreshold( .2, 60 ) - self:SetDamageThreshold( 0.4 ) - self:SetDisengageRadius( 70000 ) - - 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( "Patrolling", "Refuel", "Refuelling" ) - - --- Refuel Handler OnBefore for AI_A2A - -- @function [parent=#AI_A2A] OnBeforeRefuel - -- @param #AI_A2A self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From - -- @param #string Event - -- @param #string To - -- @return #boolean - - --- Refuel Handler OnAfter for AI_A2A - -- @function [parent=#AI_A2A] OnAfterRefuel - -- @param #AI_A2A self - -- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM. - -- @param #string From - -- @param #string Event - -- @param #string To - - --- Refuel Trigger for AI_A2A - -- @function [parent=#AI_A2A] Refuel - -- @param #AI_A2A self - - --- Refuel Asynchronous Trigger for AI_A2A - -- @function [parent=#AI_A2A] __Refuel - -- @param #AI_A2A self - -- @param #number Delay - - self:AddTransition( "*", "Takeoff", "Airborne" ) - self:AddTransition( "*", "Return", "Returning" ) - self:AddTransition( "*", "Hold", "Holding" ) - 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", "*" ) - - self.IdleCount = 0 - - return self -end - ---- @param Wrapper.Group#GROUP self --- @param Core.Event#EVENTDATA EventData -function GROUP:OnEventTakeoff( EventData, Fsm ) - Fsm:Takeoff() - self:UnHandleEvent( EVENTS.Takeoff ) -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#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h. --- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.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#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. --- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. --- @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 - ---- Sets to refuel at the given tanker. --- @param #AI_A2A self --- @param Wrapper.Group#GROUP TankerName The group name of the tanker as defined within the Mission Editor or spawned. --- @return #AI_A2A self -function AI_A2A:SetTanker( TankerName ) - self:F2( { TankerName } ) - - self.TankerName = TankerName -end - - ---- Sets the disengage range, that when engaging a target beyond the specified range, the engagement will be cancelled and the plane will RTB. --- @param #AI_A2A self --- @param #number DisengageRadius The disengage range. --- @return #AI_A2A self -function AI_A2A:SetDisengageRadius( DisengageRadius ) - self:F2( { DisengageRadius } ) - - self.DisengageRadius = DisengageRadius -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 PatrolFuelThresholdPercentage 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:SetFuelThreshold( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime ) - - self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage - 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 PatrolDamageThreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged. --- @return #AI_A2A self -function AI_A2A:SetDamageThreshold( PatrolDamageThreshold ) - - self.PatrolManageDamage = true - self.PatrolDamageThreshold = PatrolDamageThreshold - - 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:__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() - - if self.Controllable and self.Controllable:IsAlive() then - - local RTB = false - - local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() ) - - if not self:Is( "Holding" ) and not self:Is( "Returning" ) then - local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() ) - self:F({DistanceFromHomeBase=DistanceFromHomeBase}) - - if DistanceFromHomeBase > self.DisengageRadius then - self:I( self.Controllable:GetName() .. " is too far from home base, RTB!" ) - self:Hold( 300 ) - RTB = false - end - end - --- I think this code is not requirement anymore after release 2.5. --- if self:Is( "Fuel" ) or self:Is( "Damaged" ) or self:Is( "LostControl" ) then --- if DistanceFromHomeBase < 5000 then --- self:E( self.Controllable:GetName() .. " is near the home base, RTB!" ) --- self:Home( "Destroy" ) --- end --- end - - - if not self:Is( "Fuel" ) and not self:Is( "Home" ) then - local Fuel = self.Controllable:GetFuelMin() - self:F({Fuel=Fuel, PatrolFuelThresholdPercentage=self.PatrolFuelThresholdPercentage}) - if Fuel < self.PatrolFuelThresholdPercentage then - if self.TankerName then - self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" ) - self:Refuel() - else - self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" ) - local OldAIControllable = self.Controllable - - 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 - end - else - end - end - - -- TODO: Check GROUP damage function. - local Damage = self.Controllable:GetLife() - local InitialLife = self.Controllable:GetLife0() - self:F( { Damage = Damage, InitialLife = InitialLife, DamageThreshold = self.PatrolDamageThreshold } ) - if ( Damage / InitialLife ) < self.PatrolDamageThreshold then - self:I( self.Controllable:GetName() .. " is damaged: " .. Damage .. " ... RTB!" ) - self:Damaged() - RTB = true - self:SetStatusOff() - end - - -- Check if planes went RTB and are out of control. - -- We only check if planes are out of control, when they are in duty. - if self.Controllable:HasTask() == false then - if not self:Is( "Started" ) and - not self:Is( "Stopped" ) and - not self:Is( "Fuel" ) and - not self:Is( "Damaged" ) and - not self:Is( "Home" ) then - if self.IdleCount >= 3 then - if Damage ~= InitialLife then - self:Damaged() - else - self:I( self.Controllable:GetName() .. " control lost! " ) - self:LostControl() - end - else - self.IdleCount = self.IdleCount + 1 - end - end - else - self.IdleCount = 0 - end - - if RTB == true then - self:__RTB( 0.5 ) - end - - if not self:Is("Home") then - self:__Status( 10 ) - end - - end -end - - ---- @param Wrapper.Group#GROUP AIGroup -function AI_A2A.RTBRoute( AIGroup, Fsm ) - - AIGroup:F( { "AI_A2A.RTBRoute:", AIGroup:GetName() } ) - - if AIGroup:IsAlive() then - Fsm:__RTB( 0.5 ) - end - -end - ---- @param Wrapper.Group#GROUP AIGroup -function AI_A2A.RTBHold( AIGroup, Fsm ) - - AIGroup:F( { "AI_A2A.RTBHold:", AIGroup:GetName() } ) - if AIGroup:IsAlive() then - Fsm:__RTB( 0.5 ) - Fsm:Return() - local Task = AIGroup:TaskOrbitCircle( 4000, 400 ) - AIGroup:SetTask( Task ) - end - -end - - ---- @param #AI_A2A self --- @param Wrapper.Group#GROUP AIGroup -function AI_A2A:onafterRTB( AIGroup, From, Event, To ) - self:F( { AIGroup, From, Event, To } ) - - - if AIGroup and AIGroup:IsAlive() then - - self:I( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" ) - - self:ClearTargetDistance() - 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:I( "RTB and near the airbase!" ) - self:Home() - return - end - --- Create a route point of type air. - local ToRTBRoutePoint = ToAirbaseCoord:WaypointAir( - 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] = ToRTBRoutePoint - EngageRoute[#EngageRoute+1] = ToRTBRoutePoint - - 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( "AI_A2A.RTBRoute", self ) - EngageRoute[#EngageRoute].task = AIGroup:TaskCombo( Tasks ) - - --- NOW ROUTE THE GROUP! - AIGroup:Route( EngageRoute, 0.5 ) - - 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:I( "Group " .. self.Controllable:GetName() .. " ... Home! ( " .. self:GetState() .. " )" ) - - if AIGroup and AIGroup:IsAlive() then - end - -end - - - ---- @param #AI_A2A self --- @param Wrapper.Group#GROUP AIGroup -function AI_A2A:onafterHold( AIGroup, From, Event, To, HoldTime ) - self:F( { AIGroup, From, Event, To } ) - - self:I( "Group " .. self.Controllable:GetName() .. " ... Holding! ( " .. self:GetState() .. " )" ) - - if AIGroup and AIGroup:IsAlive() then - local OrbitTask = AIGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed ) - local TimedOrbitTask = AIGroup:TaskControlled( OrbitTask, AIGroup:TaskCondition( nil, nil, nil, nil, HoldTime , nil ) ) - - local RTBTask = AIGroup:TaskFunction( "AI_A2A.RTBHold", self ) - - local OrbitHoldTask = AIGroup:TaskOrbitCircle( 4000, self.PatrolMinSpeed ) - - --AIGroup:SetState( AIGroup, "AI_A2A", self ) - - AIGroup:SetTask( AIGroup:TaskCombo( { TimedOrbitTask, RTBTask, OrbitHoldTask } ), 1 ) - end - -end - ---- @param Wrapper.Group#GROUP AIGroup -function AI_A2A.Resume( AIGroup, Fsm ) - - AIGroup:I( { "AI_A2A.Resume:", AIGroup:GetName() } ) - if AIGroup:IsAlive() then - Fsm:__RTB( 0.5 ) - end - -end - ---- @param #AI_A2A self --- @param Wrapper.Group#GROUP AIGroup -function AI_A2A:onafterRefuel( AIGroup, From, Event, To ) - self:F( { AIGroup, From, Event, To } ) - - self:I( "Group " .. self.Controllable:GetName() .. " ... Refuelling! ( " .. self:GetState() .. " )" ) - - if AIGroup and AIGroup:IsAlive() then - local Tanker = GROUP:FindByName( self.TankerName ) - if Tanker:IsAlive() and Tanker:IsAirPlane() then - - local RefuelRoute = {} - - --- Calculate the target route point. - - local CurrentCoord = AIGroup:GetCoordinate() - local ToRefuelCoord = Tanker:GetCoordinate() - local ToRefuelSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed ) - - --- Create a route point of type air. - local ToRefuelRoutePoint = CurrentCoord:WaypointAir( - self.PatrolAltType, - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - ToRefuelSpeed, - true - ) - - self:F( { ToRefuelSpeed = ToRefuelSpeed } ) - - RefuelRoute[#RefuelRoute+1] = ToRefuelRoutePoint - RefuelRoute[#RefuelRoute+1] = ToRefuelRoutePoint - - AIGroup:OptionROEHoldFire() - AIGroup:OptionROTEvadeFire() - - local Tasks = {} - Tasks[#Tasks+1] = AIGroup:TaskRefueling() - Tasks[#Tasks+1] = AIGroup:TaskFunction( self:GetClassName() .. ".Resume", self ) - RefuelRoute[#RefuelRoute].task = AIGroup:TaskCombo( Tasks ) - - AIGroup:Route( RefuelRoute, 0.5 ) - else - self:RTB() - end - 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:I( 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 index ba41a3bab..460d5d614 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -10,7 +10,8 @@ -- @image AI_Combat_Air_Patrol.JPG --- @type AI_A2A_CAP --- @extends AI.AI_A2A_Patrol#AI_A2A_PATROL +-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL +-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE --- The AI_A2A_CAP class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group} @@ -97,6 +98,36 @@ AI_A2A_CAP = { ClassName = "AI_A2A_CAP", } +--- Creates a new AI_A2A_CAP object +-- @param #AI_A2A_CAP self +-- @param Wrapper.Group#GROUP AICap +-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement. +-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement. +-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO". +-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. +-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h. +-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. +-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO". +-- @return #AI_A2A_CAP +function AI_A2A_CAP:New2( AICap, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType ) + + -- Multiple inheritance ... :-) + local AI_Air = AI_AIR:New( AICap ) + local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL + local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AICap, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) + local self = BASE:Inherit( self, AI_Air_Engage ) + + self:SetFuelThreshold( .2, 60 ) + self:SetDamageThreshold( 0.4 ) + self:SetDisengageRadius( 70000 ) + + return self +end + --- Creates a new AI_A2A_CAP object -- @param #AI_A2A_CAP self -- @param Wrapper.Group#GROUP AICap @@ -111,176 +142,8 @@ AI_A2A_CAP = { -- @return #AI_A2A_CAP function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType ) - -- Inherits from BASE - local self = BASE:Inherit( self, AI_A2A_PATROL:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_A2A_CAP + return self:New2( AICap, EngageMinSpeed, EngageMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolZone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, PatrolAltType ) - self.Accomplished = false - self.Engaging = false - - self.EngageMinSpeed = EngageMinSpeed - self.EngageMaxSpeed = EngageMaxSpeed - - self:AddTransition( { "Patrolling", "Engaging", "Returning", "Airborne" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP. - - --- OnBefore Transition Handler for Event Engage. - -- @function [parent=#AI_A2A_CAP] OnBeforeEngage - -- @param #AI_A2A_CAP self - -- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter Transition Handler for Event Engage. - -- @function [parent=#AI_A2A_CAP] OnAfterEngage - -- @param #AI_A2A_CAP self - -- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Synchronous Event Trigger for Event Engage. - -- @function [parent=#AI_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.Group#GROUP AICap The Group Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. --- @return #boolean Return false to cancel Transition. - ---- OnEnter Transition Handler for State Engaging. --- @function [parent=#AI_A2A_CAP] OnEnterEngaging --- @param #AI_A2A_CAP self --- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. - - self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP. - - --- OnBefore Transition Handler for Event Fired. - -- @function [parent=#AI_A2A_CAP] OnBeforeFired - -- @param #AI_A2A_CAP self - -- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter Transition Handler for Event Fired. - -- @function [parent=#AI_A2A_CAP] OnAfterFired - -- @param #AI_A2A_CAP self - -- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Synchronous Event Trigger for Event Fired. - -- @function [parent=#AI_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.Group#GROUP AICap The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter Transition Handler for Event Destroy. - -- @function [parent=#AI_A2A_CAP] OnAfterDestroy - -- @param #AI_A2A_CAP self - -- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Synchronous Event Trigger for Event Destroy. - -- @function [parent=#AI_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.Group#GROUP AICap The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter Transition Handler for Event Abort. - -- @function [parent=#AI_A2A_CAP] OnAfterAbort - -- @param #AI_A2A_CAP self - -- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Synchronous Event Trigger for Event Abort. - -- @function [parent=#AI_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.Group#GROUP AICap The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter Transition Handler for Event Accomplish. - -- @function [parent=#AI_A2A_CAP] OnAfterAccomplish - -- @param #AI_A2A_CAP self - -- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Synchronous Event Trigger for Event Accomplish. - -- @function [parent=#AI_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. - - self:AddTransition( { "Patrolling", "Engaging" }, "Refuel", "Refuelling" ) - - return self end --- onafter State Transition for Event Patrol. @@ -291,7 +154,7 @@ end -- @param #string To The To State string. function AI_A2A_CAP:onafterStart( AICap, From, Event, To ) - self:GetParent( self ).onafterStart( self, AICap, From, Event, To ) + self:GetParent( self, AI_A2A_CAP ).onafterStart( self, AICap, From, Event, To ) AICap:HandleEvent( EVENTS.Takeoff, nil, self ) end @@ -324,168 +187,26 @@ function AI_A2A_CAP:SetEngageRange( EngageRange ) end end ---- onafter State Transition for Event Patrol. +--- Evaluate the attack and create an AttackUnitTask list. -- @param #AI_A2A_CAP self --- @param Wrapper.Group#GROUP AICap 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( AICap, From, Event, To ) +-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack. +-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders. +-- @param #number EngageAltitude The altitude to engage the targets. +-- @return #AI_A2A_CAP self +function AI_A2A_CAP:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude ) - -- Call the parent Start event handler - self:GetParent(self).onafterPatrol( self, AICap, From, Event, To ) - self:HandleEvent( EVENTS.Dead ) + local AttackUnitTasks = {} -end - --- todo: need to fix this global function - ---- @param Wrapper.Group#GROUP AICap -function AI_A2A_CAP.AttackRoute( AICap, Fsm ) - - AICap:F( { "AI_A2A_CAP.AttackRoute:", AICap:GetName() } ) - - if AICap:IsAlive() then - Fsm:__Engage( 0.5 ) - end -end - ---- @param #AI_A2A_CAP self --- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. -function AI_A2A_CAP:onbeforeEngage( AICap, From, Event, To ) - - if self.Accomplished == true then - return false - end -end - ---- @param #AI_A2A_CAP self --- @param Wrapper.Group#GROUP AICap 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( AICap, From, Event, To ) - AICap:ClearTasks() - self:__Route( 0.5 ) -end - - ---- @param #AI_A2A_CAP self --- @param Wrapper.Group#GROUP AICap The AICap 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( AICap, From, Event, To, AttackSetUnit ) - - self:F( { AICap, From, Event, To, AttackSetUnit} ) - - self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT - - local FirstAttackUnit = self.AttackSetUnit:GetFirst() -- Wrapper.Unit#UNIT - - if FirstAttackUnit and FirstAttackUnit:IsAlive() then -- If there is no attacker anymore, stop the engagement. - - if AICap and AICap:IsAlive() then - - local EngageRoute = {} - - --- Calculate the target route point. - local CurrentCoord = AICap:GetCoordinate() - local ToTargetCoord = self.AttackSetUnit:GetFirst():GetCoordinate() - local ToTargetSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed ) - local ToInterceptAngle = CurrentCoord:GetAngleDegrees( CurrentCoord:GetDirectionVec3( ToTargetCoord ) ) - - --- Create a route point of type air. - local ToPatrolRoutePoint = CurrentCoord:Translate( 5000, ToInterceptAngle ):WaypointAir( - self.PatrolAltType, - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - ToTargetSpeed, - true - ) - - self:F( { Angle = ToInterceptAngle, ToTargetSpeed = ToTargetSpeed } ) - self:T2( { self.MinSpeed, self.MaxSpeed, ToTargetSpeed } ) - - EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint - EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint - - local AttackTasks = {} - - for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do - local AttackUnit = AttackUnit -- Wrapper.Unit#UNIT - self:T( { "Attacking Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsAir() } ) - if AttackUnit:IsAlive() and AttackUnit:IsAir() then - -- TODO: Add coalition check? Only attack units of if AttackUnit:GetCoalition()~=AICap:GetCoalition() - -- Maybe the detected set also contains - AttackTasks[#AttackTasks+1] = AICap:TaskAttackUnit( AttackUnit ) - end - end - - if #AttackTasks == 0 then - self:E("No targets found -> Going back to Patrolling") - self:__Abort( 0.5 ) - else - AICap:OptionROEOpenFire() - AICap:OptionROTEvadeFire() - - AttackTasks[#AttackTasks+1] = AICap:TaskFunction( "AI_A2A_CAP.AttackRoute", self ) - EngageRoute[#EngageRoute].task = AICap:TaskCombo( AttackTasks ) - end - - AICap:Route( EngageRoute, 0.5 ) + 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 + -- TODO: Add coalition check? Only attack units of if AttackUnit:GetCoalition()~=AICap:GetCoalition() + -- Maybe the detected set also contains + AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit ) end - else - self:E("No targets found -> Going back to Patrolling") - self:__Abort( 0.5 ) - end -end - ---- @param #AI_A2A_CAP self --- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. -function AI_A2A_CAP:onafterAccomplish( AICap, From, Event, To ) - self.Accomplished = true - self:SetDetectionOff() -end - ---- @param #AI_A2A_CAP self --- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. --- @param Core.Event#EVENTDATA EventData -function AI_A2A_CAP:onafterDestroy( AICap, 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 - ---- @param Wrapper.Group#GROUP AICap -function AI_A2A_CAP.Resume( AICap, Fsm ) - - AICap:I( { "AI_A2A_CAP.Resume:", AICap:GetName() } ) - if AICap:IsAlive() then - Fsm:__Reset( 1 ) - Fsm:__Route( 5 ) end + return AttackUnitTasks end + diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index cf59ef0fa..43d74920d 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -1770,13 +1770,87 @@ do -- AI_A2A_DISPATCHER --- Set a CAP for a Squadron. -- @param #AI_A2A_DISPATCHER self -- @param #string SquadronName The squadron name. - -- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed. - -- @param #number FloorAltitude The minimum altitude at which the cap can be executed. - -- @param #number CeilingAltitude the maximum altitude at which the cap can be executed. - -- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed. - -- @param #number PatrolMaxSpeed The maximum speed at which the cap can be executed. -- @param #number EngageMinSpeed The minimum speed at which the engage can be executed. -- @param #number EngageMaxSpeed The maximum speed at which the engage can be executed. + -- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement. + -- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement. + -- @param #number EngageAltType The altitude type to engage, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude. + -- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed. + -- @param #number 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 PatrolFloorAltitude The minimum altitude at which the cap can be executed. + -- @param #number PatrolCeilingAltitude the maximum altitude at which the cap can be executed. + -- @param #number PatrolAltType The altitude type to patrol, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude. + -- @return #AI_A2A_DISPATCHER + -- @usage + -- + -- -- CAP Squadron execution. + -- CAPZoneEast = ZONE_POLYGON:New( "CAP Zone East", GROUP:FindByName( "CAP Zone East" ) ) + -- -- Setup a CAP, engaging between 800 and 900 km/h, altitude 30 (above the sea), radio altitude measurement, + -- -- patrolling speed between 500 and 600 km/h, altitude between 4000 and 10000 meters, barometric altitude measurement. + -- A2ADispatcher:SetSquadronCapV2( "Mineralnye", 800, 900, 30, 30, "RADIO", CAPZoneEast, 500, 600, 4000, 10000, "BARO" ) + -- A2ADispatcher:SetSquadronCapInterval( "Mineralnye", 2, 30, 60, 1 ) + -- + -- CAPZoneWest = ZONE_POLYGON:New( "CAP Zone West", GROUP:FindByName( "CAP Zone West" ) ) + -- -- Setup a CAP, engaging between 800 and 1200 km/h, altitude between 4000 and 10000 meters, radio altitude measurement, + -- -- patrolling speed between 600 and 800 km/h, altitude between 4000 and 8000, barometric altitude measurement. + -- A2ADispatcher:SetSquadronCapV2( "Sochi", 800, 1200, 2000, 3000, "RADIO", CAPZoneWest, 600, 800, 4000, 8000, "BARO" ) + -- A2ADispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 ) + -- + -- CAPZoneMiddle = ZONE:New( "CAP Zone Middle") + -- -- Setup a CAP, engaging between 800 and 1200 km/h, altitude between 5000 and 8000 meters, barometric altitude measurement, + -- -- patrolling speed between 600 and 800 km/h, altitude between 4000 and 8000, radio altitude. + -- A2ADispatcher:SetSquadronCapV2( "Maykop", 800, 1200, 5000, 8000, "BARO", CAPZoneMiddle, 600, 800, 4000, 8000, "RADIO" ) + -- A2ADispatcher:SetSquadronCapInterval( "Maykop", 2, 30, 120, 1 ) + -- + function AI_A2A_DISPATCHER:SetSquadronCap2( SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, Zone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType ) + + 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.EngageMinSpeed = EngageMinSpeed + Cap.EngageMaxSpeed = EngageMaxSpeed + Cap.EngageFloorAltitude = EngageFloorAltitude + Cap.EngageCeilingAltitude = EngageCeilingAltitude + Cap.Zone = Zone + Cap.PatrolMinSpeed = PatrolMinSpeed + Cap.PatrolMaxSpeed = PatrolMaxSpeed + Cap.PatrolFloorAltitude = PatrolFloorAltitude + Cap.PatrolCeilingAltitude = PatrolCeilingAltitude + Cap.PatrolAltType = PatrolAltType + Cap.EngageAltType = EngageAltType + + self:SetSquadronCapInterval( SquadronName, self.DefenderDefault.CapLimit, self.DefenderDefault.CapMinSeconds, self.DefenderDefault.CapMaxSeconds, 1 ) + + self:I( { CAP = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, Zone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageAltType } } ) + + -- Add the CAP to the EWR network. + + local RecceSet = self.Detection:GetDetectionSet() + RecceSet:FilterPrefixes( DefenderSquadron.TemplatePrefixes ) + RecceSet:FilterStart() + + self.Detection:SetFriendlyPrefixes( DefenderSquadron.TemplatePrefixes ) + + return self + end + + --- Set a CAP for a Squadron. + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The squadron name. + -- @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 DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement. + -- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement. + -- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed. + -- @param #number PatrolFloorAltitude The minimum altitude at which the cap can be executed. + -- @param #number PatrolCeilingAltitude 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 AltType The altitude type, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude. -- @return #AI_A2A_DISPATCHER -- @usage @@ -1794,37 +1868,9 @@ do -- AI_A2A_DISPATCHER -- A2ADispatcher:SetSquadronCap( "Maykop", CAPZoneMiddle, 4000, 8000, 600, 800, 800, 1200, "RADIO" ) -- A2ADispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 ) -- - 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 ) + function AI_A2A_DISPATCHER:SetSquadronCap( SquadronName, Zone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, EngageMinSpeed, EngageMaxSpeed, AltType ) - local Cap = self.DefenderSquadrons[SquadronName].Cap - Cap.Name = SquadronName - Cap.Zone = Zone - Cap.FloorAltitude = FloorAltitude - Cap.CeilingAltitude = CeilingAltitude - Cap.PatrolMinSpeed = PatrolMinSpeed - Cap.PatrolMaxSpeed = PatrolMaxSpeed - Cap.EngageMinSpeed = EngageMinSpeed - Cap.EngageMaxSpeed = EngageMaxSpeed - Cap.AltType = AltType - - self:SetSquadronCapInterval( SquadronName, self.DefenderDefault.CapLimit, self.DefenderDefault.CapMinSeconds, self.DefenderDefault.CapMaxSeconds, 1 ) - - self:F( { CAP = { SquadronName, Zone, FloorAltitude, CeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, AltType } } ) - - -- Add the CAP to the EWR network. - - local RecceSet = self.Detection:GetDetectionSet() - RecceSet:FilterPrefixes( DefenderSquadron.TemplatePrefixes ) - RecceSet:FilterStart() - - self.Detection:SetFriendlyPrefixes( DefenderSquadron.TemplatePrefixes ) - - return self + return self:SetSquadronCap2( SquadronName, EngageMinSpeed, EngageMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, AltType, Zone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, AltType ) end --- Set the squadron CAP parameters. @@ -2012,6 +2058,37 @@ do -- AI_A2A_DISPATCHER return nil end + --- Set squadron GCI. + -- @param #AI_A2A_DISPATCHER self + -- @param #string SquadronName The squadron name. + -- @param #number EngageMinSpeed The minimum speed [km/h] at which the GCI can be executed. + -- @param #number EngageMaxSpeed The maximum speed [km/h] at which the GCI can be executed. + -- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement. + -- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement. + -- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO". + -- @usage + -- + -- -- GCI Squadron execution. + -- A2ADispatcher:SetSquadronGci2( "Mozdok", 900, 1200, 5000, 5000, "BARO" ) + -- A2ADispatcher:SetSquadronGci2( "Novo", 900, 2100, 30, 30, "RADIO" ) + -- A2ADispatcher:SetSquadronGci2( "Maykop", 900, 1200, 100, 300, "RADIO" ) + -- + -- @return #AI_A2A_DISPATCHER + function AI_A2A_DISPATCHER:SetSquadronGci2( SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) + + 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 + Intercept.EngageFloorAltitude = EngageFloorAltitude + Intercept.EngageCeilingAltitude = EngageCeilingAltitude + Intercept.EngageAltType = EngageAltType + + self:I( { GCI = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } ) + end --- Set squadron GCI. -- @param #AI_A2A_DISPATCHER self @@ -3080,7 +3157,7 @@ do -- AI_A2A_DISPATCHER 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 ) + local Fsm = AI_A2A_CAP:New2( DefenderCAP, Cap.EngageMinSpeed, Cap.EngageMaxSpeed, Cap.EngageFloorAltitude, Cap.EngageCeilingAltitude, Cap.EngageAltType, Cap.Zone, Cap.PatrolMinSpeed, Cap.PatrolMaxSpeed, Cap.PatrolFloorAltitude, Cap.PatrolCeilingAltitude, Cap.PatrolAltType ) Fsm:SetDispatcher( self ) Fsm:SetHomeAirbase( DefenderSquadron.Airbase ) Fsm:SetFuelThreshold( DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold, 60 ) @@ -3101,7 +3178,7 @@ do -- AI_A2A_DISPATCHER self:SetDefenderTask( SquadronName, DefenderCAP, "CAP", Fsm ) function Fsm:onafterTakeoff( DefenderGroup, From, Event, To ) - self:F({"CAP Birth", DefenderGroup:GetName()}) + self:F({"CAP Takeoff", DefenderGroup:GetName()}) --self:GetParent(self).onafterBirth( self, Defender, From, Event, To ) local DefenderName = DefenderGroup:GetCallsign() @@ -3113,7 +3190,7 @@ do -- AI_A2A_DISPATCHER Fsm:__Patrol( 2 ) -- Start Patrolling end end - + function Fsm:onafterRTB( DefenderGroup, From, Event, To ) self:F({"CAP RTB", DefenderGroup:GetName()}) @@ -3169,7 +3246,7 @@ do -- AI_A2A_DISPATCHER for DefenderID, Defender in pairs( Defenders ) do local Fsm = self:GetDefenderTaskFsm( Defender ) - Fsm:__Engage( 1, AttackerDetection.Set ) -- Engage on the TargetSetUnit + Fsm:__EngageRoute( 1, AttackerDetection.Set ) -- Engage on the TargetSetUnit self:SetDefenderTaskTarget( Defender, AttackerDetection ) @@ -3201,7 +3278,7 @@ do -- AI_A2A_DISPATCHER for DefenderID, DefenderGroup in pairs( DefenderFriendlies or {} ) do local Fsm = self:GetDefenderTaskFsm( DefenderGroup ) - Fsm:__Engage( 1, AttackerSet ) -- Engage on the TargetSetUnit + Fsm:__EngageRoute( 1, AttackerSet ) -- Engage on the TargetSetUnit self:SetDefenderTaskTarget( DefenderGroup, AttackerDetection ) @@ -3283,7 +3360,7 @@ do -- AI_A2A_DISPATCHER DefenderCount = DefenderCount - DefenderGrouping / DefenderOverhead - local Fsm = AI_A2A_GCI:New( DefenderGCI, Gci.EngageMinSpeed, Gci.EngageMaxSpeed ) + local Fsm = AI_A2A_GCI:New2( DefenderGCI, Gci.EngageMinSpeed, Gci.EngageMaxSpeed, Gci.EngageFloorAltitude, Gci.EngageCeilingAltitude, Gci.EngageAltType ) Fsm:SetDispatcher( self ) Fsm:SetHomeAirbase( DefenderSquadron.Airbase ) Fsm:SetFuelThreshold( DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold, 60 ) @@ -3306,10 +3383,27 @@ do -- AI_A2A_DISPATCHER if DefenderTarget then Dispatcher:MessageToPlayers( DefenderName .. " wheels up.", DefenderGroup ) - Fsm:__Engage( 2, DefenderTarget.Set ) -- Engage on the TargetSetUnit + --Fsm:__Engage( 2, DefenderTarget.Set ) -- Engage on the TargetSetUnit + Fsm:EngageRoute( DefenderTarget.Set ) -- Engage on the TargetSetUnit end end + function Fsm:onafterEngageRoute( DefenderGroup, From, Event, To, AttackSetUnit ) + self:F({"GCI Route", DefenderGroup:GetName()}) + + local DefenderName = DefenderGroup:GetCallsign() + local Dispatcher = Fsm:GetDispatcher() -- #AI_A2A_DISPATCHER + local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup ) + + if Squadron then + local FirstUnit = AttackSetUnit:GetFirst() + local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE + + Dispatcher:MessageToPlayers( DefenderName .. ", intercepting bogeys at " .. Coordinate:ToStringA2A( DefenderGroup ), DefenderGroup ) + end + self:GetParent( Fsm ).onafterEngageRoute( self, DefenderGroup, From, Event, To, AttackSetUnit ) + end + function Fsm:onafterRTB( DefenderGroup, From, Event, To ) self:F({"GCI RTB", DefenderGroup:GetName()}) self:GetParent(self).onafterRTB( self, DefenderGroup, From, Event, To ) diff --git a/Moose Development/Moose/AI/AI_A2A_Gci.lua b/Moose Development/Moose/AI/AI_A2A_Gci.lua index a6642a9ce..f0ddb1d13 100644 --- a/Moose Development/Moose/AI/AI_A2A_Gci.lua +++ b/Moose Development/Moose/AI/AI_A2A_Gci.lua @@ -105,185 +105,39 @@ AI_A2A_GCI = { --- Creates a new AI_A2A_GCI object -- @param #AI_A2A_GCI self -- @param Wrapper.Group#GROUP AIIntercept +-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement. +-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement. +-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO". -- @return #AI_A2A_GCI -function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed ) +function AI_A2A_GCI:New2( AIIntercept, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) - -- Inherits from BASE - local self = BASE:Inherit( self, AI_A2A:New( AIIntercept ) ) -- #AI_A2A_GCI - - self.Accomplished = false - self.Engaging = false + local AI_Air = AI_AIR:New( AIIntercept ) + local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air, AIIntercept, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) + local self = BASE:Inherit( self, AI_Air_Engage ) -- #AI_A2A_GCI - self.EngageMinSpeed = EngageMinSpeed - self.EngageMaxSpeed = EngageMaxSpeed - self.PatrolMinSpeed = EngageMinSpeed - self.PatrolMaxSpeed = EngageMaxSpeed - - self.PatrolAltType = "RADIO" - - self:AddTransition( { "Started", "Engaging", "Returning", "Airborne" }, "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 AIIntercept The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter Transition Handler for Event Engage. - -- @function [parent=#AI_A2A_GCI] OnAfterEngage - -- @param #AI_A2A_GCI self - -- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Synchronous Event Trigger for Event Engage. - -- @function [parent=#AI_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 AIIntercept The Group Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. --- @return #boolean Return false to cancel Transition. - ---- OnEnter Transition Handler for State Engaging. --- @function [parent=#AI_A2A_GCI] OnEnterEngaging --- @param #AI_A2A_GCI self --- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. - - self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI. - - --- OnBefore Transition Handler for Event Fired. - -- @function [parent=#AI_A2A_GCI] OnBeforeFired - -- @param #AI_A2A_GCI self - -- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter Transition Handler for Event Fired. - -- @function [parent=#AI_A2A_GCI] OnAfterFired - -- @param #AI_A2A_GCI self - -- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Synchronous Event Trigger for Event Fired. - -- @function [parent=#AI_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 AIIntercept The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter Transition Handler for Event Destroy. - -- @function [parent=#AI_A2A_GCI] OnAfterDestroy - -- @param #AI_A2A_GCI self - -- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Synchronous Event Trigger for Event Destroy. - -- @function [parent=#AI_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 AIIntercept The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter Transition Handler for Event Abort. - -- @function [parent=#AI_A2A_GCI] OnAfterAbort - -- @param #AI_A2A_GCI self - -- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Synchronous Event Trigger for Event Abort. - -- @function [parent=#AI_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 AIIntercept The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - -- @return #boolean Return false to cancel Transition. - - --- OnAfter Transition Handler for Event Accomplish. - -- @function [parent=#AI_A2A_GCI] OnAfterAccomplish - -- @param #AI_A2A_GCI self - -- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM. - -- @param #string From The From State string. - -- @param #string Event The Event string. - -- @param #string To The To State string. - - --- Synchronous Event Trigger for Event Accomplish. - -- @function [parent=#AI_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. - - self:AddTransition( { "Patrolling", "Engaging" }, "Refuel", "Refuelling" ) + self:SetFuelThreshold( .2, 60 ) + self:SetDamageThreshold( 0.4 ) + self:SetDisengageRadius( 70000 ) return self end +--- Creates a new AI_A2A_GCI object +-- @param #AI_A2A_GCI self +-- @param Wrapper.Group#GROUP AIIntercept +-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement. +-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement. +-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO". +-- @return #AI_A2A_GCI +function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) + + return self:New2( AIIntercept, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) +end + --- onafter State Transition for Event Patrol. -- @param #AI_A2A_GCI self -- @param Wrapper.Group#GROUP AIIntercept The AI Group managed by the FSM. @@ -292,173 +146,33 @@ end -- @param #string To The To State string. function AI_A2A_GCI:onafterStart( AIIntercept, From, Event, To ) - self:GetParent( self ).onafterStart( self, AIIntercept, From, Event, To ) - AIIntercept:HandleEvent( EVENTS.Takeoff, nil, self ) - + self:GetParent( self, AI_A2A_GCI ).onafterStart( self, AIIntercept, From, Event, To ) end - ---- onafter State Transition for Event Patrol. +--- Evaluate the attack and create an AttackUnitTask list. -- @param #AI_A2A_GCI self --- @param Wrapper.Group#GROUP AIIntercept 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( AIIntercept, From, Event, To ) +-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack. +-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders. +-- @param #number EngageAltitude The altitude to engage the targets. +-- @return #AI_A2A_GCI self +function AI_A2A_GCI:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude ) - self:HandleEvent( EVENTS.Dead ) + local AttackUnitTasks = {} -end - --- todo: need to fix this global function - ---- @param Wrapper.Group#GROUP AIControllable -function AI_A2A_GCI.InterceptRoute( AIIntercept, Fsm ) - - AIIntercept:F( { "AI_A2A_GCI.InterceptRoute:", AIIntercept:GetName() } ) - - if AIIntercept:IsAlive() then - Fsm:__Engage( 0.5 ) - - --local Task = AIIntercept:TaskOrbitCircle( 4000, 400 ) - --AIIntercept:SetTask( Task ) - end -end - ---- @param #AI_A2A_GCI self --- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. -function AI_A2A_GCI:onbeforeEngage( AIIntercept, From, Event, To ) - - if self.Accomplished == true then - return false - end -end - ---- @param #AI_A2A_GCI self --- @param Wrapper.Group#GROUP AIIntercept 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( AIIntercept, From, Event, To ) - AIIntercept:ClearTasks() - self:Return() - self:__RTB( 0.5 ) -end - - ---- @param #AI_A2A_GCI self --- @param Wrapper.Group#GROUP AIIntercept The GroupGroup 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( AIIntercept, From, Event, To, AttackSetUnit ) - - self:F( { AIIntercept, From, Event, To, AttackSetUnit} ) - - self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT - - local FirstAttackUnit = self.AttackSetUnit:GetFirst() - - if FirstAttackUnit and FirstAttackUnit:IsAlive() then - - if AIIntercept:IsAlive() then - - local EngageRoute = {} - - local CurrentCoord = AIIntercept:GetCoordinate() - - --- Calculate the target route point. - - local CurrentCoord = AIIntercept: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( 15000, ToInterceptAngle ):WaypointAir( - self.PatrolAltType, - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - ToTargetSpeed, - true - ) - - self:F( { Angle = ToInterceptAngle, ToTargetSpeed = ToTargetSpeed } ) - self:F( { self.EngageMinSpeed, self.EngageMaxSpeed, ToTargetSpeed } ) - - EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint - EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint - - local AttackTasks = {} - - for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do - local AttackUnit = AttackUnit -- Wrapper.Unit#UNIT - if AttackUnit:IsAlive() and AttackUnit:IsAir() then - self:T( { "Intercepting Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsAir() } ) - AttackTasks[#AttackTasks+1] = AIIntercept:TaskAttackUnit( AttackUnit ) - end - end - - if #AttackTasks == 0 then - self:E("No targets found -> Going RTB") - self:Return() - self:__RTB( 0.5 ) - else - AIIntercept:OptionROEOpenFire() - AIIntercept:OptionROTEvadeFire() - - AttackTasks[#AttackTasks+1] = AIIntercept:TaskFunction( "AI_A2A_GCI.InterceptRoute", self ) - EngageRoute[#EngageRoute].task = AIIntercept:TaskCombo( AttackTasks ) - end - - AIIntercept:Route( EngageRoute, 0.5 ) - + 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 + -- TODO: Add coalition check? Only attack units of if AttackUnit:GetCoalition()~=AICap:GetCoalition() + -- Maybe the detected set also contains + AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit ) end - else - self:E("No targets found -> Going RTB") - self:Return() - self:__RTB( 0.5 ) end + + return AttackUnitTasks end ---- @param #AI_A2A_GCI self --- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. -function AI_A2A_GCI:onafterAccomplish( AIIntercept, From, Event, To ) - self.Accomplished = true - self:SetDetectionOff() -end ---- @param #AI_A2A_GCI self --- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. --- @param Core.Event#EVENTDATA EventData -function AI_A2A_GCI:onafterDestroy( AIIntercept, 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 index 6b1315440..9eedd29cc 100644 --- a/Moose Development/Moose/AI/AI_A2A_Patrol.lua +++ b/Moose Development/Moose/AI/AI_A2A_Patrol.lua @@ -136,8 +136,14 @@ AI_A2A_PATROL = { -- PatrolArea = AI_A2A_PATROL:New( PatrolZone, 3000, 6000, 600, 900 ) function AI_A2A_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) - -- Inherits from BASE - local self = BASE:Inherit( self, AI_A2A:New( AIPatrol ) ) -- #AI_A2A_PATROL + local AI_Air = AI_AIR:New( AIPatrol ) + local AI_Air_Patrol = AI_A2A_PATROL:New( AI_Air, AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) + local self = BASE:Inherit( self, AI_Air_Patrol ) -- #AI_A2A_PATROL + + self:SetFuelThreshold( .2, 60 ) + self:SetDamageThreshold( 0.4 ) + self:SetDisengageRadius( 70000 ) + self.PatrolZone = PatrolZone self.PatrolFloorAltitude = PatrolFloorAltitude @@ -257,35 +263,6 @@ function AI_A2A_PATROL:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude ) self.PatrolCeilingAltitude = PatrolCeilingAltitude end ---- Set race track parameters. CAP flights will perform race track patterns rather than randomly patrolling the zone. --- @param #AI_A2A_PATROL self --- @param #number LegMin Min Length of the race track leg in meters. Default 10,000 m. --- @param #number LegMax Max length of the race track leg in meters. Default 15,000 m. --- @param #number HeadingMin Min heading of the race track in degrees. Default 0 deg, i.e. from South to North. --- @param #number HeadingMax Max heading of the race track in degrees. Default 180 deg, i.e. from South to North. --- @param #number DurationMin (Optional) Min duration before switching the orbit position. Default is keep same orbit until RTB or engage. --- @param #number DurationMax (Optional) Max duration before switching the orbit position. Default is keep same orbit until RTB or engage. --- @param #table CapCoordinates Table of coordinates of first race track point. Second point is determined by leg length and heading. --- @return #AI_A2A_PATROL self -function AI_A2A_PATROL:SetRaceTrackPattern(LegMin, LegMax, HeadingMin, HeadingMax, DurationMin, DurationMax, CapCoordinates) - self:F2({leglength, duration}) - - self.racetrack=true - self.racetracklegmin=LegMin or 10000 - self.racetracklegmax=LegMax or 15000 - self.racetrackheadingmin=HeadingMin or 0 - self.racetrackheadingmax=HeadingMax or 180 - self.racetrackdurationmin=DurationMin - self.racetrackdurationmax=DurationMax - - if self.racetrackdurationmax and not self.racetrackdurationmin then - self.racetrackdurationmin=self.racetrackdurationmax - end - - self.racetrackcapcoordinates=CapCoordinates - -end - --- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings. -- @param #AI_A2A_PATROL self @@ -426,13 +403,3 @@ function AI_A2A_PATROL:onafterRoute( AIPatrol, From, Event, To ) end ---- @param Wrapper.Group#GROUP AIPatrol -function AI_A2A_PATROL.Resume( AIPatrol, Fsm ) - - AIPatrol:I( { "AI_A2A_PATROL.Resume:", AIPatrol:GetName() } ) - if AIPatrol:IsAlive() then - Fsm:__Reset( 1 ) - Fsm:__Route( 5 ) - end - -end diff --git a/Moose Development/Moose/AI/AI_A2G.lua b/Moose Development/Moose/AI/AI_A2G.lua deleted file mode 100644 index b80eb8796..000000000 --- a/Moose Development/Moose/AI/AI_A2G.lua +++ /dev/null @@ -1,69 +0,0 @@ ---- **AI** -- Models the process of air to ground operations for airplanes and helicopters. --- --- === --- --- ### Author: **FlightControl** --- --- === --- --- @module AI.AI_A2G --- @image AI_Air_To_Ground_Dispatching.JPG - ---- @type AI_A2G --- @extends AI.AI_Air#AI_AIR - ---- The AI_A2G class implements the core functions to operate an AI @{Wrapper.Group} A2G tasking. --- --- --- # 1) AI_A2G constructor --- --- * @{#AI_A2G.New}(): Creates a new AI_A2G object. --- --- # 2) AI_A2G is a Finite State Machine. --- --- This section must be read as follows. Each of the rows indicate a state transition, triggered through an event, and with an ending state of the event was executed. --- The first column is the **From** state, the second column the **Event**, and the third column the **To** state. --- --- So, each of the rows have the following structure. --- --- * **From** => **Event** => **To** --- --- Important to know is that an event can only be executed if the **current state** is the **From** state. --- This, when an **Event** that is being triggered has a **From** state that is equal to the **Current** state of the state machine, the event will be executed, --- and the resulting state will be the **To** state. --- --- These are the different possible state transitions of this state machine implementation: --- --- * Idle => Start => Monitoring --- --- ## 2.1) AI_A2G States. --- --- * **Idle**: The process is idle. --- --- ## 2.2) AI_A2G Events. --- --- * **Start**: Start the transport process. --- * **Stop**: Stop the transport process. --- * **Monitor**: Monitor and take action. --- --- @field #AI_A2G -AI_A2G = { - ClassName = "AI_A2G", -} - ---- Creates a new AI_A2G process. --- @param #AI_A2G self --- @param Wrapper.Group#GROUP AIGroup The group object to receive the A2G Process. --- @return #AI_A2G -function AI_A2G:New( AIGroup ) - - -- Inherits from BASE - local self = BASE:Inherit( self, AI_AIR:New( AIGroup ) ) -- #AI_A2G - - self:SetFuelThreshold( .2, 60 ) - self:SetDamageThreshold( 0.95 ) - self:SetDisengageRadius( 70000 ) - - return self -end - diff --git a/Moose Development/Moose/AI/AI_A2G_BAI.lua b/Moose Development/Moose/AI/AI_A2G_BAI.lua index ac8efbb4f..8b8b8e880 100644 --- a/Moose Development/Moose/AI/AI_A2G_BAI.lua +++ b/Moose Development/Moose/AI/AI_A2G_BAI.lua @@ -35,6 +35,7 @@ AI_A2G_BAI = { -- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target. -- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement. -- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement. +-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO". -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. -- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. -- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. @@ -42,10 +43,12 @@ AI_A2G_BAI = { -- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. -- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_A2G_BAI -function AI_A2G_BAI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) +function AI_A2G_BAI:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) - -- Inherits from BASE - local self = BASE:Inherit( self, AI_A2G_PATROL:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_A2G_BAI + local AI_Air = AI_AIR:New( AIGroup ) + local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL + local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) + local self = BASE:Inherit( self, AI_Air_Engage ) local RTBSpeedMax = AIGroup:GetSpeedMax() or 9999 @@ -55,112 +58,46 @@ function AI_A2G_BAI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAlt end ---- @param #AI_A2G_BAI self --- @param Wrapper.Group#GROUP DefenderGroup The GroupGroup managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. -function AI_A2G_BAI:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit ) +--- Creates a new AI_A2G_BAI object +-- @param #AI_A2G_BAI self +-- @param Wrapper.Group#GROUP AIGroup +-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement. +-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement. +-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. +-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h. +-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. +-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @return #AI_A2G_BAI +function AI_A2G_BAI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) - self:I( { DefenderGroup, From, Event, To, AttackSetUnit} ) - - local DefenderGroupName = DefenderGroup:GetName() - - local AttackCount = AttackSetUnit:Count() - - self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air! - - if AttackCount > 0 then - - if DefenderGroup:IsAlive() then - - local EngageAltitude = math.random( self.EngageFloorAltitude, self.EngageCeilingAltitude ) - local EngageSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed ) - - -- Determine the distance to the target. - -- If it is less than 10km, then attack without a route. - -- Otherwise perform a route attack. - - local DefenderCoord = DefenderGroup:GetPointVec3() - DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude. - - local TargetCoord = AttackSetUnit:GetFirst():GetPointVec3() - TargetCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude. - - local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord ) - local EngageDistance = ( DefenderGroup:IsHelicopter() and 5000 ) or ( DefenderGroup:IsAirPlane() and 10000 ) - - local EngageRoute = {} - local AttackTasks = {} - - --- Calculate the target route point. - - local FromWP = DefenderCoord:WaypointAir( - self.PatrolAltType or "RADIO", - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - EngageSpeed, - true - ) - - EngageRoute[#EngageRoute+1] = FromWP - - self:SetTargetDistance( TargetCoord ) -- For RTB status check - - local FromEngageAngle = TargetCoord:GetAngleDegrees( TargetCoord:GetDirectionVec3( DefenderCoord ) ) - local ToWP = TargetCoord:Translate( EngageDistance, FromEngageAngle, true ):WaypointAir( - self.PatrolAltType or "RADIO", - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - EngageSpeed, - true - ) - - EngageRoute[#EngageRoute+1] = ToWP - - local AttackUnitTasks = {} - - local AttackSetUnitPerThreatLevel = AttackSetUnit:GetSetPerThreatLevel( 10, 0 ) - for AttackUnitIndex, AttackUnit in ipairs( AttackSetUnitPerThreatLevel or {} ) do - if AttackUnit then - if AttackUnit:IsAlive() and AttackUnit:IsGround() then - self:T( { "BAI Unit:", AttackUnit:GetName() } ) - AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, true, false, nil, nil, EngageAltitude ) - end - end - end - - if #AttackUnitTasks == 0 then - self:I( DefenderGroupName .. ": No targets found -> Going RTB") - self:Return() - self:__RTB( self.TaskDelay ) - else - DefenderGroup:OptionROEOpenFire() - DefenderGroup:OptionROTEvadeFire() - DefenderGroup:OptionKeepWeaponsOnThreat() - - AttackTasks[#AttackTasks+1] = DefenderGroup:TaskCombo( AttackUnitTasks ) - end - - AttackTasks[#AttackTasks+1] = DefenderGroup:TaskFunction( "AI_A2G_ENGAGE.___Engage", self, AttackSetUnit ) - EngageRoute[#EngageRoute].task = DefenderGroup:TaskCombo( AttackTasks ) - - DefenderGroup:Route( EngageRoute, self.TaskDelay ) - end - else - self:I( DefenderGroupName .. ": No targets found -> Going RTB") - self:Return() - self:__RTB( self.TaskDelay ) - end + return self:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType) end ---- @param Wrapper.Group#GROUP AIEngage -function AI_A2G_BAI.Resume( AIEngage, Fsm ) +--- Evaluate the attack and create an AttackUnitTask list. +-- @param #AI_A2G_BAI self +-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack. +-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders. +-- @param #number EngageAltitude The altitude to engage the targets. +-- @return #AI_A2G_BAI self +function AI_A2G_BAI:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude ) - AIEngage:F( { "AI_A2G_BAI.Resume:", AIEngage:GetName() } ) - if AIEngage:IsAlive() then - Fsm:__Reset( Fsm.TaskDelay ) - Fsm:__EngageRoute( Fsm.TaskDelay, Fsm.AttackSetUnit ) + local AttackUnitTasks = {} + + local AttackSetUnitPerThreatLevel = AttackSetUnit:GetSetPerThreatLevel( 10, 0 ) + for AttackUnitIndex, AttackUnit in ipairs( AttackSetUnitPerThreatLevel or {} ) do + if AttackUnit then + if AttackUnit:IsAlive() and AttackUnit:IsGround() then + self:T( { "BAI Unit:", AttackUnit:GetName() } ) + AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, true, false, nil, nil, EngageAltitude ) + end + end end -end \ No newline at end of file + return AttackUnitTasks +end + + diff --git a/Moose Development/Moose/AI/AI_A2G_CAS.lua b/Moose Development/Moose/AI/AI_A2G_CAS.lua index 8ed9ee29d..00cd73383 100644 --- a/Moose Development/Moose/AI/AI_A2G_CAS.lua +++ b/Moose Development/Moose/AI/AI_A2G_CAS.lua @@ -14,7 +14,7 @@ --- @type AI_A2G_CAS --- @extends AI.AI_A2G_Patrol#AI_A2G_PATROL +-- @extends AI.AI_A2G_Patrol#AI_AIR_PATROL --- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders. @@ -35,6 +35,7 @@ AI_A2G_CAS = { -- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target. -- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement. -- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement. +-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO". -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. -- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. -- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. @@ -42,10 +43,12 @@ AI_A2G_CAS = { -- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. -- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_A2G_CAS -function AI_A2G_CAS:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) +function AI_A2G_CAS:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) - -- Inherits from BASE - local self = BASE:Inherit( self, AI_A2G_PATROL:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_A2G_CAS + local AI_Air = AI_AIR:New( AIGroup ) + local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL + local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) + local self = BASE:Inherit( self, AI_Air_Engage ) local RTBSpeedMax = AIGroup:GetSpeedMax() or 9999 @@ -55,108 +58,47 @@ function AI_A2G_CAS:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAlt end ---- @param #AI_A2G_CAS self --- @param Wrapper.Group#GROUP DefenderGroup The GroupGroup managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. -function AI_A2G_CAS:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit ) +--- Creates a new AI_A2G_CAS object +-- @param #AI_A2G_CAS self +-- @param Wrapper.Group#GROUP AIGroup +-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement. +-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement. +-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. +-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h. +-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. +-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @return #AI_A2G_CAS +function AI_A2G_CAS:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) - self:F( { DefenderGroup, From, Event, To, AttackSetUnit} ) - - local DefenderGroupName = DefenderGroup:GetName() - - self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air! - - local AttackCount = AttackSetUnit:Count() - - if AttackCount > 0 then - - if DefenderGroup:IsAlive() then - - local EngageAltitude = math.random( self.EngageFloorAltitude or 500, self.EngageCeilingAltitude or 1000 ) - local EngageSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed ) - - local DefenderCoord = DefenderGroup:GetPointVec3() - DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude. - - local TargetCoord = AttackSetUnit:GetFirst():GetPointVec3() - TargetCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude. - - local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord ) - local EngageDistance = ( DefenderGroup:IsHelicopter() and 5000 ) or ( DefenderGroup:IsAirPlane() and 10000 ) - - local EngageRoute = {} - local AttackTasks = {} - - local FromWP = DefenderCoord:WaypointAir( - self.PatrolAltType or "RADIO", - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - EngageSpeed, - true - ) - EngageRoute[#EngageRoute+1] = FromWP - - self:SetTargetDistance( TargetCoord ) -- For RTB status check - - local FromEngageAngle = DefenderCoord:GetAngleDegrees( DefenderCoord:GetDirectionVec3( TargetCoord ) ) - local ToWP = DefenderCoord:Translate( EngageDistance, FromEngageAngle, true ):WaypointAir( - self.PatrolAltType or "RADIO", - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - EngageSpeed, - true - ) - EngageRoute[#EngageRoute+1] = ToWP - - if TargetDistance <= EngageDistance * 3 then - - local AttackUnitTasks = {} - - local AttackSetUnitPerThreatLevel = AttackSetUnit:GetSetPerThreatLevel( 10, 0 ) - for AttackUnitIndex, AttackUnit in ipairs( AttackSetUnitPerThreatLevel or {} ) do - if AttackUnit then - if AttackUnit:IsAlive() and AttackUnit:IsGround() then - self:T( { "CAS Unit:", AttackUnit:GetName() } ) - AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, true, false, nil, nil, EngageAltitude ) - end - end - end - - - if #AttackUnitTasks == 0 then - self:I( DefenderGroupName .. ": No targets found -> Going RTB") - self:Return() - self:__RTB( self.TaskDelay ) - else - DefenderGroup:OptionROEOpenFire() - DefenderGroup:OptionROTEvadeFire() - DefenderGroup:OptionKeepWeaponsOnThreat() - - AttackTasks[#AttackTasks+1] = DefenderGroup:TaskCombo( AttackUnitTasks ) - end - end - - AttackTasks[#AttackTasks+1] = DefenderGroup:TaskFunction( "AI_A2G_ENGAGE.___Engage", self, AttackSetUnit ) - EngageRoute[#EngageRoute].task = DefenderGroup:TaskCombo( AttackTasks ) - - DefenderGroup:Route( EngageRoute, self.TaskDelay ) - end - else - self:I( DefenderGroupName .. ": No targets found -> Going RTB") - self:Return() - self:__RTB( self.TaskDelay ) - end + return self:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType) end ---- @param Wrapper.Group#GROUP AIEngage -function AI_A2G_CAS.Resume( AIEngage, Fsm ) +--- Evaluate the attack and create an AttackUnitTask list. +-- @param #AI_A2G_CAS self +-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack. +-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders. +-- @param #number EngageAltitude The altitude to engage the targets. +-- @return #AI_A2G_CAS self +function AI_A2G_CAS:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude ) - AIEngage:F( { "AI_A2G_CAS.Resume:", AIEngage:GetName() } ) - if AIEngage:IsAlive() then - Fsm:__Reset( Fsm.TaskDelay ) - Fsm:__EngageRoute( Fsm.TaskDelay, Fsm.AttackSetUnit ) + local AttackUnitTasks = {} + + local AttackSetUnitPerThreatLevel = AttackSetUnit:GetSetPerThreatLevel( 10, 0 ) + for AttackUnitIndex, AttackUnit in ipairs( AttackSetUnitPerThreatLevel or {} ) do + if AttackUnit then + if AttackUnit:IsAlive() and AttackUnit:IsGround() then + self:T( { "CAS Unit:", AttackUnit:GetName() } ) + AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, true, false, nil, nil, EngageAltitude ) + end + end end -end \ No newline at end of file + return AttackUnitTasks +end + + + diff --git a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua index 0c6450c2c..3628fca69 100644 --- a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua @@ -2088,22 +2088,23 @@ do -- AI_A2G_DISPATCHER - --- + --- Set a squadron to engage for suppression of air defenses, when a defense point is under attack. -- @param #AI_A2G_DISPATCHER self -- @param #string SquadronName The squadron name. -- @param #number EngageMinSpeed (optional, default = 50% of max speed) The minimum speed at which the SEAD task can be executed. -- @param #number EngageMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the SEAD task can be executed. -- @param DCS#Altitude EngageFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the engagement. -- @param DCS#Altitude EngageCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the engagement. + -- @param #number EngageAltType The altitude type when engaging, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude. -- @usage -- -- -- SEAD Squadron execution. - -- A2GDispatcher:SetSquadronSead( "Mozdok", 900, 1200 ) - -- A2GDispatcher:SetSquadronSead( "Novo", 900, 2100 ) - -- A2GDispatcher:SetSquadronSead( "Maykop", 900, 1200 ) + -- A2GDispatcher:SetSquadronSead( "Mozdok", 900, 1200, 4000, 5000, "BARO" ) + -- A2GDispatcher:SetSquadronSead( "Novo", 900, 2100, 6000, 9000, "BARO" ) + -- A2GDispatcher:SetSquadronSead( "Maykop", 900, 1200, 30, 100, "RADIO" ) -- -- @return #AI_A2G_DISPATCHER - function AI_A2G_DISPATCHER:SetSquadronSead( SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude ) + function AI_A2G_DISPATCHER:SetSquadronSead2( SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) local DefenderSquadron = self:GetSquadron( SquadronName ) @@ -2115,9 +2116,32 @@ do -- AI_A2G_DISPATCHER Sead.EngageMaxSpeed = EngageMaxSpeed Sead.EngageFloorAltitude = EngageFloorAltitude or 500 Sead.EngageCeilingAltitude = EngageCeilingAltitude or 1000 + Sead.EngageAltType = EngageAltType Sead.Defend = true - self:F( { Sead = Sead } ) + self:I( { SEAD = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } ) + + return self + end + + --- Set a squadron to engage for suppression of air defenses, when a defense point is under attack. + -- @param #AI_A2G_DISPATCHER self + -- @param #string SquadronName The squadron name. + -- @param #number EngageMinSpeed (optional, default = 50% of max speed) The minimum speed at which the SEAD task can be executed. + -- @param #number EngageMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the SEAD task can be executed. + -- @param DCS#Altitude EngageFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the engagement. + -- @param DCS#Altitude EngageCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the engagement. + -- @usage + -- + -- -- SEAD Squadron execution. + -- A2GDispatcher:SetSquadronSead( "Mozdok", 900, 1200, 4000, 5000 ) + -- A2GDispatcher:SetSquadronSead( "Novo", 900, 2100, 6000, 8000 ) + -- A2GDispatcher:SetSquadronSead( "Maykop", 900, 1200, 6000, 10000 ) + -- + -- @return #AI_A2G_DISPATCHER + function AI_A2G_DISPATCHER:SetSquadronSead( SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude ) + + return self:SetSquadronSead2( SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, "RADIO" ) end --- Set the squadron SEAD engage limit. @@ -2140,6 +2164,55 @@ do -- AI_A2G_DISPATCHER + --- Set a Sead patrol for a Squadron. + -- The Sead patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded. + -- @param #AI_A2G_DISPATCHER self + -- @param #string SquadronName The squadron name. + -- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed. + -- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed. + -- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed. + -- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed. + -- @param #number PatrolCeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed. + -- @param #number PatrolAltType The altitude type when patrolling, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude. + -- @param #number EngageMinSpeed (optional, default = 50% of max speed) The minimum speed at which the engage can be executed. + -- @param #number EngageMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the engage can be executed. + -- @param #number EngageFloorAltitude (optional, default = 1000m ) The minimum altitude at which the engage can be executed. + -- @param #number EngageCeilingAltitude (optional, default = 1500m ) The maximum altitude at which the engage can be executed. + -- @param #number EngageAltType The altitude type when engaging, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude. + -- @return #AI_A2G_DISPATCHER + -- @usage + -- + -- -- Sead Patrol Squadron execution. + -- PatrolZoneEast = ZONE_POLYGON:New( "Patrol Zone East", GROUP:FindByName( "Patrol Zone East" ) ) + -- A2GDispatcher:SetSquadronSeadPatrol2( "Mineralnye", PatrolZoneEast, 500, 600, 4000, 10000, "BARO", 800, 900, 2000, 3000, "RADIO", ) + -- + function AI_A2G_DISPATCHER:SetSquadronSeadPatrol2( SquadronName, Zone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) + + local DefenderSquadron = self:GetSquadron( SquadronName ) + + DefenderSquadron.SEAD = DefenderSquadron.SEAD or {} + + local SeadPatrol = DefenderSquadron.SEAD + SeadPatrol.Name = SquadronName + SeadPatrol.Zone = Zone + SeadPatrol.PatrolFloorAltitude = PatrolFloorAltitude + SeadPatrol.PatrolCeilingAltitude = PatrolCeilingAltitude + SeadPatrol.EngageFloorAltitude = EngageFloorAltitude + SeadPatrol.EngageCeilingAltitude = EngageCeilingAltitude + SeadPatrol.PatrolMinSpeed = PatrolMinSpeed + SeadPatrol.PatrolMaxSpeed = PatrolMaxSpeed + SeadPatrol.EngageMinSpeed = EngageMinSpeed + SeadPatrol.EngageMaxSpeed = EngageMaxSpeed + SeadPatrol.PatrolAltType = PatrolAltType + SeadPatrol.EngageAltType = EngageAltType + SeadPatrol.Patrol = true + + self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "SEAD" ) + + self:I( { SEAD = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } ) + end + + --- Set a Sead patrol for a Squadron. -- The Sead patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded. -- @param #AI_A2G_DISPATCHER self @@ -2160,47 +2233,29 @@ do -- AI_A2G_DISPATCHER -- A2GDispatcher:SetSquadronSeadPatrol( "Mineralnye", PatrolZoneEast, 4000, 10000, 500, 600, 800, 900 ) -- function AI_A2G_DISPATCHER:SetSquadronSeadPatrol( SquadronName, Zone, FloorAltitude, CeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, AltType ) + + self:SetSquadronSeadPatrol2( SquadronName, Zone, PatrolMinSpeed, PatrolMaxSpeed, FloorAltitude, CeilingAltitude, AltType, EngageMinSpeed, EngageMaxSpeed, FloorAltitude, CeilingAltitude, AltType ) - local DefenderSquadron = self:GetSquadron( SquadronName ) - - DefenderSquadron.SEAD = DefenderSquadron.SEAD or {} - - local SeadPatrol = DefenderSquadron.SEAD - SeadPatrol.Name = SquadronName - SeadPatrol.Zone = Zone - SeadPatrol.PatrolFloorAltitude = FloorAltitude - SeadPatrol.PatrolCeilingAltitude = CeilingAltitude - SeadPatrol.EngageFloorAltitude = FloorAltitude - SeadPatrol.EngageCeilingAltitude = CeilingAltitude - SeadPatrol.PatrolMinSpeed = PatrolMinSpeed - SeadPatrol.PatrolMaxSpeed = PatrolMaxSpeed - SeadPatrol.EngageMinSpeed = EngageMinSpeed - SeadPatrol.EngageMaxSpeed = EngageMaxSpeed - SeadPatrol.AltType = AltType - SeadPatrol.Patrol = true - - self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "SEAD" ) - - self:F( { Sead = SeadPatrol } ) end - + - --- + --- Set a squadron to engage for close air support, when a defense point is under attack. -- @param #AI_A2G_DISPATCHER self -- @param #string SquadronName The squadron name. -- @param #number EngageMinSpeed (optional, default = 50% of max speed) The minimum speed at which the CAS task can be executed. -- @param #number EngageMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the CAS task can be executed. -- @param DCS#Altitude EngageFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the engagement. -- @param DCS#Altitude EngageCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the engagement. + -- @param #number EngageAltType The altitude type when engaging, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude. -- @usage -- -- -- CAS Squadron execution. - -- A2GDispatcher:SetSquadronCas( "Mozdok", 900, 1200 ) - -- A2GDispatcher:SetSquadronCas( "Novo", 900, 2100 ) - -- A2GDispatcher:SetSquadronCas( "Maykop", 900, 1200 ) + -- A2GDispatcher:SetSquadronCas( "Mozdok", 900, 1200, 4000, 5000, "BARO" ) + -- A2GDispatcher:SetSquadronCas( "Novo", 900, 2100, 6000, 9000, "BARO" ) + -- A2GDispatcher:SetSquadronCas( "Maykop", 900, 1200, 30, 100, "RADIO" ) -- -- @return #AI_A2G_DISPATCHER - function AI_A2G_DISPATCHER:SetSquadronCas( SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude ) + function AI_A2G_DISPATCHER:SetSquadronCas2( SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) local DefenderSquadron = self:GetSquadron( SquadronName ) @@ -2212,9 +2267,32 @@ do -- AI_A2G_DISPATCHER Cas.EngageMaxSpeed = EngageMaxSpeed Cas.EngageFloorAltitude = EngageFloorAltitude or 500 Cas.EngageCeilingAltitude = EngageCeilingAltitude or 1000 + Cas.EngageAltType = EngageAltType Cas.Defend = true - self:F( { Cas = Cas } ) + self:I( { CAS = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } ) + + return self + end + + --- Set a squadron to engage for close air support, when a defense point is under attack. + -- @param #AI_A2G_DISPATCHER self + -- @param #string SquadronName The squadron name. + -- @param #number EngageMinSpeed (optional, default = 50% of max speed) The minimum speed at which the CAS task can be executed. + -- @param #number EngageMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the CAS task can be executed. + -- @param DCS#Altitude EngageFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the engagement. + -- @param DCS#Altitude EngageCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the engagement. + -- @usage + -- + -- -- CAS Squadron execution. + -- A2GDispatcher:SetSquadronCas( "Mozdok", 900, 1200, 4000, 5000 ) + -- A2GDispatcher:SetSquadronCas( "Novo", 900, 2100, 6000, 8000 ) + -- A2GDispatcher:SetSquadronCas( "Maykop", 900, 1200, 6000, 10000 ) + -- + -- @return #AI_A2G_DISPATCHER + function AI_A2G_DISPATCHER:SetSquadronCas( SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude ) + + return self:SetSquadronCas2( SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, "RADIO" ) end @@ -2236,6 +2314,53 @@ do -- AI_A2G_DISPATCHER end + --- Set a Cas patrol for a Squadron. + -- The Cas patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded. + -- @param #AI_A2G_DISPATCHER self + -- @param #string SquadronName The squadron name. + -- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed. + -- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed. + -- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed. + -- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed. + -- @param #number PatrolCeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed. + -- @param #number PatrolAltType The altitude type when patrolling, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude. + -- @param #number EngageMinSpeed (optional, default = 50% of max speed) The minimum speed at which the engage can be executed. + -- @param #number EngageMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the engage can be executed. + -- @param #number EngageFloorAltitude (optional, default = 1000m ) The minimum altitude at which the engage can be executed. + -- @param #number EngageCeilingAltitude (optional, default = 1500m ) The maximum altitude at which the engage can be executed. + -- @param #number EngageAltType The altitude type when engaging, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude. + -- @return #AI_A2G_DISPATCHER + -- @usage + -- + -- -- Cas Patrol Squadron execution. + -- PatrolZoneEast = ZONE_POLYGON:New( "Patrol Zone East", GROUP:FindByName( "Patrol Zone East" ) ) + -- A2GDispatcher:SetSquadronCasPatrol2( "Mineralnye", PatrolZoneEast, 500, 600, 4000, 10000, "BARO", 800, 900, 2000, 3000, "RADIO", ) + -- + function AI_A2G_DISPATCHER:SetSquadronCasPatrol2( SquadronName, Zone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) + + local DefenderSquadron = self:GetSquadron( SquadronName ) + + DefenderSquadron.CAS = DefenderSquadron.CAS or {} + + local CasPatrol = DefenderSquadron.CAS + CasPatrol.Name = SquadronName + CasPatrol.Zone = Zone + CasPatrol.PatrolFloorAltitude = PatrolFloorAltitude + CasPatrol.PatrolCeilingAltitude = PatrolCeilingAltitude + CasPatrol.EngageFloorAltitude = EngageFloorAltitude + CasPatrol.EngageCeilingAltitude = EngageCeilingAltitude + CasPatrol.PatrolMinSpeed = PatrolMinSpeed + CasPatrol.PatrolMaxSpeed = PatrolMaxSpeed + CasPatrol.EngageMinSpeed = EngageMinSpeed + CasPatrol.EngageMaxSpeed = EngageMaxSpeed + CasPatrol.PatrolAltType = PatrolAltType + CasPatrol.EngageAltType = EngageAltType + CasPatrol.Patrol = true + + self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "CAS" ) + + self:I( { CAS = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } ) + end --- Set a Cas patrol for a Squadron. @@ -2258,47 +2383,28 @@ do -- AI_A2G_DISPATCHER -- A2GDispatcher:SetSquadronCasPatrol( "Mineralnye", PatrolZoneEast, 4000, 10000, 500, 600, 800, 900 ) -- function AI_A2G_DISPATCHER:SetSquadronCasPatrol( SquadronName, Zone, FloorAltitude, CeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, AltType ) + + self:SetSquadronCasPatrol2( SquadronName, Zone, PatrolMinSpeed, PatrolMaxSpeed, FloorAltitude, CeilingAltitude, AltType, EngageMinSpeed, EngageMaxSpeed, FloorAltitude, CeilingAltitude, AltType ) - local DefenderSquadron = self:GetSquadron( SquadronName ) - - DefenderSquadron.CAS = DefenderSquadron.CAS or {} - - local CasPatrol = DefenderSquadron.CAS - CasPatrol.Name = SquadronName - CasPatrol.Zone = Zone - CasPatrol.PatrolFloorAltitude = FloorAltitude - CasPatrol.PatrolCeilingAltitude = CeilingAltitude - CasPatrol.EngageFloorAltitude = FloorAltitude - CasPatrol.EngageCeilingAltitude = CeilingAltitude - CasPatrol.PatrolMinSpeed = PatrolMinSpeed - CasPatrol.PatrolMaxSpeed = PatrolMaxSpeed - CasPatrol.EngageMinSpeed = EngageMinSpeed - CasPatrol.EngageMaxSpeed = EngageMaxSpeed - CasPatrol.AltType = AltType - CasPatrol.Patrol = true - - self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "CAS" ) - - self:F( { Cas = CasPatrol } ) end - - --- + --- Set a squadron to engage for a battlefield area interdiction, when a defense point is under attack. -- @param #AI_A2G_DISPATCHER self -- @param #string SquadronName The squadron name. -- @param #number EngageMinSpeed (optional, default = 50% of max speed) The minimum speed at which the BAI task can be executed. -- @param #number EngageMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the BAI task can be executed. -- @param DCS#Altitude EngageFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the engagement. -- @param DCS#Altitude EngageCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the engagement. + -- @param #number EngageAltType The altitude type when engaging, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude. -- @usage -- -- -- BAI Squadron execution. - -- A2GDispatcher:SetSquadronBai( "Mozdok", 900, 1200 ) - -- A2GDispatcher:SetSquadronBai( "Novo", 900, 2100 ) - -- A2GDispatcher:SetSquadronBai( "Maykop", 900, 1200 ) + -- A2GDispatcher:SetSquadronBai( "Mozdok", 900, 1200, 4000, 5000, "BARO" ) + -- A2GDispatcher:SetSquadronBai( "Novo", 900, 2100, 6000, 9000, "BARO" ) + -- A2GDispatcher:SetSquadronBai( "Maykop", 900, 1200, 30, 100, "RADIO" ) -- -- @return #AI_A2G_DISPATCHER - function AI_A2G_DISPATCHER:SetSquadronBai( SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude ) + function AI_A2G_DISPATCHER:SetSquadronBai2( SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) local DefenderSquadron = self:GetSquadron( SquadronName ) @@ -2310,9 +2416,32 @@ do -- AI_A2G_DISPATCHER Bai.EngageMaxSpeed = EngageMaxSpeed Bai.EngageFloorAltitude = EngageFloorAltitude or 500 Bai.EngageCeilingAltitude = EngageCeilingAltitude or 1000 + Bai.EngageAltType = EngageAltType Bai.Defend = true - self:F( { Bai = Bai } ) + self:I( { BAI = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } ) + + return self + end + + --- Set a squadron to engage for a battlefield area interdiction, when a defense point is under attack. + -- @param #AI_A2G_DISPATCHER self + -- @param #string SquadronName The squadron name. + -- @param #number EngageMinSpeed (optional, default = 50% of max speed) The minimum speed at which the BAI task can be executed. + -- @param #number EngageMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the BAI task can be executed. + -- @param DCS#Altitude EngageFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the engagement. + -- @param DCS#Altitude EngageCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the engagement. + -- @usage + -- + -- -- BAI Squadron execution. + -- A2GDispatcher:SetSquadronBai( "Mozdok", 900, 1200, 4000, 5000 ) + -- A2GDispatcher:SetSquadronBai( "Novo", 900, 2100, 6000, 8000 ) + -- A2GDispatcher:SetSquadronBai( "Maykop", 900, 1200, 6000, 10000 ) + -- + -- @return #AI_A2G_DISPATCHER + function AI_A2G_DISPATCHER:SetSquadronBai( SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude ) + + return self:SetSquadronBai2( SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, "RADIO" ) end @@ -2333,6 +2462,54 @@ do -- AI_A2G_DISPATCHER end + + --- Set a Bai patrol for a Squadron. + -- The Bai patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded. + -- @param #AI_A2G_DISPATCHER self + -- @param #string SquadronName The squadron name. + -- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed. + -- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed. + -- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed. + -- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed. + -- @param #number PatrolCeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed. + -- @param #number PatrolAltType The altitude type when patrolling, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude. + -- @param #number EngageMinSpeed (optional, default = 50% of max speed) The minimum speed at which the engage can be executed. + -- @param #number EngageMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the engage can be executed. + -- @param #number EngageFloorAltitude (optional, default = 1000m ) The minimum altitude at which the engage can be executed. + -- @param #number EngageCeilingAltitude (optional, default = 1500m ) The maximum altitude at which the engage can be executed. + -- @param #number EngageAltType The altitude type when engaging, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude. + -- @return #AI_A2G_DISPATCHER + -- @usage + -- + -- -- Bai Patrol Squadron execution. + -- PatrolZoneEast = ZONE_POLYGON:New( "Patrol Zone East", GROUP:FindByName( "Patrol Zone East" ) ) + -- A2GDispatcher:SetSquadronBaiPatrol2( "Mineralnye", PatrolZoneEast, 500, 600, 4000, 10000, "BARO", 800, 900, 2000, 3000, "RADIO", ) + -- + function AI_A2G_DISPATCHER:SetSquadronBaiPatrol2( SquadronName, Zone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) + + local DefenderSquadron = self:GetSquadron( SquadronName ) + + DefenderSquadron.BAI = DefenderSquadron.BAI or {} + + local BaiPatrol = DefenderSquadron.BAI + BaiPatrol.Name = SquadronName + BaiPatrol.Zone = Zone + BaiPatrol.PatrolFloorAltitude = PatrolFloorAltitude + BaiPatrol.PatrolCeilingAltitude = PatrolCeilingAltitude + BaiPatrol.EngageFloorAltitude = EngageFloorAltitude + BaiPatrol.EngageCeilingAltitude = EngageCeilingAltitude + BaiPatrol.PatrolMinSpeed = PatrolMinSpeed + BaiPatrol.PatrolMaxSpeed = PatrolMaxSpeed + BaiPatrol.EngageMinSpeed = EngageMinSpeed + BaiPatrol.EngageMaxSpeed = EngageMaxSpeed + BaiPatrol.PatrolAltType = PatrolAltType + BaiPatrol.EngageAltType = EngageAltType + BaiPatrol.Patrol = true + + self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "BAI" ) + + self:I( { BAI = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } ) + end --- Set a Bai patrol for a Squadron. -- The Bai patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded. @@ -2354,28 +2531,9 @@ do -- AI_A2G_DISPATCHER -- A2GDispatcher:SetSquadronBaiPatrol( "Mineralnye", PatrolZoneEast, 4000, 10000, 500, 600, 800, 900 ) -- function AI_A2G_DISPATCHER:SetSquadronBaiPatrol( SquadronName, Zone, FloorAltitude, CeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, AltType ) + + self:SetSquadronBaiPatrol2( SquadronName, Zone, PatrolMinSpeed, PatrolMaxSpeed, FloorAltitude, CeilingAltitude, AltType, EngageMinSpeed, EngageMaxSpeed, FloorAltitude, CeilingAltitude, AltType ) - local DefenderSquadron = self:GetSquadron( SquadronName ) - - DefenderSquadron.BAI = DefenderSquadron.BAI or {} - - local BaiPatrol = DefenderSquadron.BAI - BaiPatrol.Name = SquadronName - BaiPatrol.Zone = Zone - BaiPatrol.PatrolFloorAltitude = FloorAltitude - BaiPatrol.PatrolCeilingAltitude = CeilingAltitude - BaiPatrol.EngageFloorAltitude = FloorAltitude - BaiPatrol.EngageCeilingAltitude = CeilingAltitude - BaiPatrol.PatrolMinSpeed = PatrolMinSpeed - BaiPatrol.PatrolMaxSpeed = PatrolMaxSpeed - BaiPatrol.EngageMinSpeed = EngageMinSpeed - BaiPatrol.EngageMaxSpeed = EngageMaxSpeed - BaiPatrol.AltType = AltType - BaiPatrol.Patrol = true - - self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "BAI" ) - - self:F( { Bai = BaiPatrol } ) end @@ -3496,7 +3654,7 @@ do -- AI_A2G_DISPATCHER local AI_A2G_PATROL = { SEAD = AI_A2G_SEAD, BAI = AI_A2G_BAI, CAS = AI_A2G_CAS } - local AI_A2G_Fsm = AI_A2G_PATROL[DefenseTaskType]:New( DefenderGroup, Patrol.EngageMinSpeed, Patrol.EngageMaxSpeed, Patrol.EngageFloorAltitude, Patrol.EngageCeilingAltitude, Patrol.Zone, Patrol.PatrolFloorAltitude, Patrol.PatrolCeilingAltitude, Patrol.PatrolMinSpeed, Patrol.PatrolMaxSpeed, Patrol.AltType ) + local AI_A2G_Fsm = AI_A2G_PATROL[DefenseTaskType]:New2( DefenderGroup, Patrol.EngageMinSpeed, Patrol.EngageMaxSpeed, Patrol.EngageFloorAltitude, Patrol.EngageCeilingAltitude, Patrol.EngageAltType, Patrol.Zone, Patrol.PatrolFloorAltitude, Patrol.PatrolCeilingAltitude, Patrol.PatrolMinSpeed, Patrol.PatrolMaxSpeed, Patrol.PatrolAltType ) AI_A2G_Fsm:SetDispatcher( self ) AI_A2G_Fsm:SetHomeAirbase( DefenderSquadron.Airbase ) AI_A2G_Fsm:SetFuelThreshold( DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold, 60 ) @@ -3508,7 +3666,7 @@ do -- AI_A2G_DISPATCHER self:SetDefenderTask( SquadronName, DefenderGroup, DefenseTaskType, AI_A2G_Fsm, nil, DefenderGrouping ) function AI_A2G_Fsm:onafterTakeoff( DefenderGroup, From, Event, To ) - self:F({"Defender Takeoff", DefenderGroup:GetName()}) + self:F({"Takeoff", DefenderGroup:GetName()}) --self:GetParent(self).onafterBirth( self, Defender, From, Event, To ) local DefenderName = DefenderGroup:GetCallsign() -- #string @@ -3522,7 +3680,7 @@ do -- AI_A2G_DISPATCHER end function AI_A2G_Fsm:onafterPatrolRoute( DefenderGroup, From, Event, To ) - self:F({"Defender PatrolRoute", DefenderGroup:GetName()}) + self:F({"PatrolRoute", DefenderGroup:GetName()}) self:GetParent(self).onafterPatrolRoute( self, DefenderGroup, From, Event, To ) local DefenderName = DefenderGroup:GetCallsign() @@ -3544,7 +3702,7 @@ do -- AI_A2G_DISPATCHER local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup ) - if Squadron then + if Squadron and AttackSetUnit:Count() > 0 then local FirstUnit = AttackSetUnit:GetFirst() local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE @@ -3568,7 +3726,7 @@ do -- AI_A2G_DISPATCHER end function AI_A2G_Fsm:onafterRTB( DefenderGroup, From, Event, To ) - self:F({"Defender RTB", DefenderGroup:GetName()}) + self:F({"RTB", DefenderGroup:GetName()}) self:GetParent(self).onafterRTB( self, DefenderGroup, From, Event, To ) local DefenderName = DefenderGroup:GetCallsign() @@ -3581,7 +3739,7 @@ do -- AI_A2G_DISPATCHER --- @param #AI_A2G_DISPATCHER self function AI_A2G_Fsm:onafterLostControl( DefenderGroup, From, Event, To ) - self:F({"Defender LostControl", DefenderGroup:GetName()}) + self:F({"LostControl", DefenderGroup:GetName()}) self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To ) local DefenderName = DefenderGroup:GetCallsign() @@ -3596,7 +3754,7 @@ do -- AI_A2G_DISPATCHER --- @param #AI_A2G_DISPATCHER self function AI_A2G_Fsm:onafterHome( DefenderGroup, From, Event, To, Action ) - self:F({"Defender Home", DefenderGroup:GetName()}) + self:F({"Home", DefenderGroup:GetName()}) self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To ) local DefenderName = DefenderGroup:GetCallsign() @@ -3635,9 +3793,9 @@ do -- AI_A2G_DISPATCHER if DefenderGroup then - local AI_A2G = { SEAD = AI_A2G_SEAD, BAI = AI_A2G_BAI, CAS = AI_A2G_CAS } + local AI_A2G_ENGAGE = { SEAD = AI_A2G_SEAD, BAI = AI_A2G_BAI, CAS = AI_A2G_CAS } - local AI_A2G_Fsm = AI_A2G[DefenseTaskType]:New( DefenderGroup, Defense.EngageMinSpeed, Defense.EngageMaxSpeed, Defense.EngageFloorAltitude, Defense.EngageCeilingAltitude ) -- AI.AI_A2G_ENGAGE + local AI_A2G_Fsm = AI_A2G_ENGAGE[DefenseTaskType]:New( DefenderGroup, Defense.EngageMinSpeed, Defense.EngageMaxSpeed, Defense.EngageFloorAltitude, Defense.EngageCeilingAltitude, Defense.EngageAltType ) -- AI.AI_AIR_ENGAGE AI_A2G_Fsm:SetDispatcher( self ) AI_A2G_Fsm:SetHomeAirbase( DefenderSquadron.Airbase ) AI_A2G_Fsm:SetFuelThreshold( DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold, 60 ) diff --git a/Moose Development/Moose/AI/AI_A2G_SEAD.lua b/Moose Development/Moose/AI/AI_A2G_SEAD.lua index cd2883772..b72080558 100644 --- a/Moose Development/Moose/AI/AI_A2G_SEAD.lua +++ b/Moose Development/Moose/AI/AI_A2G_SEAD.lua @@ -14,7 +14,7 @@ --- @type AI_A2G_SEAD --- @extends AI.AI_A2G_Patrol#AI_A2G_PATROL +-- @extends AI.AI_A2G_Patrol#AI_AIR_PATROL --- Implements the core functions to SEAD intruders. Use the Engage trigger to intercept intruders. @@ -85,6 +85,7 @@ AI_A2G_SEAD = { -- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target. -- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement. -- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement. +-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO". -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. -- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. -- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. @@ -92,10 +93,12 @@ AI_A2G_SEAD = { -- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. -- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO -- @return #AI_A2G_SEAD -function AI_A2G_SEAD:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) +function AI_A2G_SEAD:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) - -- Inherits from BASE - local self = BASE:Inherit( self, AI_A2G_PATROL:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_A2G_SEAD + local AI_Air = AI_AIR:New( AIGroup ) + local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL + local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) + local self = BASE:Inherit( self, AI_Air_Engage ) local RTBSpeedMax = AIGroup:GetSpeedMax() or 9999 @@ -105,116 +108,49 @@ function AI_A2G_SEAD:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAl end +--- Creates a new AI_A2G_SEAD object +-- @param #AI_A2G_SEAD self +-- @param Wrapper.Group#GROUP AIGroup +-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target. +-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement. +-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement. +-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. +-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol. +-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol. +-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h. +-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h. +-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO +-- @return #AI_A2G_SEAD +function AI_A2G_SEAD:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ---- @param #AI_A2G_SEAD self --- @param Wrapper.Group#GROUP DefenderGroup The GroupGroup managed by the FSM. --- @param #string From The From State string. --- @param #string Event The Event string. --- @param #string To The To State string. -function AI_A2G_SEAD:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit ) - - self:F( { DefenderGroup, From, Event, To, AttackSetUnit} ) - - local DefenderGroupName = DefenderGroup:GetName() - - self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air! - - local AttackCount = AttackSetUnit:Count() - - if AttackCount > 0 then - - if DefenderGroup:IsAlive() then - - -- Determine the distance to the target. - -- If it is less than 50km, then attack without a route. - -- Otherwise perform a route attack. - - local EngageAltitude = math.random( self.EngageFloorAltitude or 500, self.EngageCeilingAltitude or 1000 ) - local EngageSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed ) - - local DefenderCoord = DefenderGroup:GetPointVec3() - DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude. - - local TargetCoord = AttackSetUnit:GetFirst():GetPointVec3() - TargetCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude. - - local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord ) - local EngageDistance = ( DefenderGroup:IsHelicopter() and 5000 ) or ( DefenderGroup:IsAirPlane() and 25000 ) - - local EngageRoute = {} - local AttackTasks = {} - - local FromWP = DefenderCoord:WaypointAir( - self.PatrolAltType or "RADIO", - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - EngageSpeed, - false - ) - EngageRoute[#EngageRoute+1] = FromWP - - self:SetTargetDistance( TargetCoord ) -- For RTB status check - - local FromEngageAngle = DefenderCoord:GetAngleDegrees( DefenderCoord:GetDirectionVec3( TargetCoord ) ) - local ToWP = DefenderCoord:Translate( EngageDistance, FromEngageAngle, true ):WaypointAir( - self.PatrolAltType or "RADIO", - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - EngageSpeed, - true - ) - EngageRoute[#EngageRoute+1] = ToWP - - if TargetDistance <= EngageDistance * 3 then - - local AttackUnitTasks = {} - - local AttackSetUnitPerThreatLevel = AttackSetUnit:GetSetPerThreatLevel( 10, 0 ) - for AttackUnitID, AttackUnit in ipairs( AttackSetUnitPerThreatLevel ) do - if AttackUnit then - if AttackUnit:IsAlive() and AttackUnit:IsGround() then - local HasRadar = AttackUnit:HasSEAD() - if HasRadar then - self:F( { "SEAD Unit:", AttackUnit:GetName() } ) - AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, true, false, nil, nil, EngageAltitude ) - end - end - end - end - - if #AttackUnitTasks == 0 then - self:I( DefenderGroupName .. ": No targets found -> Going RTB") - self:Return() - self:__RTB( self.TaskDelay ) - else - DefenderGroup:OptionROEOpenFire() - DefenderGroup:OptionROTVertical() - DefenderGroup:OptionKeepWeaponsOnThreat() - --DefenderGroup:OptionRTBAmmo( Weapon.flag.AnyASM ) - - AttackTasks[#AttackTasks+1] = DefenderGroup:TaskCombo( AttackUnitTasks ) - end - end - - AttackTasks[#AttackTasks+1] = DefenderGroup:TaskFunction( "AI_A2G_ENGAGE.___Engage", self, AttackSetUnit ) - EngageRoute[#EngageRoute].task = DefenderGroup:TaskCombo( AttackTasks ) - - DefenderGroup:Route( EngageRoute, self.TaskDelay ) - end - else - self:I( DefenderGroupName .. ": No targets found -> Going RTB") - self:Return() - self:__RTB( self.TaskDelay ) - end + return self:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) end ---- @param Wrapper.Group#GROUP AIEngage -function AI_A2G_SEAD.Resume( AIEngage, Fsm ) - AIEngage:F( { "AI_A2G_SEAD.Resume:", AIEngage:GetName() } ) - if AIEngage:IsAlive() then - Fsm:__Reset( Fsm.TaskDelay ) - Fsm:__EngageRoute( Fsm.TaskDelay, Fsm.AttackSetUnit ) +--- Evaluate the attack and create an AttackUnitTask list. +-- @param #AI_A2G_SEAD self +-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack. +-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders. +-- @param #number EngageAltitude The altitude to engage the targets. +-- @return #AI_A2G_SEAD self +function AI_A2G_SEAD:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude ) + + local AttackUnitTasks = {} + + local AttackSetUnitPerThreatLevel = AttackSetUnit:GetSetPerThreatLevel( 10, 0 ) + for AttackUnitID, AttackUnit in ipairs( AttackSetUnitPerThreatLevel ) do + if AttackUnit then + if AttackUnit:IsAlive() and AttackUnit:IsGround() then + local HasRadar = AttackUnit:HasSEAD() + if HasRadar then + self:F( { "SEAD Unit:", AttackUnit:GetName() } ) + AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, true, false, nil, nil, EngageAltitude ) + end + end + end end -end \ No newline at end of file + return AttackUnitTasks +end + diff --git a/Moose Development/Moose/AI/AI_Air_Dispatcher.lua b/Moose Development/Moose/AI/AI_Air_Dispatcher.lua index ac912f819..23531f689 100644 --- a/Moose Development/Moose/AI/AI_Air_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Air_Dispatcher.lua @@ -2577,7 +2577,7 @@ do -- AI_AIR_DISPATCHER local AI_A2G = { SEAD = AI_A2G_SEAD, BAI = AI_A2G_BAI, CAS = AI_A2G_CAS } - local Fsm = AI_A2G[DefenseTaskType]:New( DefenderGroup, Defense.EngageMinSpeed, Defense.EngageMaxSpeed, Defense.EngageFloorAltitude, Defense.EngageCeilingAltitude ) -- AI.AI_A2G_ENGAGE + local Fsm = AI_A2G[DefenseTaskType]:New( DefenderGroup, Defense.EngageMinSpeed, Defense.EngageMaxSpeed, Defense.EngageFloorAltitude, Defense.EngageCeilingAltitude ) -- AI.AI_AIR_ENGAGE Fsm:SetDispatcher( self ) Fsm:SetHomeAirbase( DefenderSquadron.Airbase ) Fsm:SetFuelThreshold( DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold, 60 ) diff --git a/Moose Development/Moose/AI/AI_A2G_Engage.lua b/Moose Development/Moose/AI/AI_Air_Engage.lua similarity index 64% rename from Moose Development/Moose/AI/AI_A2G_Engage.lua rename to Moose Development/Moose/AI/AI_Air_Engage.lua index f74f82f80..a14d604aa 100644 --- a/Moose Development/Moose/AI/AI_A2G_Engage.lua +++ b/Moose Development/Moose/AI/AI_Air_Engage.lua @@ -8,20 +8,20 @@ -- -- === -- --- @module AI.AI_A2G_Engage +-- @module AI.AI_Air_Engage -- @image AI_Air_To_Ground_Engage.JPG ---- @type AI_A2G_ENGAGE --- @extends AI.AI_A2G#AI_A2G +--- @type AI_AIR_ENGAGE +-- @extends AI.AI_AIR#AI_AIR --- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders. -- -- ![Process](..\Presentations\AI_GCI\Dia3.JPG) -- --- The AI_A2G_ENGAGE is assigned a @{Wrapper.Group} and this must be done before the AI_A2G_ENGAGE process can be started using the **Start** event. +-- The AI_AIR_ENGAGE is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_ENGAGE process can be started using the **Start** event. -- -- ![Process](..\Presentations\AI_GCI\Dia4.JPG) -- @@ -47,9 +47,9 @@ -- -- ![Process](..\Presentations\AI_GCI\Dia13.JPG) -- --- ## 1. AI_A2G_ENGAGE constructor +-- ## 1. AI_AIR_ENGAGE constructor -- --- * @{#AI_A2G_ENGAGE.New}(): Creates a new AI_A2G_ENGAGE object. +-- * @{#AI_AIR_ENGAGE.New}(): Creates a new AI_AIR_ENGAGE object. -- -- ## 3. Set the Range of Engagement -- @@ -59,7 +59,7 @@ -- that will define when the AI will engage with the detected airborne enemy targets. -- The range can be beyond or smaller than the range of the Patrol Zone. -- The range is applied at the position of the AI. --- Use the method @{AI.AI_GCI#AI_A2G_ENGAGE.SetEngageRange}() to define that range. +-- Use the method @{AI.AI_GCI#AI_AIR_ENGAGE.SetEngageRange}() to define that range. -- -- ## 4. Set the Zone of Engagement -- @@ -67,29 +67,30 @@ -- -- An optional @{Zone} can be set, -- that will define when the AI will engage with the detected airborne enemy targets. --- Use the method @{AI.AI_Cap#AI_A2G_ENGAGE.SetEngageZone}() to define that Zone. +-- Use the method @{AI.AI_Cap#AI_AIR_ENGAGE.SetEngageZone}() to define that Zone. -- -- === -- --- @field #AI_A2G_ENGAGE -AI_A2G_ENGAGE = { - ClassName = "AI_A2G_ENGAGE", +-- @field #AI_AIR_ENGAGE +AI_AIR_ENGAGE = { + ClassName = "AI_AIR_ENGAGE", } ---- Creates a new AI_A2G_ENGAGE object --- @param #AI_A2G_ENGAGE self +--- Creates a new AI_AIR_ENGAGE object +-- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup -- @param DCS#Speed EngageMinSpeed (optional, default = 50% of max speed) The minimum speed of the @{Wrapper.Group} in km/h when engaging a target. -- @param DCS#Speed EngageMaxSpeed (optional, default = 75% of max speed) The maximum speed of the @{Wrapper.Group} in km/h when engaging a target. -- @param DCS#Altitude EngageFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the engagement. -- @param DCS#Altitude EngageCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the engagement. --- @return #AI_A2G_ENGAGE -function AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude ) +-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO". +-- @return #AI_AIR_ENGAGE +function AI_AIR_ENGAGE:New( AI_Air, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType ) -- Inherits from BASE - local self = BASE:Inherit( self, AI_A2G:New( AIGroup ) ) -- #AI_A2G_ENGAGE + local self = BASE:Inherit( self, AI_Air ) -- #AI_AIR_ENGAGE self.Accomplished = false self.Engaging = false @@ -100,12 +101,13 @@ function AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor self.EngageMaxSpeed = EngageMaxSpeed or SpeedMax * 0.75 self.EngageFloorAltitude = EngageFloorAltitude or 1000 self.EngageCeilingAltitude = EngageCeilingAltitude or 1500 + self.EngageAltType = EngageAltType or "RADIO" - self:AddTransition( { "Started", "Engaging", "Returning", "Airborne", "Patrolling" }, "EngageRoute", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2G_ENGAGE. + self:AddTransition( { "Started", "Engaging", "Returning", "Airborne", "Patrolling" }, "EngageRoute", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_ENGAGE. --- OnBefore Transition Handler for Event EngageRoute. - -- @function [parent=#AI_A2G_ENGAGE] OnBeforeEngageRoute - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] OnBeforeEngageRoute + -- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -113,25 +115,25 @@ function AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor -- @return #boolean Return false to cancel Transition. --- OnAfter Transition Handler for Event EngageRoute. - -- @function [parent=#AI_A2G_ENGAGE] OnAfterEngageRoute - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] OnAfterEngageRoute + -- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. --- Synchronous Event Trigger for Event EngageRoute. - -- @function [parent=#AI_A2G_ENGAGE] EngageRoute - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] EngageRoute + -- @param #AI_AIR_ENGAGE self --- Asynchronous Event Trigger for Event EngageRoute. - -- @function [parent=#AI_A2G_ENGAGE] __EngageRoute - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] __EngageRoute + -- @param #AI_AIR_ENGAGE self -- @param #number Delay The delay in seconds. --- OnLeave Transition Handler for State Engaging. --- @function [parent=#AI_A2G_ENGAGE] OnLeaveEngaging --- @param #AI_A2G_ENGAGE self +-- @function [parent=#AI_AIR_ENGAGE] OnLeaveEngaging +-- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -139,18 +141,18 @@ function AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor -- @return #boolean Return false to cancel Transition. --- OnEnter Transition Handler for State Engaging. --- @function [parent=#AI_A2G_ENGAGE] OnEnterEngaging --- @param #AI_A2G_ENGAGE self +-- @function [parent=#AI_AIR_ENGAGE] OnEnterEngaging +-- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. - self:AddTransition( { "Started", "Engaging", "Returning", "Airborne", "Patrolling" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2G_ENGAGE. + self:AddTransition( { "Started", "Engaging", "Returning", "Airborne", "Patrolling" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_ENGAGE. --- OnBefore Transition Handler for Event Engage. - -- @function [parent=#AI_A2G_ENGAGE] OnBeforeEngage - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] OnBeforeEngage + -- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -158,25 +160,25 @@ function AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor -- @return #boolean Return false to cancel Transition. --- OnAfter Transition Handler for Event Engage. - -- @function [parent=#AI_A2G_ENGAGE] OnAfterEngage - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] OnAfterEngage + -- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. --- Synchronous Event Trigger for Event Engage. - -- @function [parent=#AI_A2G_ENGAGE] Engage - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] Engage + -- @param #AI_AIR_ENGAGE self --- Asynchronous Event Trigger for Event Engage. - -- @function [parent=#AI_A2G_ENGAGE] __Engage - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] __Engage + -- @param #AI_AIR_ENGAGE self -- @param #number Delay The delay in seconds. --- OnLeave Transition Handler for State Engaging. --- @function [parent=#AI_A2G_ENGAGE] OnLeaveEngaging --- @param #AI_A2G_ENGAGE self +-- @function [parent=#AI_AIR_ENGAGE] OnLeaveEngaging +-- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -184,18 +186,18 @@ function AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor -- @return #boolean Return false to cancel Transition. --- OnEnter Transition Handler for State Engaging. --- @function [parent=#AI_A2G_ENGAGE] OnEnterEngaging --- @param #AI_A2G_ENGAGE self +-- @function [parent=#AI_AIR_ENGAGE] OnEnterEngaging +-- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. - self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2G_ENGAGE. + self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_ENGAGE. --- OnBefore Transition Handler for Event Fired. - -- @function [parent=#AI_A2G_ENGAGE] OnBeforeFired - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] OnBeforeFired + -- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -203,27 +205,27 @@ function AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor -- @return #boolean Return false to cancel Transition. --- OnAfter Transition Handler for Event Fired. - -- @function [parent=#AI_A2G_ENGAGE] OnAfterFired - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] OnAfterFired + -- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. --- Synchronous Event Trigger for Event Fired. - -- @function [parent=#AI_A2G_ENGAGE] Fired - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] Fired + -- @param #AI_AIR_ENGAGE self --- Asynchronous Event Trigger for Event Fired. - -- @function [parent=#AI_A2G_ENGAGE] __Fired - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] __Fired + -- @param #AI_AIR_ENGAGE self -- @param #number Delay The delay in seconds. - self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_A2G_ENGAGE. + self:AddTransition( "*", "Destroy", "*" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_ENGAGE. --- OnBefore Transition Handler for Event Destroy. - -- @function [parent=#AI_A2G_ENGAGE] OnBeforeDestroy - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] OnBeforeDestroy + -- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -231,28 +233,28 @@ function AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor -- @return #boolean Return false to cancel Transition. --- OnAfter Transition Handler for Event Destroy. - -- @function [parent=#AI_A2G_ENGAGE] OnAfterDestroy - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] OnAfterDestroy + -- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. --- Synchronous Event Trigger for Event Destroy. - -- @function [parent=#AI_A2G_ENGAGE] Destroy - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] Destroy + -- @param #AI_AIR_ENGAGE self --- Asynchronous Event Trigger for Event Destroy. - -- @function [parent=#AI_A2G_ENGAGE] __Destroy - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] __Destroy + -- @param #AI_AIR_ENGAGE self -- @param #number Delay The delay in seconds. - self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2G_ENGAGE. + self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_ENGAGE. --- OnBefore Transition Handler for Event Abort. - -- @function [parent=#AI_A2G_ENGAGE] OnBeforeAbort - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] OnBeforeAbort + -- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -260,27 +262,27 @@ function AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor -- @return #boolean Return false to cancel Transition. --- OnAfter Transition Handler for Event Abort. - -- @function [parent=#AI_A2G_ENGAGE] OnAfterAbort - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] OnAfterAbort + -- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. --- Synchronous Event Trigger for Event Abort. - -- @function [parent=#AI_A2G_ENGAGE] Abort - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] Abort + -- @param #AI_AIR_ENGAGE self --- Asynchronous Event Trigger for Event Abort. - -- @function [parent=#AI_A2G_ENGAGE] __Abort - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] __Abort + -- @param #AI_AIR_ENGAGE self -- @param #number Delay The delay in seconds. - self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2G_ENGAGE. + self:AddTransition( "Engaging", "Accomplish", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_ENGAGE. --- OnBefore Transition Handler for Event Accomplish. - -- @function [parent=#AI_A2G_ENGAGE] OnBeforeAccomplish - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] OnBeforeAccomplish + -- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -288,20 +290,20 @@ function AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor -- @return #boolean Return false to cancel Transition. --- OnAfter Transition Handler for Event Accomplish. - -- @function [parent=#AI_A2G_ENGAGE] OnAfterAccomplish - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] OnAfterAccomplish + -- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. --- Synchronous Event Trigger for Event Accomplish. - -- @function [parent=#AI_A2G_ENGAGE] Accomplish - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] Accomplish + -- @param #AI_AIR_ENGAGE self --- Asynchronous Event Trigger for Event Accomplish. - -- @function [parent=#AI_A2G_ENGAGE] __Accomplish - -- @param #AI_A2G_ENGAGE self + -- @function [parent=#AI_AIR_ENGAGE] __Accomplish + -- @param #AI_AIR_ENGAGE self -- @param #number Delay The delay in seconds. self:AddTransition( { "Patrolling", "Engaging" }, "Refuel", "Refuelling" ) @@ -310,14 +312,14 @@ function AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor end --- onafter event handler for Start event. --- @param #AI_A2G_ENGAGE self +-- @param #AI_AIR_ENGAGE 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_A2G_ENGAGE:onafterStart( AIGroup, From, Event, To ) +function AI_AIR_ENGAGE:onafterStart( AIGroup, From, Event, To ) - self:GetParent( self, AI_A2G_ENGAGE ).onafterStart( self, AIGroup, From, Event, To ) + self:GetParent( self, AI_AIR_ENGAGE ).onafterStart( self, AIGroup, From, Event, To ) AIGroup:HandleEvent( EVENTS.Takeoff, nil, self ) @@ -326,12 +328,12 @@ end --- onafter event handler for Engage event. --- @param #AI_A2G_ENGAGE self +-- @param #AI_AIR_ENGAGE 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_A2G_ENGAGE:onafterEngage( AIGroup, From, Event, To ) +function AI_AIR_ENGAGE:onafterEngage( AIGroup, From, Event, To ) self:HandleEvent( EVENTS.Dead ) @@ -339,39 +341,14 @@ end -- todo: need to fix this global function ---- @param Wrapper.Group#GROUP AIControllable -function AI_A2G_ENGAGE.___EngageRoute( AIGroup, Fsm, AttackSetUnit ) - - AIGroup:I( { "AI_A2G_ENGAGE.___EngageRoute:", AIGroup:GetName() } ) - - if AIGroup:IsAlive() then - Fsm:__EngageRoute( Fsm.TaskDelay, AttackSetUnit ) - - --local Task = AIGroup:TaskOrbitCircle( 4000, 400 ) - --AIGroup:SetTask( Task ) - end -end - ---- @param Wrapper.Group#GROUP AIControllable -function AI_A2G_ENGAGE.___Engage( AIGroup, Fsm, AttackSetUnit ) - - AIGroup:I( { "AI_A2G_ENGAGE.___Engage:", AIGroup:GetName() } ) - - if AIGroup:IsAlive() then - Fsm:__Engage( Fsm.TaskDelay, AttackSetUnit ) - - --local Task = AIGroup:TaskOrbitCircle( 4000, 400 ) - --AIGroup:SetTask( Task ) - end -end --- onbefore event handler for Engage event. --- @param #AI_A2G_ENGAGE self +-- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. -function AI_A2G_ENGAGE:onbeforeEngage( AIGroup, From, Event, To ) +function AI_AIR_ENGAGE:onbeforeEngage( AIGroup, From, Event, To ) if self.Accomplished == true then return false @@ -379,44 +356,44 @@ function AI_A2G_ENGAGE:onbeforeEngage( AIGroup, From, Event, To ) end --- onafter event handler for Abort event. --- @param #AI_A2G_ENGAGE self +-- @param #AI_AIR_ENGAGE 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_A2G_ENGAGE:onafterAbort( AIGroup, From, Event, To ) +function AI_AIR_ENGAGE:onafterAbort( AIGroup, From, Event, To ) AIGroup:ClearTasks() self:Return() self:__RTB( self.TaskDelay ) end ---- @param #AI_A2G_ENGAGE self +--- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. -function AI_A2G_ENGAGE:onafterAccomplish( AIGroup, From, Event, To ) +function AI_AIR_ENGAGE:onafterAccomplish( AIGroup, From, Event, To ) self.Accomplished = true self:SetDetectionOff() end ---- @param #AI_A2G_ENGAGE self +--- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. -- @param Core.Event#EVENTDATA EventData -function AI_A2G_ENGAGE:onafterDestroy( AIGroup, From, Event, To, EventData ) +function AI_AIR_ENGAGE:onafterDestroy( AIGroup, From, Event, To, EventData ) if EventData.IniUnit then self.AttackUnits[EventData.IniUnit] = nil end end ---- @param #AI_A2G_ENGAGE self +--- @param #AI_AIR_ENGAGE self -- @param Core.Event#EVENTDATA EventData -function AI_A2G_ENGAGE:OnEventDead( EventData ) +function AI_AIR_ENGAGE:OnEventDead( EventData ) self:F( { "EventDead", EventData } ) if EventData.IniDCSUnit then @@ -426,14 +403,29 @@ function AI_A2G_ENGAGE:OnEventDead( EventData ) end end ---- @param #AI_A2G_ENGAGE self + +--- @param Wrapper.Group#GROUP AIControllable +function AI_AIR_ENGAGE.___EngageRoute( AIGroup, Fsm, AttackSetUnit ) + + Fsm:I( { "AI_AIR_ENGAGE.___EngageRoute:", AIGroup:GetName() } ) + + if AIGroup:IsAlive() then + Fsm:__EngageRoute( Fsm.TaskDelay, AttackSetUnit ) + + --local Task = AIGroup:TaskOrbitCircle( 4000, 400 ) + --AIGroup:SetTask( Task ) + end +end + + +--- @param #AI_AIR_ENGAGE self -- @param Wrapper.Group#GROUP DefenderGroup The GroupGroup managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. -function AI_A2G_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, AttackSetUnit ) +function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, AttackSetUnit ) - self:F( { DefenderGroup, From, Event, To, AttackSetUnit} ) + self:I( { DefenderGroup, From, Event, To, AttackSetUnit } ) local DefenderGroupName = DefenderGroup:GetName() @@ -495,7 +487,7 @@ function AI_A2G_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac EngageRoute[#EngageRoute+1] = ToWP - AttackTasks[#AttackTasks+1] = DefenderGroup:TaskFunction( "AI_A2G_ENGAGE.___EngageRoute", self, AttackSetUnit ) + AttackTasks[#AttackTasks+1] = DefenderGroup:TaskFunction( "AI_AIR_ENGAGE.___EngageRoute", self, AttackSetUnit ) EngageRoute[#EngageRoute].task = DefenderGroup:TaskCombo( AttackTasks ) DefenderGroup:OptionROEReturnFire() @@ -512,3 +504,113 @@ function AI_A2G_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac end end + +--- @param Wrapper.Group#GROUP AIControllable +function AI_AIR_ENGAGE.___Engage( AIGroup, Fsm, AttackSetUnit ) + + Fsm:I( { "AI_AIR_ENGAGE.___Engage:", AIGroup:GetName() } ) + + if AIGroup:IsAlive() then + Fsm:__Engage( Fsm.TaskDelay, AttackSetUnit ) + end +end + + +--- @param #AI_AIR_ENGAGE self +-- @param Wrapper.Group#GROUP DefenderGroup The GroupGroup 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_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit ) + + self:F( { DefenderGroup, From, Event, To, AttackSetUnit} ) + + local DefenderGroupName = DefenderGroup:GetName() + + self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air! + + local AttackCount = AttackSetUnit:Count() + self:I({AttackCount = AttackCount}) + + if AttackCount > 0 then + + if DefenderGroup:IsAlive() then + + local EngageAltitude = math.random( self.EngageFloorAltitude or 500, self.EngageCeilingAltitude or 1000 ) + local EngageSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed ) + + local DefenderCoord = DefenderGroup:GetPointVec3() + DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude. + + local TargetCoord = AttackSetUnit:GetFirst():GetPointVec3() + TargetCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude. + + local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord ) + local EngageDistance = ( DefenderGroup:IsHelicopter() and 5000 ) or ( DefenderGroup:IsAirPlane() and 10000 ) + + local EngageRoute = {} + local AttackTasks = {} + + local FromWP = DefenderCoord:WaypointAir( + self.EngageAltType or "RADIO", + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + EngageSpeed, + true + ) + EngageRoute[#EngageRoute+1] = FromWP + + self:SetTargetDistance( TargetCoord ) -- For RTB status check + + local FromEngageAngle = DefenderCoord:GetAngleDegrees( DefenderCoord:GetDirectionVec3( TargetCoord ) ) + local ToWP = DefenderCoord:Translate( EngageDistance, FromEngageAngle, true ):WaypointAir( + self.EngageAltType or "RADIO", + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + EngageSpeed, + true + ) + EngageRoute[#EngageRoute+1] = ToWP + + if TargetDistance <= EngageDistance * 3 then + + local AttackUnitTasks = self:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude ) + + if #AttackUnitTasks == 0 then + self:I( DefenderGroupName .. ": No targets found -> Going RTB") + self:Return() + self:__RTB( self.TaskDelay ) + return + else + DefenderGroup:OptionROEOpenFire() + DefenderGroup:OptionROTEvadeFire() + DefenderGroup:OptionKeepWeaponsOnThreat() + + AttackTasks[#AttackTasks+1] = DefenderGroup:TaskCombo( AttackUnitTasks ) + end + end + + AttackTasks[#AttackTasks+1] = DefenderGroup:TaskFunction( "AI_AIR_ENGAGE.___Engage", self, AttackSetUnit ) + EngageRoute[#EngageRoute].task = DefenderGroup:TaskCombo( AttackTasks ) + + DefenderGroup:Route( EngageRoute, self.TaskDelay ) + + end + else + self:I( DefenderGroupName .. ": No targets found -> Going RTB") + self:Return() + self:__RTB( self.TaskDelay ) + return + end +end + +--- @param Wrapper.Group#GROUP AIEngage +function AI_AIR_ENGAGE.Resume( AIEngage, Fsm ) + + AIEngage:F( { "Resume:", AIEngage:GetName() } ) + if AIEngage:IsAlive() then + Fsm:__Reset( Fsm.TaskDelay ) + Fsm:__EngageRoute( Fsm.TaskDelay, Fsm.AttackSetUnit ) + end + +end diff --git a/Moose Development/Moose/AI/AI_A2G_Patrol.lua b/Moose Development/Moose/AI/AI_Air_Patrol.lua similarity index 56% rename from Moose Development/Moose/AI/AI_A2G_Patrol.lua rename to Moose Development/Moose/AI/AI_Air_Patrol.lua index 68e1954ca..53e439f8a 100644 --- a/Moose Development/Moose/AI/AI_A2G_Patrol.lua +++ b/Moose Development/Moose/AI/AI_Air_Patrol.lua @@ -6,19 +6,19 @@ -- -- === -- --- @module AI.AI_A2G_Patrol +-- @module AI.AI_Air_Patrol -- @image AI_Air_To_Ground_Patrol.JPG ---- @type AI_A2G_PATROL --- @extends AI.AI_A2G_Engage#AI_A2G_ENGAGE +--- @type AI_AIR_PATROL +-- @extends AI.AI_Air#AI_AIR ---- The AI_A2G_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group} +--- The AI_AIR_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group} -- and automatically engage any airborne enemies that are within a certain range or within a certain zone. -- -- ![Process](..\Presentations\AI_CAP\Dia3.JPG) -- --- The AI_A2G_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_A2G_PATROL process can be started using the **Start** event. +-- The AI_AIR_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_PATROL process can be started using the **Start** event. -- -- ![Process](..\Presentations\AI_CAP\Dia4.JPG) -- @@ -44,32 +44,32 @@ -- -- ![Process](..\Presentations\AI_CAP\Dia13.JPG) -- --- ## 1. AI_A2G_PATROL constructor +-- ## 1. AI_AIR_PATROL constructor -- --- * @{#AI_A2G_PATROL.New}(): Creates a new AI_A2G_PATROL object. +-- * @{#AI_AIR_PATROL.New}(): Creates a new AI_AIR_PATROL object. -- --- ## 2. AI_A2G_PATROL is a FSM +-- ## 2. AI_AIR_PATROL is a FSM -- -- ![Process](..\Presentations\AI_CAP\Dia2.JPG) -- --- ### 2.1 AI_A2G_PATROL States +-- ### 2.1 AI_AIR_PATROL States -- -- * **None** ( Group ): The process is not started yet. -- * **Patrolling** ( Group ): The AI is patrolling the Patrol Zone. -- * **Engaging** ( Group ): The AI is engaging the bogeys. -- * **Returning** ( Group ): The AI is returning to Base.. -- --- ### 2.2 AI_A2G_PATROL Events +-- ### 2.2 AI_AIR_PATROL Events -- -- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process. -- * **@{AI.AI_Patrol#AI_PATROL_ZONE.PatrolRoute}**: Route the AI to a new random 3D point within the Patrol Zone. --- * **@{#AI_A2G_PATROL.Engage}**: Let the AI engage the bogeys. --- * **@{#AI_A2G_PATROL.Abort}**: Aborts the engagement and return patrolling in the patrol zone. +-- * **@{#AI_AIR_PATROL.Engage}**: Let the AI engage the bogeys. +-- * **@{#AI_AIR_PATROL.Abort}**: Aborts the engagement and return patrolling in the patrol zone. -- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base. -- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets. -- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets. --- * **@{#AI_A2G_PATROL.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}. --- * **@{#AI_A2G_PATROL.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task. +-- * **@{#AI_AIR_PATROL.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}. +-- * **@{#AI_AIR_PATROL.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task. -- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB. -- -- ## 3. Set the Range of Engagement @@ -80,7 +80,7 @@ -- that will define when the AI will engage with the detected airborne enemy targets. -- The range can be beyond or smaller than the range of the Patrol Zone. -- The range is applied at the position of the AI. --- Use the method @{AI.AI_CAP#AI_A2G_PATROL.SetEngageRange}() to define that range. +-- Use the method @{AI.AI_CAP#AI_AIR_PATROL.SetEngageRange}() to define that range. -- -- ## 4. Set the Zone of Engagement -- @@ -88,33 +88,29 @@ -- -- An optional @{Zone} can be set, -- that will define when the AI will engage with the detected airborne enemy targets. --- Use the method @{AI.AI_Cap#AI_A2G_PATROL.SetEngageZone}() to define that Zone. +-- Use the method @{AI.AI_Cap#AI_AIR_PATROL.SetEngageZone}() to define that Zone. -- -- === -- --- @field #AI_A2G_PATROL -AI_A2G_PATROL = { - ClassName = "AI_A2G_PATROL", +-- @field #AI_AIR_PATROL +AI_AIR_PATROL = { + ClassName = "AI_AIR_PATROL", } ---- Creates a new AI_A2G_PATROL object --- @param #AI_A2G_PATROL self +--- Creates a new AI_AIR_PATROL object +-- @param #AI_AIR_PATROL self -- @param Wrapper.Group#GROUP AIGroup --- @param DCS#Speed EngageMinSpeed (optional, default = 50% of max speed) The minimum speed of the @{Wrapper.Group} in km/h when engaging a target. --- @param DCS#Speed EngageMaxSpeed (optional, default = 75% of max speed) The maximum speed of the @{Wrapper.Group} in km/h when engaging a target. --- @param DCS#Altitude EngageFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the engagement. --- @param DCS#Altitude EngageCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the engagement. -- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed. -- @param DCS#Altitude PatrolFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the patrol. -- @param DCS#Altitude PatrolCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the patrol. -- @param DCS#Speed PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed of the @{Wrapper.Group} in km/h. -- @param DCS#Speed PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed of the @{Wrapper.Group} in km/h. -- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO. --- @return #AI_A2G_PATROL -function AI_A2G_PATROL:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) +-- @return #AI_AIR_PATROL +function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- Inherits from BASE - local self = BASE:Inherit( self, AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude ) ) -- #AI_A2G_PATROL + local self = BASE:Inherit( self, AI_Air ) -- #AI_AIR_PATROL local SpeedMax = AIGroup:GetSpeedMax() @@ -131,8 +127,8 @@ function AI_A2G_PATROL:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor self:AddTransition( { "Started", "Airborne", "Refuelling" }, "Patrol", "Patrolling" ) --- OnBefore Transition Handler for Event Patrol. - -- @function [parent=#AI_A2G_PATROL] OnBeforePatrol - -- @param #AI_A2G_PATROL self + -- @function [parent=#AI_AIR_PATROL] OnBeforePatrol + -- @param #AI_AIR_PATROL self -- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -140,25 +136,25 @@ function AI_A2G_PATROL:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor -- @return #boolean Return false to cancel Transition. --- OnAfter Transition Handler for Event Patrol. - -- @function [parent=#AI_A2G_PATROL] OnAfterPatrol - -- @param #AI_A2G_PATROL self + -- @function [parent=#AI_AIR_PATROL] OnAfterPatrol + -- @param #AI_AIR_PATROL self -- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. --- Synchronous Event Trigger for Event Patrol. - -- @function [parent=#AI_A2G_PATROL] Patrol - -- @param #AI_A2G_PATROL self + -- @function [parent=#AI_AIR_PATROL] Patrol + -- @param #AI_AIR_PATROL self --- Asynchronous Event Trigger for Event Patrol. - -- @function [parent=#AI_A2G_PATROL] __Patrol - -- @param #AI_A2G_PATROL self + -- @function [parent=#AI_AIR_PATROL] __Patrol + -- @param #AI_AIR_PATROL self -- @param #number Delay The delay in seconds. --- OnLeave Transition Handler for State Patrolling. - -- @function [parent=#AI_A2G_PATROL] OnLeavePatrolling - -- @param #AI_A2G_PATROL self + -- @function [parent=#AI_AIR_PATROL] OnLeavePatrolling + -- @param #AI_AIR_PATROL self -- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -166,18 +162,18 @@ function AI_A2G_PATROL:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor -- @return #boolean Return false to cancel Transition. --- OnEnter Transition Handler for State Patrolling. - -- @function [parent=#AI_A2G_PATROL] OnEnterPatrolling - -- @param #AI_A2G_PATROL self + -- @function [parent=#AI_AIR_PATROL] OnEnterPatrolling + -- @param #AI_AIR_PATROL self -- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. - self:AddTransition( "Patrolling", "PatrolRoute", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2G_PATROL. + self:AddTransition( "Patrolling", "PatrolRoute", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_PATROL. --- OnBefore Transition Handler for Event PatrolRoute. - -- @function [parent=#AI_A2G_PATROL] OnBeforePatrolRoute - -- @param #AI_A2G_PATROL self + -- @function [parent=#AI_AIR_PATROL] OnBeforePatrolRoute + -- @param #AI_AIR_PATROL self -- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. @@ -185,34 +181,34 @@ function AI_A2G_PATROL:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor -- @return #boolean Return false to cancel Transition. --- OnAfter Transition Handler for Event PatrolRoute. - -- @function [parent=#AI_A2G_PATROL] OnAfterPatrolRoute - -- @param #AI_A2G_PATROL self + -- @function [parent=#AI_AIR_PATROL] OnAfterPatrolRoute + -- @param #AI_AIR_PATROL self -- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. --- Synchronous Event Trigger for Event PatrolRoute. - -- @function [parent=#AI_A2G_PATROL] PatrolRoute - -- @param #AI_A2G_PATROL self + -- @function [parent=#AI_AIR_PATROL] PatrolRoute + -- @param #AI_AIR_PATROL self --- Asynchronous Event Trigger for Event PatrolRoute. - -- @function [parent=#AI_A2G_PATROL] __PatrolRoute - -- @param #AI_A2G_PATROL self + -- @function [parent=#AI_AIR_PATROL] __PatrolRoute + -- @param #AI_AIR_PATROL self -- @param #number Delay The delay in seconds. - self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2G_PATROL. + self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_PATROL. return self end --- Set the Engage Range when the AI will engage with airborne enemies. --- @param #AI_A2G_PATROL self +-- @param #AI_AIR_PATROL self -- @param #number EngageRange The Engage Range. --- @return #AI_A2G_PATROL self -function AI_A2G_PATROL:SetEngageRange( EngageRange ) +-- @return #AI_AIR_PATROL self +function AI_AIR_PATROL:SetEngageRange( EngageRange ) self:F2() if EngageRange then @@ -222,14 +218,44 @@ function AI_A2G_PATROL:SetEngageRange( EngageRange ) end end +--- Set race track parameters. CAP flights will perform race track patterns rather than randomly patrolling the zone. +-- @param #AI_AIR_PATROL self +-- @param #number LegMin Min Length of the race track leg in meters. Default 10,000 m. +-- @param #number LegMax Max length of the race track leg in meters. Default 15,000 m. +-- @param #number HeadingMin Min heading of the race track in degrees. Default 0 deg, i.e. from South to North. +-- @param #number HeadingMax Max heading of the race track in degrees. Default 180 deg, i.e. from South to North. +-- @param #number DurationMin (Optional) Min duration before switching the orbit position. Default is keep same orbit until RTB or engage. +-- @param #number DurationMax (Optional) Max duration before switching the orbit position. Default is keep same orbit until RTB or engage. +-- @param #table CapCoordinates Table of coordinates of first race track point. Second point is determined by leg length and heading. +-- @return #AI_AIR_PATROL self +function AI_AIR_PATROL:SetRaceTrackPattern(LegMin, LegMax, HeadingMin, HeadingMax, DurationMin, DurationMax, CapCoordinates) + + self.racetrack=true + self.racetracklegmin=LegMin or 10000 + self.racetracklegmax=LegMax or 15000 + self.racetrackheadingmin=HeadingMin or 0 + self.racetrackheadingmax=HeadingMax or 180 + self.racetrackdurationmin=DurationMin + self.racetrackdurationmax=DurationMax + + if self.racetrackdurationmax and not self.racetrackdurationmin then + self.racetrackdurationmin=self.racetrackdurationmax + end + + self.racetrackcapcoordinates=CapCoordinates + +end + + + --- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings. --- @param #AI_A2G_PATROL self --- @return #AI_A2G_PATROL self +-- @param #AI_AIR_PATROL self +-- @return #AI_AIR_PATROL self -- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. -function AI_A2G_PATROL:onafterPatrol( AIPatrol, From, Event, To ) +function AI_AIR_PATROL:onafterPatrol( AIPatrol, From, Event, To ) self:F2() self:ClearTargetDistance() @@ -247,9 +273,9 @@ end --- @param Wrapper.Group#GROUP AIPatrol -- This statis method is called from the route path within the last task at the last waaypoint of the AIPatrol. -- Note that this method is required, as triggers the next route when patrolling for the AIPatrol. -function AI_A2G_PATROL.___PatrolRoute( AIPatrol, Fsm ) +function AI_AIR_PATROL.___PatrolRoute( AIPatrol, Fsm ) - AIPatrol:F( { "AI_A2G_PATROL.___PatrolRoute:", AIPatrol:GetName() } ) + AIPatrol:F( { "AI_AIR_PATROL.___PatrolRoute:", AIPatrol:GetName() } ) if AIPatrol:IsAlive() then Fsm:PatrolRoute() @@ -258,12 +284,12 @@ function AI_A2G_PATROL.___PatrolRoute( AIPatrol, Fsm ) end --- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings. --- @param #AI_A2G_PATROL self +-- @param #AI_AIR_PATROL self -- @param Wrapper.Group#GROUP AIPatrol The Group managed by the FSM. -- @param #string From The From State string. -- @param #string Event The Event string. -- @param #string To The To State string. -function AI_A2G_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To ) +function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To ) self:F2() @@ -295,34 +321,82 @@ function AI_A2G_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To ) true ) PatrolRoute[#PatrolRoute+1] = FromWP - - --- Create a route point of type air. - local ToWP = ToTargetCoord:WaypointAir( - self.PatrolAltType, - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - ToTargetSpeed, - true - ) - PatrolRoute[#PatrolRoute+1] = ToWP - - local Tasks = {} - Tasks[#Tasks+1] = AIPatrol:TaskFunction( "AI_A2G_PATROL.___PatrolRoute", self ) - PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks ) - - AIPatrol:OptionROEReturnFire() - AIPatrol:OptionROTEvadeFire() + if self.racetrack then + + -- Random heading. + local heading = math.random(self.racetrackheadingmin, self.racetrackheadingmax) + + -- Random leg length. + local leg=math.random(self.racetracklegmin, self.racetracklegmax) + + -- Random duration if any. + local duration = self.racetrackdurationmin + if self.racetrackdurationmax then + duration=math.random(self.racetrackdurationmin, self.racetrackdurationmax) + end + + -- CAP coordinate. + local c0=self.PatrolZone:GetRandomCoordinate() + if self.racetrackcapcoordinates and #self.racetrackcapcoordinates>0 then + c0=self.racetrackcapcoordinates[math.random(#self.racetrackcapcoordinates)] + end + + -- Race track points. + local c1=c0:SetAltitude(altitude) --Core.Point#COORDINATE + local c2=c1:Translate(leg, heading):SetAltitude(altitude) + + self:SetTargetDistance(c0) -- For RTB status check + + -- Debug: + self:T(string.format("Patrol zone race track: v=%.1f knots, h=%.1f ft, heading=%03d, leg=%d m, t=%s sec", UTILS.KmphToKnots(speedkmh), UTILS.MetersToFeet(altitude), heading, leg, tostring(duration))) + --c1:MarkToAll("Race track c1") + --c2:MarkToAll("Race track c2") - AIPatrol:Route( PatrolRoute, self.TaskDelay ) + -- Task to orbit. + local taskOrbit=AIPatrol:TaskOrbit(c1, altitude, UTILS.KmphToMps(speedkmh), c2) + + -- Task function to redo the patrol at other random position. + local taskPatrol=AIPatrol:TaskFunction("AI_A2A_PATROL.PatrolRoute", self) + + -- Controlled task with task condition. + local taskCond=AIPatrol:TaskCondition(nil, nil, nil, nil, duration, nil) + local taskCont=AIPatrol:TaskControlled(taskOrbit, taskCond) + + -- Second waypoint + PatrolRoute[2]=c1:WaypointAirTurningPoint(self.PatrolAltType, speedkmh, {taskCont, taskPatrol}, "CAP Orbit") + + else + + --- Create a route point of type air. + local ToWP = ToTargetCoord:WaypointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + ToTargetSpeed, + true + ) + + PatrolRoute[#PatrolRoute+1] = ToWP + + local Tasks = {} + Tasks[#Tasks+1] = AIPatrol:TaskFunction( "AI_AIR_PATROL.___PatrolRoute", self ) + PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks ) + + AIPatrol:OptionROEReturnFire() + AIPatrol:OptionROTEvadeFire() + + AIPatrol:Route( PatrolRoute, self.TaskDelay ) + end + end end --- @param Wrapper.Group#GROUP AIPatrol -function AI_A2G_PATROL.Resume( AIPatrol, Fsm ) +function AI_AIR_PATROL.Resume( AIPatrol, Fsm ) - AIPatrol:F( { "AI_A2G_PATROL.Resume:", AIPatrol:GetName() } ) + AIPatrol:F( { "AI_AIR_PATROL.Resume:", AIPatrol:GetName() } ) if AIPatrol:IsAlive() then Fsm:__Reset( Fsm.TaskDelay ) Fsm:__PatrolRoute( Fsm.TaskDelay ) diff --git a/Moose Development/Moose/Core/RadioSpeech.lua b/Moose Development/Moose/Core/RadioSpeech.lua index 618cb5161..cb8ce9cfd 100644 --- a/Moose Development/Moose/Core/RadioSpeech.lua +++ b/Moose Development/Moose/Core/RadioSpeech.lua @@ -58,6 +58,14 @@ RADIOSPEECH.Vocabulary.EN = { ["80"] = { "80", 0.26 }, ["90"] = { "90", 0.36 }, ["100"] = { "100", 0.55 }, + ["200"] = { "200", 0.55 }, + ["300"] = { "300", 0.61 }, + ["400"] = { "400", 0.60 }, + ["500"] = { "500", 0.61 }, + ["600"] = { "600", 0.65 }, + ["700"] = { "700", 0.70 }, + ["800"] = { "800", 0.54 }, + ["900"] = { "900", 0.60 }, ["1000"] = { "1000", 1 }, ["chevy"] = { "chevy", 0.35 }, @@ -70,7 +78,6 @@ RADIOSPEECH.Vocabulary.EN = { ["uzi"] = { "uzi", 0.28 }, ["degrees"] = { "degrees", 0.5 }, - ["�"] = { "degrees", 0.5 }, ["kilometers"] = { "kilometers", 0.65 }, ["km"] = { "kilometers", 0.65 }, ["miles"] = { "miles", 0.45 }, @@ -81,7 +88,7 @@ RADIOSPEECH.Vocabulary.EN = { ["returning to base"] = { "returning_to_base", 0.85 }, - ["moving on to ground target"] = { "moving_on_to_ground_target", 1.20 }, + ["on route to ground target"] = { "on_route_to_ground_target", 1.05 }, ["engaging ground target"] = { "engaging_ground_target", 1.20 }, ["wheels up"] = { "wheels_up", 0.42 }, ["landing at base"] = { "landing at base", 0.8 }, diff --git a/Moose Development/Moose/Modules.lua b/Moose Development/Moose/Modules.lua index 0a499fe25..da8a13e96 100644 --- a/Moose Development/Moose/Modules.lua +++ b/Moose Development/Moose/Modules.lua @@ -71,17 +71,15 @@ __Moose.Include( 'Scripts/Moose/Ops/RescueHelo.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_Balancer.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_Air.lua' ) -__Moose.Include( 'Scripts/Moose/AI/AI_A2A.lua' ) +__Moose.Include( 'Scripts/Moose/AI/AI_Air_Patrol.lua' ) +__Moose.Include( 'Scripts/Moose/AI/AI_Air_Engage.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_A2A_Patrol.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_A2A_Cap.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_A2A_Gci.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_A2A_Dispatcher.lua' ) -__Moose.Include( 'Scripts/Moose/AI/AI_A2G.lua' ) -__Moose.Include( 'Scripts/Moose/AI/AI_A2G_Engage.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_A2G_BAI.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_A2G_CAS.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_A2G_SEAD.lua' ) -__Moose.Include( 'Scripts/Moose/AI/AI_A2G_Patrol.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_A2G_Dispatcher.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_Patrol.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_Cap.lua' )