From 6f13aa2c5b0691ba0b287d05b6dcc401af7fb8af Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sun, 3 Mar 2019 19:44:39 +0100 Subject: [PATCH] These changes will blast the hell out of A2G... this is going to be great. --- Moose Development/Moose/AI/AI_A2G_BAI.lua | 2 +- Moose Development/Moose/AI/AI_A2G_CAS.lua | 2 +- .../Moose/AI/AI_A2G_Dispatcher.lua | 175 ++++++++++-------- Moose Development/Moose/AI/AI_A2G_SEAD.lua | 2 +- 4 files changed, 98 insertions(+), 83 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2G_BAI.lua b/Moose Development/Moose/AI/AI_A2G_BAI.lua index 79871ba52..027474c2c 100644 --- a/Moose Development/Moose/AI/AI_A2G_BAI.lua +++ b/Moose Development/Moose/AI/AI_A2G_BAI.lua @@ -144,7 +144,7 @@ function AI_A2G_BAI:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit if AttackUnit then if AttackUnit:IsAlive() and AttackUnit:IsGround() then self:T( { "BAI Unit:", AttackUnit:GetName() } ) - AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, false, false, nil, nil, EngageAltitude ) + AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, true, false, nil, nil, EngageAltitude ) end end end diff --git a/Moose Development/Moose/AI/AI_A2G_CAS.lua b/Moose Development/Moose/AI/AI_A2G_CAS.lua index 54e677576..221341608 100644 --- a/Moose Development/Moose/AI/AI_A2G_CAS.lua +++ b/Moose Development/Moose/AI/AI_A2G_CAS.lua @@ -141,7 +141,7 @@ function AI_A2G_CAS:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit if AttackUnit then if AttackUnit:IsAlive() and AttackUnit:IsGround() then self:T( { "CAS Unit:", AttackUnit:GetName() } ) - AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, false, false, nil, nil, EngageAltitude ) + AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, true, false, nil, nil, EngageAltitude ) end end end diff --git a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua index 8cde9e245..abbfd61ff 100644 --- a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua @@ -3169,14 +3169,13 @@ do -- AI_A2G_DISPATCHER --- -- @param #AI_A2G_DISPATCHER self - function AI_A2G_DISPATCHER:CountDefendersEngaged( AttackerDetection ) + function AI_A2G_DISPATCHER:CountDefendersEngaged( AttackerDetection, AttackerCount ) -- First, count the active AIGroups Units, targetting the DetectedSet local DefendersEngaged = 0 local DefendersTotal = 0 local AttackerSet = AttackerDetection.Set - local AttackerCount = AttackerSet:Count() local DefendersMissing = AttackerCount --DetectedSet:Flush() @@ -3628,13 +3627,64 @@ do -- AI_A2G_DISPATCHER --- -- @param #AI_A2G_DISPATCHER self - function AI_A2G_DISPATCHER:onafterDefend( From, Event, To, AttackerDetection, DefendersTotal, DefendersEngaged, DefendersMissing, DefenderFriendlies, DefenseTaskType ) + function AI_A2G_DISPATCHER:HasDefenseLine( DefenseCoordinate, DetectedItem ) - self:F( { From, Event, To, AttackerDetection.Index, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing, DefenderFriendlies = DefenderFriendlies } ) + local AttackCoordinate = self.Detection:GetDetectedItemCoordinate( DetectedItem ) + local EvaluateDistance = AttackCoordinate:Get2DDistance( DefenseCoordinate ) - AttackerDetection.Type = DefenseTaskType -- This is set to report the task type in the status panel. + -- Now check if this coordinate is not in a danger zone, meaning, that the attack line is not crossing other coordinates. + -- (y1 – y2)x + (x2 – x1)y + (x1y2 – x2y1) = 0 + + local c1 = DefenseCoordinate + local c2 = AttackCoordinate + + local a = c1.z - c2.z -- Calculate a + local b = c2.x - c1.x -- Calculate b + local c = c1.x * c2.z - c2.x * c1.z -- calculate c + + local ok = true + + -- Now we check if each coordinate radius of about 30km of each attack is crossing a defense line. If yes, then this is not a good attack! + for AttackItemID, CheckAttackItem in pairs( self.Detection:GetDetectedItems() ) do + + -- Only compare other detected coordinates. + if AttackItemID ~= DetectedItem.ID then + + local CheckAttackCoordinate = self.Detection:GetDetectedItemCoordinate( CheckAttackItem ) + + local x = CheckAttackCoordinate.x + local y = CheckAttackCoordinate.z + local r = 8000 + + -- now we check if the coordinate is intersecting with the defense line. + + local IntersectDistance = ( math.abs( a * x + b * y + c ) ) / math.sqrt( a * a + b * b ) + self:F( { IntersectDistance = IntersectDistance, x = x, y = y } ) + + local IntersectAttackDistance = CheckAttackCoordinate:Get2DDistance( DefenseCoordinate ) + + self:F( { IntersectAttackDistance=IntersectAttackDistance, EvaluateDistance=EvaluateDistance } ) + + -- If the distance of the attack coordinate is larger than the test radius; then the line intersects, and this is not a good coordinate. + if IntersectDistance < r and IntersectAttackDistance < EvaluateDistance then + ok = false + break + end + end + end + + return ok + end - local AttackerSet = AttackerDetection.Set + --- + -- @param #AI_A2G_DISPATCHER self + function AI_A2G_DISPATCHER:onafterDefend( From, Event, To, DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, DefenderFriendlies, DefenseTaskType ) + + self:F( { From, Event, To, DetectedItem.Index, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing, DefenderFriendlies = DefenderFriendlies } ) + + DetectedItem.Type = DefenseTaskType -- This is set to report the task type in the status panel. + + local AttackerSet = DetectedItem.Set local AttackerUnit = AttackerSet:GetFirst() if AttackerUnit and AttackerUnit:IsAlive() then @@ -3642,18 +3692,25 @@ do -- AI_A2G_DISPATCHER local DefenderCount = 0 for DefenderID, DefenderGroup in pairs( DefenderFriendlies or {} ) do - - local SquadronName = self:GetDefenderTask( DefenderGroup ).SquadronName - local SquadronOverhead = self:GetSquadronOverhead( SquadronName ) - local Fsm = self:GetDefenderTaskFsm( DefenderGroup ) - Fsm:Engage( AttackerSet ) -- Engage on the TargetSetUnit - - self:SetDefenderTaskTarget( DefenderGroup, AttackerDetection ) + -- Here we check if the defenders have a defense line to the attackers. + -- If the attackers are behind enemy lines or too close to an other defense line; then don´t engage. + local DefenseCoordinate = DefenderGroup:GetCoordinate() + local HasDefenseLine = self:HasDefenseLine( DefenseCoordinate, DetectedItem ) - local DefenderGroupSize = DefenderGroup:GetSize() - DefendersMissing = DefendersMissing - DefenderGroupSize / SquadronOverhead - DefendersTotal = DefendersTotal + DefenderGroupSize / SquadronOverhead + if HasDefenseLine == true then + local SquadronName = self:GetDefenderTask( DefenderGroup ).SquadronName + local SquadronOverhead = self:GetSquadronOverhead( SquadronName ) + + local Fsm = self:GetDefenderTaskFsm( DefenderGroup ) + Fsm:Engage( AttackerSet ) -- Engage on the TargetSetUnit + + self:SetDefenderTaskTarget( DefenderGroup, DetectedItem ) + + local DefenderGroupSize = DefenderGroup:GetSize() + DefendersMissing = DefendersMissing - DefenderGroupSize / SquadronOverhead + DefendersTotal = DefendersTotal + DefenderGroupSize / SquadronOverhead + end if DefendersMissing <= 0 then break @@ -3676,21 +3733,26 @@ do -- AI_A2G_DISPATCHER if DefenderSquadron[DefenseTaskType] then - local SpawnCoord = DefenderSquadron.Airbase:GetCoordinate() -- Core.Point#COORDINATE + local AirbaseCoordinate = DefenderSquadron.Airbase:GetCoordinate() -- Core.Point#COORDINATE local AttackerCoord = AttackerUnit:GetCoordinate() - local InterceptCoord = AttackerDetection.InterceptCoord + local InterceptCoord = DetectedItem.InterceptCoord self:F( { InterceptCoord = InterceptCoord } ) if InterceptCoord then - local InterceptDistance = SpawnCoord:Get2DDistance( InterceptCoord ) - local AirbaseDistance = SpawnCoord:Get2DDistance( AttackerCoord ) + local InterceptDistance = AirbaseCoordinate:Get2DDistance( InterceptCoord ) + local AirbaseDistance = AirbaseCoordinate:Get2DDistance( AttackerCoord ) self:F( { InterceptDistance = InterceptDistance, AirbaseDistance = AirbaseDistance, InterceptCoord = InterceptCoord } ) 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.DefenseRadius then - ClosestDistance = InterceptDistance - ClosestDefenderSquadronName = SquadronName + + -- Check if there is a defense line... + local HasDefenseLine = self:HasDefenseLine( AirbaseCoordinate, DetectedItem ) + if HasDefenseLine == true then + ClosestDistance = InterceptDistance + ClosestDefenderSquadronName = SquadronName + end end end end @@ -3735,7 +3797,7 @@ do -- AI_A2G_DISPATCHER end while ( DefendersNeeded > 0 ) do - self:ResourceQueue( false, DefenderSquadron, DefendersNeeded, Defense, DefenseTaskType, AttackerDetection, ClosestDefenderSquadronName ) + self:ResourceQueue( false, DefenderSquadron, DefendersNeeded, Defense, DefenseTaskType, DetectedItem, ClosestDefenderSquadronName ) DefendersNeeded = DefendersNeeded - DefenderGrouping DefenderCount = DefenderCount - DefenderGrouping / DefenderOverhead end -- while ( DefendersNeeded > 0 ) do @@ -3764,13 +3826,12 @@ do -- AI_A2G_DISPATCHER self:F( { DetectedItem.ItemID } ) local AttackerSet = DetectedItem.Set -- Core.Set#SET_UNIT - local AttackerCount = AttackerSet:Count() - local IsSEAD = AttackerSet:HasSEAD() -- Is the AttackerSet a SEAD group? + local AttackerCount = AttackerSet:HasSEAD() -- Is the AttackerSet a SEAD group, then the amount of radar emitters will be returned; that need to be attacked. - if ( IsSEAD > 0 ) then + if ( AttackerCount > 0 ) then -- First, count the active defenders, engaging the DetectedItem. - local DefendersTotal, DefendersEngaged, DefendersMissing = self:CountDefendersEngaged( DetectedItem ) + local DefendersTotal, DefendersEngaged, DefendersMissing = self:CountDefendersEngaged( DetectedItem, AttackerCount ) self:F( { AttackerCount = AttackerCount, DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } ) @@ -3805,7 +3866,7 @@ do -- AI_A2G_DISPATCHER if IsCas == true then -- First, count the active defenders, engaging the DetectedItem. - local DefendersTotal, DefendersEngaged, DefendersMissing = self:CountDefendersEngaged( DetectedItem ) + local DefendersTotal, DefendersEngaged, DefendersMissing = self:CountDefendersEngaged( DetectedItem, AttackerCount ) self:F( { AttackerCount = AttackerCount, DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } ) @@ -3838,7 +3899,7 @@ do -- AI_A2G_DISPATCHER if IsBai == true then -- First, count the active defenders, engaging the DetectedItem. - local DefendersTotal, DefendersEngaged, DefendersMissing = self:CountDefendersEngaged( DetectedItem ) + local DefendersTotal, DefendersEngaged, DefendersMissing = self:CountDefendersEngaged( DetectedItem, AttackerCount ) self:F( { AttackerCount = AttackerCount, DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } ) @@ -3854,6 +3915,8 @@ do -- AI_A2G_DISPATCHER end + + --- Assigns A2G AI Tasks in relation to the detected items. -- @param #AI_A2G_DISPATCHER self -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object. @@ -3900,7 +3963,6 @@ do -- AI_A2G_DISPATCHER local Report = REPORT:New( "\nTactical Overview" ) local DefenderGroupCount = 0 - local Delay = 0 -- We need to implement a delay for each action because the spawning on airbases get confused if done too quick. local DefendersTotal = 0 @@ -3940,52 +4002,8 @@ do -- AI_A2G_DISPATCHER self:F( { DistanceProbability = DistanceProbability, DefenseProbability = DefenseProbability } ) if DefenseProbability <= DistanceProbability / ( 300 / 30 ) then - - -- Now check if this coordinate is not in a danger zone, meaning, that the attack line is not crossing other coordinates. - -- (y1 – y2)x + (x2 – x1)y + (x1y2 – x2y1) = 0 - - local c1 = DefenseCoordinate - local c2 = AttackCoordinate - - local a = c1.z - c2.z -- Calculate a - local b = c2.x - c1.x -- Calculate b - local c = c1.x * c2.z - c2.x * c1.z -- calculate c - - local ok = true - - -- Now we check if each coordinate radius of about 30km of each attack is crossing a defense line. If yes, then this is not a good attack! - for AttackItemID, CheckAttackItem in pairs( Detection:GetDetectedItems() ) do - - -- Only compare other detected coordinates. - if AttackItemID ~= DetectedItemID then - - local CheckAttackCoordinate = self.Detection:GetDetectedItemCoordinate( CheckAttackItem ) - - local x = CheckAttackCoordinate.x - local y = CheckAttackCoordinate.z - local r = 8000 - - -- now we check if the coordinate is intersecting with the defense line. - - local IntersectDistance = ( math.abs( a * x + b * y + c ) ) / math.sqrt( a * a + b * b ) - self:F( { IntersectDistance = IntersectDistance, x = x, y = y } ) - - local IntersectAttackDistance = CheckAttackCoordinate:Get2DDistance( DefenseCoordinate ) - - self:F( { IntersectAttackDistance=IntersectAttackDistance, EvaluateDistance=EvaluateDistance } ) - - -- If the distance of the attack coordinate is larger than the test radius; then the line intersects, and this is not a good coordinate. - if IntersectDistance < r and IntersectAttackDistance < EvaluateDistance then - ok = false - break - end - end - end - - if ok == true then - EngageCoordinate = DefenseCoordinate - break - end + EngageCoordinate = DefenseCoordinate + break end end end @@ -3996,7 +4014,6 @@ do -- AI_A2G_DISPATCHER if DefendersMissing and DefendersMissing > 0 then self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } ) self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "SEAD", EngageCoordinate ) - Delay = Delay + 1 end end @@ -4005,7 +4022,6 @@ do -- AI_A2G_DISPATCHER if DefendersMissing and DefendersMissing > 0 then self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } ) self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "CAS", EngageCoordinate ) - Delay = Delay + 1 end end @@ -4014,7 +4030,6 @@ do -- AI_A2G_DISPATCHER if DefendersMissing and DefendersMissing > 0 then self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } ) self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "BAI", EngageCoordinate ) - Delay = Delay + 1 end end end @@ -4030,7 +4045,7 @@ do -- AI_A2G_DISPATCHER if self.TacticalDisplay then -- Show tactical situation local ThreatLevel = DetectedItem.Set:CalculateThreatLevelA2G() - Report:Add( string.format( " - %s ( %s ): ( #%d - %4s ) %s" , DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "■", ThreatLevel ) ) ) + Report:Add( string.format( " - %1s%s ( %4s ): ( #%d - %4s ) %s" , ( DetectedItem.IsDetected == true ) and "!" or " ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "■", ThreatLevel ) ) ) for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do local Defender = Defender -- Wrapper.Group#GROUP if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then diff --git a/Moose Development/Moose/AI/AI_A2G_SEAD.lua b/Moose Development/Moose/AI/AI_A2G_SEAD.lua index e47d09449..77a69ca10 100644 --- a/Moose Development/Moose/AI/AI_A2G_SEAD.lua +++ b/Moose Development/Moose/AI/AI_A2G_SEAD.lua @@ -189,7 +189,7 @@ function AI_A2G_SEAD:onafterEngage( DefenderGroup, From, Event, To, AttackSetUni local HasRadar = AttackUnit:HasSEAD() if HasRadar then self:F( { "SEAD Unit:", AttackUnit:GetName() } ) - AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, false, false, nil, nil, EngageAltitude ) + AttackUnitTasks[#AttackUnitTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit, true, false, nil, nil, EngageAltitude ) end end end