diff --git a/Moose Development/Moose/AI/AI_A2A.lua b/Moose Development/Moose/AI/AI_A2A.lua index 8b75eb57f..9cdb27e70 100644 --- a/Moose Development/Moose/AI/AI_A2A.lua +++ b/Moose Development/Moose/AI/AI_A2A.lua @@ -261,6 +261,18 @@ function AI_A2A:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude ) end +--- Sets the home airbase. +-- @param #AI_A2A self +-- @param Wrapper.Airbase#AIRBASE HomeAirbase +-- @return #AI_A2A self +function AI_A2A:SetHomeAirbase( HomeAirbase ) + self:F2( { HomeAirbase } ) + + self.HomeAirbase = HomeAirbase +end + + + --- Set the status checking off. -- @param #AI_A2A self -- @return #AI_A2A self @@ -374,39 +386,67 @@ function AI_A2A:onafterStatus() end ---- @param #AI_A2A self -function AI_A2A:onafterRTB() - self:F2() +--- @param Wrapper.Group#GROUP AIGroup +function AI_A2A.RTBRoute( AIGroup ) - if self.Controllable and self.Controllable:IsAlive() then + AIGroup:E( { "RTBRoute:", AIGroup:GetName() } ) + local _AI_A2A = AIGroup:GetState( AIGroup, "AI_A2A" ) -- #AI_A2A + _AI_A2A:__Engage( 1 ) +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.CheckStatus = false - local PatrolRoute = {} - - --- Calculate the current route point. - local CurrentVec2 = self.Controllable:GetVec2() + local EngageRoute = {} + + --- Calculate the target route point. - --TODO: Create GetAltitude function for GROUP, and delete GetUnit(1). - local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude() - local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y ) - local ToPatrolZoneSpeed = self.PatrolMaxSpeed - local CurrentRoutePoint = CurrentPointVec3:RoutePointAir( - self.PatrolAltType, - POINT_VEC3.RoutePointType.TurningPoint, - POINT_VEC3.RoutePointAction.TurningPoint, - ToPatrolZoneSpeed, - true - ) + local CurrentCoord = AIGroup:GetCoordinate() + local ToTargetCoord = self.HomeAirbase:GetCoordinate() + local ToTargetSpeed = math.random( self.MinSpeed, self.MaxSpeed ) + local ToInterceptAngle = CurrentCoord:GetAngleDegrees( CurrentCoord:GetDirectionVec3( ToTargetCoord ) ) + + local Distance = CurrentCoord:Get2DDistance( ToTargetCoord ) - PatrolRoute[#PatrolRoute+1] = CurrentRoutePoint + local ToAirbaseCoord = CurrentCoord:Translate( 5000, ToInterceptAngle ) + if Distance > 10000 then + ToAirbaseCoord = ToTargetCoord + end + --- Create a route point of type air. + local ToPatrolRoutePoint = ToAirbaseCoord:RoutePointAir( + self.PatrolAltType, + POINT_VEC3.RoutePointType.TurningPoint, + POINT_VEC3.RoutePointAction.TurningPoint, + ToTargetSpeed, + true + ) + + self:F( { Angle = ToInterceptAngle, ToTargetSpeed = ToTargetSpeed } ) + self:T2( { self.MinSpeed, self.MaxSpeed, ToTargetSpeed } ) + EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint + + AIGroup:OptionROEHoldFire() + AIGroup:OptionROTEvadeFire() + --- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable... - self.Controllable:WayPointInitialize( PatrolRoute ) + AIGroup:WayPointInitialize( EngageRoute ) + local Tasks = {} + Tasks[#Tasks+1] = AIGroup:TaskFunction( 1, 1, "AI_A2A.RTBRoute" ) + EngageRoute[1].task = AIGroup:TaskCombo( Tasks ) + + AIGroup:SetState( AIGroup, "AI_A2A", self ) + --- NOW ROUTE THE GROUP! - self.Controllable:WayPointExecute( 1, 1 ) - + AIGroup:WayPointExecute( 1, 2 ) + end end diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua index 8037254b6..6249a0641 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -136,7 +136,7 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling self.Accomplished = false self.Engaging = false - self:AddTransition( { "Patrolling", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP. + self:AddTransition( { "Patrolling", "Engaging", "RTB" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP. --- OnBefore Transition Handler for Event Engage. -- @function [parent=#AI_A2A_CAP] OnBeforeEngage diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 9621dbb19..b233ce2f0 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -1,4 +1,4 @@ ---- **Tasking** - The AI_A2A_DISPATCHER creates and manages AI_A2A tasks based on detected targets. +--- **AI** - The AI_A2A_DISPATCHER creates and manages AI_A2A tasks based on detected targets. -- -- ==== -- @@ -145,6 +145,13 @@ do -- AI_A2A_DISPATCHER -- Essentially this controls how many flights of GCI aircraft can be active at any time. -- Note allowing large numbers of active GCI flights can adversely impact mission performance on low or medium specification hosts/servers. -- + -- # Country, type, load out, skill and skins for CAP and GCI aircraft? + -- + -- * Note these can be from any countries within the coalition but must be an aircraft with one of the main tasks being “CAP”. + -- * Obviously skins which are selected must be available to all players that join the mission otherwise they will see a default skin. + -- * Load outs should be appropriate to a CAP mission eg perhaps drop tanks for CAP flights and extra missiles for GCI flights. + -- * These decisions will eventually lead to template aircraft units being placed as late activation units that the script will use as templates for spawning CAP and GCI flights. Up to 4 different aircraft configurations can be chosen for each coalition. The spawned aircraft will inherit the characteristics of the template aircraft. + -- * The selected aircraft type must be able to perform the CAP tasking for the chosen country. -- -- -- @field #AI_A2A_DISPATCHER @@ -394,6 +401,24 @@ do -- AI_A2A_DISPATCHER return self end + --- + -- @param #AI_A2A_DISPATCHER self + function AI_A2A_DISPATCHER:ClearDefenderTaskTarget( AIGroup ) + if AIGroup:IsAlive() and self.DefenderTasks[AIGroup] then + local Target = self.DefenderTasks[AIGroup].Target + local Message = "Clearing (" .. self.DefenderTasks[AIGroup].Type .. ") " + Message = Message .. AIGroup:GetName() + if Target then + Message = Message .. ( Target and ( " from " .. Target.Index .. " [" .. Target.Set:Count() .. "]" ) ) or "" + end + self:F( { Target = Message } ) + end + if AIGroup and self.DefenderTasks[AIGroup] and self.DefenderTasks[AIGroup].Target then + self.DefenderTasks[AIGroup].Target = nil + end + return self + end + --- -- @param #AI_A2A_DISPATCHER self @@ -786,6 +811,7 @@ do -- AI_A2A_DISPATCHER local Fsm = AI_A2A_CAP:New( AIGroup, Cap.Zone, Cap.FloorAltitude, Cap.CeilingAltitude, Cap.MinSpeed, Cap.MaxSpeed, Cap.AltType ) Fsm:SetDispatcher( self ) + Fsm:SetHomeAirbase( DefenderSquadron.Airbase ) Fsm:Start() Fsm:__Patrol( 1 ) @@ -814,11 +840,12 @@ do -- AI_A2A_DISPATCHER self:SetDefenderTaskTarget( AIGroup, Target ) - function Fsm:onafterRTB() + function Fsm:onafterRTB( AIGroup, From, Event, To ) self:F({"CAP RTB"}) + self:GetParent(self).onafterRTB( self, AIGroup, From, Event, To ) local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER local AIGroup = self:GetControllable() - Dispatcher:ClearDefenderTask( AIGroup ) + Dispatcher:ClearDefenderTaskTarget( AIGroup ) end end end @@ -884,17 +911,21 @@ do -- AI_A2A_DISPATCHER local Fsm = AI_A2A_INTERCEPT:New( AIGroup, Intercept.MinSpeed, Intercept.MaxSpeed ) Fsm:SetDispatcher( self ) + Fsm:SetHomeAirbase( DefenderSquadron.Airbase ) Fsm:Start() Fsm:__Engage( 1, Target.Set ) -- Engage on the TargetSetUnit self:SetDefenderTask( AIGroup, "INTERCEPT", Fsm, Target ) - function Fsm:onafterRTB() + + function Fsm:onafterRTB( AIGroup, From, Event, To ) self:F({"INTERCEPT RTB"}) + self:GetParent(self).onafterRTB( self, AIGroup, From, Event, To ) + local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER local AIGroup = self:GetControllable() - Dispatcher:ClearDefenderTask( AIGroup ) + Dispatcher:ClearDefenderTaskTarget( AIGroup ) end end @@ -971,7 +1002,15 @@ do -- AI_A2A_DISPATCHER for AIGroup, DefenderTask in pairs( self:GetDefenderTasks() ) do local AIGroup = AIGroup -- Wrapper.Group#GROUP if not AIGroup:IsAlive() then - self:ClearDefenderTask( AIGroup ) + self:ClearDefenderTask( AIGroup ) + else + if DefenderTask.Target then + if DefenderTask.Target.Set then + if DefenderTask.Target.Set:Count() == 0 then + self:ClearDefenderTaskTarget( AIGroup ) + end + end + end end end diff --git a/Moose Development/Moose/AI/AI_A2A_Intercept.lua b/Moose Development/Moose/AI/AI_A2A_Intercept.lua index e7c858ddf..ee2fb9364 100644 --- a/Moose Development/Moose/AI/AI_A2A_Intercept.lua +++ b/Moose Development/Moose/AI/AI_A2A_Intercept.lua @@ -132,7 +132,7 @@ function AI_A2A_INTERCEPT:New( AIGroup, MinSpeed, MaxSpeed ) self.PatrolAltType = "RADIO" - self:AddTransition( { "Started", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_INTERCEPT. + self:AddTransition( { "Started", "Engaging", "RTB" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_INTERCEPT. --- OnBefore Transition Handler for Event Engage. -- @function [parent=#AI_A2A_INTERCEPT] OnBeforeEngage