From c2965e07363b74fd2569360c3ae40d7904c0f158 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Fri, 1 Sep 2017 19:24:50 +0200 Subject: [PATCH 1/3] Single lase commands --- .../Moose/Functional/Designate.lua | 189 +++++++++--------- 1 file changed, 98 insertions(+), 91 deletions(-) diff --git a/Moose Development/Moose/Functional/Designate.lua b/Moose Development/Moose/Functional/Designate.lua index 78758e763..a70f12f7e 100644 --- a/Moose Development/Moose/Functional/Designate.lua +++ b/Moose Development/Moose/Functional/Designate.lua @@ -990,6 +990,8 @@ do -- DESIGNATE function DESIGNATE:onafterLaseOn( From, Event, To, Index, Duration, LaserCode ) self.Designating[Index] = "Laser" + self.LaseStart = timer.getTime() + self.LaseDuration = Duration self:__Lasing( -1, Index, Duration, LaserCode ) end @@ -1038,59 +1040,84 @@ do -- DESIGNATE end end + if self.AutoLase or ( not self.AutoLase and ( self.LaseStart + Duration >= timer.getTime() ) ) then - TargetSetUnit:ForEachUnitPerThreatLevel( 10, 0, - --- @param Wrapper.Unit#UNIT SmokeUnit - function( TargetUnit ) - - self:F( { TargetUnit = TargetUnit:GetName() } ) - - if MarkingCount < self.MaximumMarkings then - - if TargetUnit:IsAlive() then + TargetSetUnit:ForEachUnitPerThreatLevel( 10, 0, + --- @param Wrapper.Unit#UNIT SmokeUnit + function( TargetUnit ) + + self:F( { TargetUnit = TargetUnit:GetName() } ) - local Recce = self.Recces[TargetUnit] + if MarkingCount < self.MaximumMarkings then - if not Recce then - - self:E( "Lasing..." ) - self.RecceSet:Flush() - - for RecceGroupID, RecceGroup in pairs( self.RecceSet:GetSet() ) do - for UnitID, UnitData in pairs( RecceGroup:GetUnits() or {} ) do - - local RecceUnit = UnitData -- Wrapper.Unit#UNIT - local RecceUnitDesc = RecceUnit:GetDesc() - --self:F( { RecceUnit = RecceUnit:GetName(), RecceDescription = RecceUnitDesc } ) - - if RecceUnit:IsLasing() == false then - --self:F( { IsDetected = RecceUnit:IsDetected( TargetUnit ), IsLOS = RecceUnit:IsLOS( TargetUnit ) } ) - - if RecceUnit:IsDetected( TargetUnit ) and RecceUnit:IsLOS( TargetUnit ) then - - local LaserCodeIndex = math.random( 1, #self.LaserCodes ) - local LaserCode = self.LaserCodes[LaserCodeIndex] - --self:F( { LaserCode = LaserCode, LaserCodeUsed = self.LaserCodesUsed[LaserCode] } ) - - if LaserCodeRequested and LaserCodeRequested ~= LaserCode then - LaserCode = LaserCodeRequested - LaserCodeRequested = nil - end - - if not self.LaserCodesUsed[LaserCode] then - - self.LaserCodesUsed[LaserCode] = LaserCodeIndex - local Spot = RecceUnit:LaseUnit( TargetUnit, LaserCode, Duration ) - local AttackSet = self.AttackSet - - function Spot:OnAfterDestroyed( From, Event, To ) - self:E( "Destroyed Message" ) - self.Recce:ToSetGroup( "Target " .. TargetUnit:GetTypeName() .. " destroyed. " .. TargetSetUnit:Count() .. " targets left.", 5, AttackSet, self.DesignateName ) + if TargetUnit:IsAlive() then + + local Recce = self.Recces[TargetUnit] + + if not Recce then + + self:E( "Lasing..." ) + self.RecceSet:Flush() + + for RecceGroupID, RecceGroup in pairs( self.RecceSet:GetSet() ) do + for UnitID, UnitData in pairs( RecceGroup:GetUnits() or {} ) do + + local RecceUnit = UnitData -- Wrapper.Unit#UNIT + local RecceUnitDesc = RecceUnit:GetDesc() + --self:F( { RecceUnit = RecceUnit:GetName(), RecceDescription = RecceUnitDesc } ) + + if RecceUnit:IsLasing() == false then + --self:F( { IsDetected = RecceUnit:IsDetected( TargetUnit ), IsLOS = RecceUnit:IsLOS( TargetUnit ) } ) + + if RecceUnit:IsDetected( TargetUnit ) and RecceUnit:IsLOS( TargetUnit ) then + + local LaserCodeIndex = math.random( 1, #self.LaserCodes ) + local LaserCode = self.LaserCodes[LaserCodeIndex] + --self:F( { LaserCode = LaserCode, LaserCodeUsed = self.LaserCodesUsed[LaserCode] } ) + + if LaserCodeRequested and LaserCodeRequested ~= LaserCode then + LaserCode = LaserCodeRequested + LaserCodeRequested = nil end - - self.Recces[TargetUnit] = RecceUnit - RecceUnit:MessageToSetGroup( "Marking " .. TargetUnit:GetTypeName() .. " with laser " .. RecceUnit:GetSpot().LaserCode .. " for " .. Duration .. "s.", 5, self.AttackSet, self.DesignateName ) - -- OK. We have assigned for the Recce a TargetUnit. We can exit the function. + + if not self.LaserCodesUsed[LaserCode] then + + self.LaserCodesUsed[LaserCode] = LaserCodeIndex + local Spot = RecceUnit:LaseUnit( TargetUnit, LaserCode, Duration ) + local AttackSet = self.AttackSet + + function Spot:OnAfterDestroyed( From, Event, To ) + self:E( "Destroyed Message" ) + self.Recce:ToSetGroup( "Target " .. TargetUnit:GetTypeName() .. " destroyed. " .. TargetSetUnit:Count() .. " targets left.", 5, AttackSet, self.DesignateName ) + end + + self.Recces[TargetUnit] = RecceUnit + RecceUnit:MessageToSetGroup( "Marking " .. TargetUnit:GetTypeName() .. " with laser " .. RecceUnit:GetSpot().LaserCode .. " for " .. Duration .. "s.", 5, self.AttackSet, self.DesignateName ) + -- OK. We have assigned for the Recce a TargetUnit. We can exit the function. + MarkingCount = MarkingCount + 1 + local TargetUnitType = TargetUnit:GetTypeName() + if not MarkedTypes[TargetUnitType] then + MarkedTypes[TargetUnitType] = true + ReportTypes:Add(TargetUnitType) + end + ReportLaserCodes:Add(RecceUnit.LaserCode) + return + end + else + --RecceUnit:MessageToSetGroup( "Can't mark " .. TargetUnit:GetTypeName(), 5, self.AttackSet ) + end + else + -- The Recce is lasing, but the Target is not detected or within LOS. So stop lasing and send a report. + + if not RecceUnit:IsDetected( TargetUnit ) or not RecceUnit:IsLOS( TargetUnit ) then + + local Recce = self.Recces[TargetUnit] -- Wrapper.Unit#UNIT + + if Recce then + Recce:LaseOff() + Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() "out of LOS. Cancelling lase!", 5, self.AttackSet, self.DesignateName ) + end + else MarkingCount = MarkingCount + 1 local TargetUnitType = TargetUnit:GetTypeName() if not MarkedTypes[TargetUnitType] then @@ -1098,59 +1125,39 @@ do -- DESIGNATE ReportTypes:Add(TargetUnitType) end ReportLaserCodes:Add(RecceUnit.LaserCode) - return - end - else - --RecceUnit:MessageToSetGroup( "Can't mark " .. TargetUnit:GetTypeName(), 5, self.AttackSet ) + end end - else - -- The Recce is lasing, but the Target is not detected or within LOS. So stop lasing and send a report. - - if not RecceUnit:IsDetected( TargetUnit ) or not RecceUnit:IsLOS( TargetUnit ) then - - local Recce = self.Recces[TargetUnit] -- Wrapper.Unit#UNIT - - if Recce then - Recce:LaseOff() - Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() "out of LOS. Cancelling lase!", 5, self.AttackSet, self.DesignateName ) - end - else - MarkingCount = MarkingCount + 1 - local TargetUnitType = TargetUnit:GetTypeName() - if not MarkedTypes[TargetUnitType] then - MarkedTypes[TargetUnitType] = true - ReportTypes:Add(TargetUnitType) - end - ReportLaserCodes:Add(RecceUnit.LaserCode) - end end end + else + MarkingCount = MarkingCount + 1 + local TargetUnitType = TargetUnit:GetTypeName() + if not MarkedTypes[TargetUnitType] then + MarkedTypes[TargetUnitType] = true + ReportTypes:Add(TargetUnitType) + end + ReportLaserCodes:Add(Recce.LaserCode) + --Recce:MessageToSetGroup( self.DesignateName .. ": Marking " .. TargetUnit:GetTypeName() .. " with laser " .. Recce.LaserCode .. ".", 5, self.AttackSet ) end - else - MarkingCount = MarkingCount + 1 - local TargetUnitType = TargetUnit:GetTypeName() - if not MarkedTypes[TargetUnitType] then - MarkedTypes[TargetUnitType] = true - ReportTypes:Add(TargetUnitType) - end - ReportLaserCodes:Add(Recce.LaserCode) - --Recce:MessageToSetGroup( self.DesignateName .. ": Marking " .. TargetUnit:GetTypeName() .. " with laser " .. Recce.LaserCode .. ".", 5, self.AttackSet ) end end end + ) + + local MarkedTypesText = ReportTypes:Text(', ') + local MarkedLaserCodesText = ReportLaserCodes:Text(', ') + for MarkedType, MarketCount in pairs( MarkedTypes ) do + self.CC:GetPositionable():MessageToSetGroup( "Marking " .. MarkingCount .. " x " .. MarkedTypesText .. " with lasers " .. MarkedLaserCodesText .. ".", 5, self.AttackSet, self.DesignateName ) end - ) + + self:__Lasing( -30, Index, Duration, LaserCodeRequested ) + + self:SetDesignateMenu() - local MarkedTypesText = ReportTypes:Text(', ') - local MarkedLaserCodesText = ReportLaserCodes:Text(', ') - for MarkedType, MarketCount in pairs( MarkedTypes ) do - self.CC:GetPositionable():MessageToSetGroup( "Marking " .. MarkingCount .. " x " .. MarkedTypesText .. " with lasers " .. MarkedLaserCodesText .. ".", 5, self.AttackSet, self.DesignateName ) + else + self:__LaseOff( 1 ) end - self:__Lasing( -30, Index, Duration ) - - self:SetDesignateMenu() - end --- From e6c765c4418d52a2c086309ce205951fca641081 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 2 Sep 2017 09:22:23 +0200 Subject: [PATCH 2/3] Solve calculation problems with player has disconnected or changed plane * Player disconnecting will not result in coordinate calculation problems in AI_A2A_CAP and AI_A2A_GCI while engaged with the player machine. The engagement will stop. --- Moose Development/Moose/AI/AI_A2A_Cap.lua | 4 ++-- Moose Development/Moose/AI/AI_A2A_Gci.lua | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua index a804ecaa3..2509721b9 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -391,9 +391,9 @@ function AI_A2A_CAP:onafterEngage( AIGroup, From, Event, To, AttackSetUnit ) self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT - local FirstAttackUnit = self.AttackSetUnit:GetFirst() + local FirstAttackUnit = self.AttackSetUnit:GetFirst() -- Wrapper.Unit#UNIT - if FirstAttackUnit then + if FirstAttackUnit and FirstAttackUnit:IsAlive() then -- If there is no attacker anymore, stop the engagement. if AIGroup:IsAlive() then diff --git a/Moose Development/Moose/AI/AI_A2A_Gci.lua b/Moose Development/Moose/AI/AI_A2A_Gci.lua index 3bdc0ebbb..5d0c415c7 100644 --- a/Moose Development/Moose/AI/AI_A2A_Gci.lua +++ b/Moose Development/Moose/AI/AI_A2A_Gci.lua @@ -360,14 +360,13 @@ function AI_A2A_GCI:onafterEngage( AIGroup, From, Event, To, AttackSetUnit ) local FirstAttackUnit = self.AttackSetUnit:GetFirst() - if FirstAttackUnit then + if FirstAttackUnit and FirstAttackUnit:IsAlive() then if AIGroup:IsAlive() then local EngageRoute = {} local CurrentCoord = AIGroup:GetCoordinate() - --- Calculate the target route point. From 2830bcb8679c662883f655be1daa201262f9a8c8 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 2 Sep 2017 10:24:28 +0200 Subject: [PATCH 3/3] Respect Gci radius * Corrected the calculation to the distance to the airbase, when the intercept calculation is used. Now the intercept point is not anymore interfering with the gci radius validation and gci radius is now correctly respected and validated. --- .../Moose/AI/AI_A2A_Dispatcher.lua | 311 +++++++++--------- 1 file changed, 158 insertions(+), 153 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index ccfbfa352..649d2223e 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -1369,14 +1369,14 @@ do -- AI_A2A_DISPATCHER --- -- @param #AI_A2A_DISPATCHER self -- @param Wrapper.Group#GROUP AIGroup - function AI_A2A_DISPATCHER:SetDefenderTaskTarget( Defender, Target ) + function AI_A2A_DISPATCHER:SetDefenderTaskTarget( Defender, AttackerDetection ) local Message = "(" .. self.DefenderTasks[Defender].Type .. ") " Message = Message .. Defender:GetName() - Message = Message .. ( Target and ( " target " .. Target.Index .. " [" .. Target.Set:Count() .. "]" ) ) or "" - self:F( { Target = Message } ) - if Target then - self.DefenderTasks[Defender].Target = Target + Message = Message .. ( AttackerDetection and ( " target " .. AttackerDetection.Index .. " [" .. AttackerDetection.Set:Count() .. "]" ) ) or "" + self:F( { AttackerDetection = Message } ) + if AttackerDetection then + self.DefenderTasks[Defender].Target = AttackerDetection end return self end @@ -2510,20 +2510,20 @@ do -- AI_A2A_DISPATCHER --- -- @param #AI_A2A_DISPATCHER self - function AI_A2A_DISPATCHER:CountDefendersEngaged( Target ) + function AI_A2A_DISPATCHER:CountDefendersEngaged( AttackerDetection ) -- First, count the active AIGroups Units, targetting the DetectedSet local AIUnitCount = 0 self:E( "Counting Defenders Engaged for Attacker:" ) - local DetectedSet = Target.Set + local DetectedSet = AttackerDetection.Set DetectedSet:Flush() local DefenderTasks = self:GetDefenderTasks() for AIGroup, DefenderTask in pairs( DefenderTasks ) do local AIGroup = AIGroup -- Wrapper.Group#GROUP local DefenderTask = self:GetDefenderTaskTarget( AIGroup ) - if DefenderTask and DefenderTask.Index == Target.Index then + if DefenderTask and DefenderTask.Index == AttackerDetection.Index then AIUnitCount = AIUnitCount + AIGroup:GetSize() self:E( "Defender Group Name: " .. AIGroup:GetName() .. ", Size: " .. AIGroup:GetSize() ) end @@ -2534,18 +2534,18 @@ do -- AI_A2A_DISPATCHER --- -- @param #AI_A2A_DISPATCHER self - function AI_A2A_DISPATCHER:CountDefendersToBeEngaged( DetectedItem, DefenderCount ) + function AI_A2A_DISPATCHER:CountDefendersToBeEngaged( AttackerDetection, DefenderCount ) local Friendlies = nil - local DetectedSet = DetectedItem.Set - local DetectedCount = DetectedSet:Count() + local AttackerSet = AttackerDetection.Set + local AttackerCount = AttackerSet:Count() - local AIFriendlies = self:GetAIFriendliesNearBy( DetectedItem ) + local DefenderFriendlies = self:GetAIFriendliesNearBy( AttackerDetection ) - for FriendlyDistance, AIFriendly in UTILS.spairs( AIFriendlies or {} ) do + for FriendlyDistance, AIFriendly in UTILS.spairs( DefenderFriendlies or {} ) do -- We only allow to ENGAGE targets as long as the Units on both sides are balanced. - if DetectedCount > DefenderCount then + if AttackerCount > DefenderCount then local Friendly = AIFriendly:GetGroup() -- Wrapper.Group#GROUP if Friendly and Friendly:IsAlive() then -- Ok, so we have a friendly near the potential target. @@ -2554,7 +2554,7 @@ do -- AI_A2A_DISPATCHER if DefenderTask then -- The Task should be CAP or GCI if DefenderTask.Type == "CAP" or DefenderTask.Type == "GCI" then - -- If there is no target, then add the AIGroup to the ResultAIGroups for Engagement to the TargetSet + -- If there is no target, then add the AIGroup to the ResultAIGroups for Engagement to the AttackerSet if DefenderTask.Target == nil then if DefenderTask.Fsm:Is( "Returning" ) or DefenderTask.Fsm:Is( "Patrolling" ) then @@ -2650,16 +2650,16 @@ do -- AI_A2A_DISPATCHER --- -- @param #AI_A2A_DISPATCHER self - function AI_A2A_DISPATCHER:onafterENGAGE( From, Event, To, Target, Defenders ) + function AI_A2A_DISPATCHER:onafterENGAGE( From, Event, To, AttackerDetection, Defenders ) if Defenders then for DefenderID, Defender in pairs( Defenders ) do local Fsm = self:GetDefenderTaskFsm( Defender ) - Fsm:__Engage( 1, Target.Set ) -- Engage on the TargetSetUnit + Fsm:__Engage( 1, AttackerDetection.Set ) -- Engage on the TargetSetUnit - self:SetDefenderTaskTarget( Defender, Target ) + self:SetDefenderTaskTarget( Defender, AttackerDetection ) end end @@ -2667,164 +2667,169 @@ do -- AI_A2A_DISPATCHER --- -- @param #AI_A2A_DISPATCHER self - function AI_A2A_DISPATCHER:onafterGCI( From, Event, To, DetectedItem, DefendersMissing, Friendlies ) + function AI_A2A_DISPATCHER:onafterGCI( From, Event, To, AttackerDetection, DefendersMissing, DefenderFriendlies ) - self:F( { From, Event, To, DetectedItem.Index, DefendersMissing, Friendlies } ) + self:F( { From, Event, To, AttackerDetection.Index, DefendersMissing, DefenderFriendlies } ) - local AttackerSet = DetectedItem.Set - local AttackerCount = AttackerSet:Count() - local DefendersCount = 0 - - for DefenderID, AIGroup in pairs( Friendlies or {} ) do - - local Fsm = self:GetDefenderTaskFsm( AIGroup ) - Fsm:__Engage( 1, AttackerSet ) -- Engage on the TargetSetUnit + local AttackerSet = AttackerDetection.Set + local AttackerUnit = AttackerSet:GetFirst() + + if AttackerUnit and AttackerUnit:IsAlive() then + local AttackerCount = AttackerSet:Count() + local DefenderCount = 0 + + for DefenderID, DefenderGroup in pairs( DefenderFriendlies or {} ) do + + local Fsm = self:GetDefenderTaskFsm( DefenderGroup ) + Fsm:__Engage( 1, AttackerSet ) -- Engage on the TargetSetUnit + + self:SetDefenderTaskTarget( DefenderGroup, AttackerDetection ) + + DefenderCount = DefenderCount + DefenderGroup:GetSize() + end + + DefenderCount = DefendersMissing + + local ClosestDistance = 0 + local ClosestDefenderSquadronName = nil - self:SetDefenderTaskTarget( AIGroup, DetectedItem ) - - DefendersCount = DefendersCount + AIGroup:GetSize() - end - - DefendersCount = DefendersMissing - - local ClosestDistance = 0 - local ClosestDefenderSquadronName = nil - - local BreakLoop = false - - while( DefendersCount > 0 and not BreakLoop ) do - self:F( { DefenderSquadrons = self.DefenderSquadrons } ) - for SquadronName, DefenderSquadron in pairs( self.DefenderSquadrons or {} ) do - self:F( { GCI = DefenderSquadron.Gci } ) - for InterceptID, Intercept in pairs( DefenderSquadron.Gci or {} ) do - - self:F( { DefenderSquadron } ) - local SpawnCoord = DefenderSquadron.Airbase:GetCoordinate() -- Core.Point#COORDINATE - --local TargetCoord = AttackerSet:GetFirst():GetCoordinate() - local InterceptCoord = DetectedItem.InterceptCoord - self:F({InterceptCoord = InterceptCoord}) - if InterceptCoord then - local Distance = SpawnCoord:Get2DDistance( InterceptCoord ) - self:F( { Distance = Distance, InterceptCoord = InterceptCoord } ) - - if ClosestDistance == 0 or Distance < ClosestDistance then + local BreakLoop = false + + while( DefenderCount > 0 and not BreakLoop ) do + self:F( { DefenderSquadrons = self.DefenderSquadrons } ) + for SquadronName, DefenderSquadron in pairs( self.DefenderSquadrons or {} ) do + self:F( { GCI = DefenderSquadron.Gci } ) + for InterceptID, Intercept in pairs( DefenderSquadron.Gci or {} ) do + + self:F( { DefenderSquadron } ) + local SpawnCoord = DefenderSquadron.Airbase:GetCoordinate() -- Core.Point#COORDINATE + local AttackerCoord = AttackerUnit:GetCoordinate() + local InterceptCoord = AttackerDetection.InterceptCoord + self:F({InterceptCoord = InterceptCoord}) + if InterceptCoord then + local InterceptDistance = SpawnCoord:Get2DDistance( InterceptCoord ) + local AirbaseDistance = SpawnCoord:Get2DDistance( AttackerCoord ) + self:F( { InterceptDistance = InterceptDistance, AirbaseDistance = AirbaseDistance, InterceptCoord = InterceptCoord } ) - -- Only intercept if the distance to target is smaller or equal to the GciRadius limit. - if Distance <= self.GciRadius then - ClosestDistance = Distance - ClosestDefenderSquadronName = SquadronName + if ClosestDistance == 0 or InterceptDistance < ClosestDistance then + + -- Only intercept if the distance to target is smaller or equal to the GciRadius limit. + if AirbaseDistance <= self.GciRadius then + ClosestDistance = InterceptDistance + ClosestDefenderSquadronName = SquadronName + end end end end end - end - - if ClosestDefenderSquadronName then - - local DefenderSquadron = self:CanGCI( ClosestDefenderSquadronName ) - if DefenderSquadron then - - local Gci = self.DefenderSquadrons[ClosestDefenderSquadronName].Gci - - if Gci then + if ClosestDefenderSquadronName then - local DefenderOverhead = DefenderSquadron.Overhead or self.DefenderDefault.Overhead - local DefenderGrouping = DefenderSquadron.Grouping or self.DefenderDefault.Grouping - local DefendersNeeded = math.ceil( DefendersCount * DefenderOverhead ) - - self:F( { DefaultOverhead = self.DefenderDefault.Overhead, Overhead = DefenderOverhead } ) - self:F( { DefaultGrouping = self.DefenderDefault.Grouping, Grouping = DefenderGrouping } ) - self:F( { DefendersCount = DefendersCount, DefendersNeeded = DefendersNeeded } ) - - while ( DefendersNeeded > 0 ) do + local DefenderSquadron = self:CanGCI( ClosestDefenderSquadronName ) - local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] -- Functional.Spawn#SPAWN - local DefenderGrouping = ( DefenderGrouping < DefendersNeeded ) and DefenderGrouping or DefendersNeeded - if DefenderGrouping then - Spawn:InitGrouping( DefenderGrouping ) - else - Spawn:InitGrouping() - end + if DefenderSquadron then + + local Gci = self.DefenderSquadrons[ClosestDefenderSquadronName].Gci + + if Gci then + + local DefenderOverhead = DefenderSquadron.Overhead or self.DefenderDefault.Overhead + local DefenderGrouping = DefenderSquadron.Grouping or self.DefenderDefault.Grouping + local DefendersNeeded = math.ceil( DefenderCount * DefenderOverhead ) - local TakeoffMethod = self:GetSquadronTakeoff( ClosestDefenderSquadronName ) - local DefenderGCI = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod, DefenderSquadron.TakeoffAltitude or self.DefenderDefault.TakeoffAltitude ) -- Wrapper.Group#GROUP - self:F( { GCIDefender = DefenderGCI:GetName() } ) - - DefendersNeeded = DefendersNeeded - DefenderGrouping - - self:AddDefenderToSquadron( DefenderSquadron, DefenderGCI, DefenderGrouping ) + self:F( { DefaultOverhead = self.DefenderDefault.Overhead, Overhead = DefenderOverhead } ) + self:F( { DefaultGrouping = self.DefenderDefault.Grouping, Grouping = DefenderGrouping } ) + self:F( { DefendersCount = DefenderCount, DefendersNeeded = DefendersNeeded } ) + + while ( DefendersNeeded > 0 ) do + + local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] -- Functional.Spawn#SPAWN + local DefenderGrouping = ( DefenderGrouping < DefendersNeeded ) and DefenderGrouping or DefendersNeeded + if DefenderGrouping then + Spawn:InitGrouping( DefenderGrouping ) + else + Spawn:InitGrouping() + end + + local TakeoffMethod = self:GetSquadronTakeoff( ClosestDefenderSquadronName ) + local DefenderGCI = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod, DefenderSquadron.TakeoffAltitude or self.DefenderDefault.TakeoffAltitude ) -- Wrapper.Group#GROUP + self:F( { GCIDefender = DefenderGCI:GetName() } ) + + DefendersNeeded = DefendersNeeded - DefenderGrouping - if DefenderGCI then - - DefendersCount = DefendersCount - DefenderGrouping - - local Fsm = AI_A2A_GCI:New( DefenderGCI, Gci.EngageMinSpeed, Gci.EngageMaxSpeed ) - Fsm:SetDispatcher( self ) - Fsm:SetHomeAirbase( DefenderSquadron.Airbase ) - Fsm:SetFuelThreshold( DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold, 60 ) - Fsm:SetDamageThreshold( self.DefenderDefault.DamageThreshold ) - Fsm:SetDisengageRadius( self.DisengageRadius ) - Fsm:Start() - Fsm:__Engage( 2, DetectedItem.Set ) -- Engage on the TargetSetUnit - + self:AddDefenderToSquadron( DefenderSquadron, DefenderGCI, DefenderGrouping ) + + if DefenderGCI then - self:SetDefenderTask( ClosestDefenderSquadronName, DefenderGCI, "GCI", Fsm, DetectedItem ) - - - function Fsm:onafterRTB( Defender, From, Event, To ) - self:F({"GCI RTB", Defender:GetName()}) - self:GetParent(self).onafterRTB( self, Defender, From, Event, To ) + DefenderCount = DefenderCount - DefenderGrouping - local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER - Dispatcher:ClearDefenderTaskTarget( Defender ) - end - - --- @param #AI_A2A_DISPATCHER self - function Fsm:onafterLostControl( Defender, From, Event, To ) - self:F({"GCI LostControl", Defender:GetName()}) - self:GetParent(self).onafterHome( self, Defender, From, Event, To ) + local Fsm = AI_A2A_GCI:New( DefenderGCI, Gci.EngageMinSpeed, Gci.EngageMaxSpeed ) + Fsm:SetDispatcher( self ) + Fsm:SetHomeAirbase( DefenderSquadron.Airbase ) + Fsm:SetFuelThreshold( DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold, 60 ) + Fsm:SetDamageThreshold( self.DefenderDefault.DamageThreshold ) + Fsm:SetDisengageRadius( self.DisengageRadius ) + Fsm:Start() + Fsm:__Engage( 2, AttackerDetection.Set ) -- Engage on the TargetSetUnit + + + self:SetDefenderTask( ClosestDefenderSquadronName, DefenderGCI, "GCI", Fsm, AttackerDetection ) - local Dispatcher = Fsm:GetDispatcher() -- #AI_A2A_DISPATCHER - local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) - if Defender:IsAboveRunway() then - Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender ) - Defender:Destroy() - end - end - - --- @param #AI_A2A_DISPATCHER self - function Fsm:onafterHome( Defender, From, Event, To, Action ) - self:F({"GCI Home", Defender:GetName()}) - self:GetParent(self).onafterHome( self, Defender, From, Event, To ) - local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER - local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) - - if Action and Action == "Destroy" then - Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender ) - Defender:Destroy() + function Fsm:onafterRTB( Defender, From, Event, To ) + self:F({"GCI RTB", Defender:GetName()}) + self:GetParent(self).onafterRTB( self, Defender, From, Event, To ) + + local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER + Dispatcher:ClearDefenderTaskTarget( Defender ) end - - if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2A_DISPATCHER.Landing.NearAirbase then - Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender ) - Defender:Destroy() + + --- @param #AI_A2A_DISPATCHER self + function Fsm:onafterLostControl( Defender, From, Event, To ) + self:F({"GCI LostControl", Defender:GetName()}) + self:GetParent(self).onafterHome( self, Defender, From, Event, To ) + + local Dispatcher = Fsm:GetDispatcher() -- #AI_A2A_DISPATCHER + local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) + if Defender:IsAboveRunway() then + Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender ) + Defender:Destroy() + end end - end - end -- if DefenderGCI then - end -- while ( DefendersNeeded > 0 ) do + + --- @param #AI_A2A_DISPATCHER self + function Fsm:onafterHome( Defender, From, Event, To, Action ) + self:F({"GCI Home", Defender:GetName()}) + self:GetParent(self).onafterHome( self, Defender, From, Event, To ) + + local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER + local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) + + if Action and Action == "Destroy" then + Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender ) + Defender:Destroy() + end + + if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2A_DISPATCHER.Landing.NearAirbase then + Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender ) + Defender:Destroy() + end + end + end -- if DefenderGCI then + end -- while ( DefendersNeeded > 0 ) do + end + else + -- No more resources, try something else. + -- Subject for a later enhancement to try to depart from another squadron and disable this one. + BreakLoop = true + break end else - -- No more resources, try something else. - -- Subject for a later enhancement to try to depart from another squadron and disable this one. - BreakLoop = true + -- There isn't any closest airbase anymore, break the loop. break end - else - -- There isn't any closest airbase anymore, break the loop. - break - end - end -- if DefenderSquadron then + end -- if DefenderSquadron then + end -- if AttackerUnit end