From 169c5a674c4c3a66ce9541d2a67b26ad73e00d76 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 25 Nov 2019 11:50:07 +0100 Subject: [PATCH] Fixes AI_PATROL: - Target unit is nil. Issue #1234 DETECTION: - ReportFriendliesNearBy ForEachPlayer added nil check. CONTROLLABLE: - Added IsHelicopter() - Added OptionRestrictBurner() AI_A2A_Cap - AtteckUnit not nil check. AI_A2A_Dispatcher: - DefenderGroup not nil and alive check #1228 AI_A2A_GCICAP: - AttackCoordinate nil check --- Moose Development/Moose/AI/AI_A2A_Cap.lua | 3 +- .../Moose/AI/AI_A2A_Dispatcher.lua | 132 ++++++++++-------- Moose Development/Moose/AI/AI_Patrol.lua | 26 ++-- .../Moose/Functional/Detection.lua | 42 +++--- .../Moose/Wrapper/Controllable.lua | 45 ++++++ 5 files changed, 160 insertions(+), 88 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua index d44d9763c..ae4171ae5 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -200,8 +200,7 @@ function AI_A2A_CAP:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageA 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 + if AttackUnit and 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 self:T( { "Attacking Task:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsAir() } ) diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index d25dc2ce9..26da1d54c 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -3231,65 +3231,73 @@ do -- AI_A2A_DISPATCHER self:SetDefenderTask( SquadronName, DefenderCAP, "CAP", AI_A2A_Fsm ) function AI_A2A_Fsm:onafterTakeoff( DefenderGroup, From, Event, To ) - self:F({"CAP Takeoff", DefenderGroup:GetName()}) - --self:GetParent(self).onafterBirth( self, Defender, From, Event, To ) - - local DefenderName = DefenderGroup:GetCallsign() - local Dispatcher = AI_A2A_Fsm:GetDispatcher() -- #AI_A2A_DISPATCHER - local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup ) - - if Squadron then - Dispatcher:MessageToPlayers( Squadron, DefenderName .. " Wheels up.", DefenderGroup ) - AI_A2A_Fsm:__Patrol( 2 ) -- Start Patrolling + -- Issue GetCallsign() returns nil, see https://github.com/FlightControl-Master/MOOSE/issues/1228 + if DefenderGroup and DefenderGroup:IsAlive() then + self:F({"CAP Takeoff", DefenderGroup:GetName()}) + --self:GetParent(self).onafterBirth( self, Defender, From, Event, To ) + + local DefenderName = DefenderGroup:GetCallsign() + local Dispatcher = AI_A2A_Fsm:GetDispatcher() -- #AI_A2A_DISPATCHER + local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup ) + + if Squadron then + Dispatcher:MessageToPlayers( Squadron, DefenderName .. " Wheels up.", DefenderGroup ) + AI_A2A_Fsm:__Patrol( 2 ) -- Start Patrolling + end end end function AI_A2A_Fsm:onafterPatrolRoute( DefenderGroup, From, Event, To ) - self:F({"CAP PatrolRoute", DefenderGroup:GetName()}) - self:GetParent(self).onafterPatrolRoute( self, DefenderGroup, From, Event, To ) - - local DefenderName = DefenderGroup:GetCallsign() - local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER - local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup ) - if Squadron then - Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", patrolling.", DefenderGroup ) + if DefenderGroup and DefenderGroup:IsAlive() then + self:F({"CAP PatrolRoute", DefenderGroup:GetName()}) + self:GetParent(self).onafterPatrolRoute( self, DefenderGroup, From, Event, To ) + + local DefenderName = DefenderGroup:GetCallsign() + local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER + local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup ) + if Squadron then + Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", patrolling.", DefenderGroup ) + end + + Dispatcher:ClearDefenderTaskTarget( DefenderGroup ) end - - Dispatcher:ClearDefenderTaskTarget( DefenderGroup ) end function AI_A2A_Fsm:onafterRTB( DefenderGroup, From, Event, To ) - - self:F({"CAP RTB", DefenderGroup:GetName()}) - - self:GetParent(self).onafterRTB( self, DefenderGroup, From, Event, To ) - - local DefenderName = DefenderGroup:GetCallsign() - local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER - local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup ) - if Squadron then - Dispatcher:MessageToPlayers( Squadron, DefenderName .. " returning to base.", DefenderGroup ) + if DefenderGroup and DefenderGroup:IsAlive() then + self:F({"CAP RTB", DefenderGroup:GetName()}) + + self:GetParent(self).onafterRTB( self, DefenderGroup, From, Event, To ) + + local DefenderName = DefenderGroup:GetCallsign() + local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER + local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup ) + if Squadron then + Dispatcher:MessageToPlayers( Squadron, DefenderName .. " returning to base.", DefenderGroup ) + end + Dispatcher:ClearDefenderTaskTarget( DefenderGroup ) end - Dispatcher:ClearDefenderTaskTarget( DefenderGroup ) end --- @param #AI_A2A_DISPATCHER self function AI_A2A_Fsm:onafterHome( Defender, From, Event, To, Action ) - self:F({"CAP 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() - Dispatcher:ParkDefender( Squadron ) + if Defender and Defender:IsAlive() then + self:F({"CAP 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() + Dispatcher:ParkDefender( Squadron ) + end end end end @@ -3636,22 +3644,31 @@ do -- AI_A2A_DISPATCHER --- Assigns A2G AI Tasks in relation to the detected items. -- @param #AI_A2G_DISPATCHER self function AI_A2A_DISPATCHER:Order( DetectedItem ) - local AttackCoordinate = self.Detection:GetDetectedItemCoordinate( DetectedItem ) + + local detection=self.Detection -- Functional.Detection#DETECTION_AREAS local ShortestDistance = 999999999 + + -- Get coordinate (or nil). + local AttackCoordinate = detection:GetDetectedItemCoordinate( DetectedItem ) + + -- Issue https://github.com/FlightControl-Master/MOOSE/issues/1232 + if AttackCoordinate then - for DefenderSquadronName, DefenderSquadron in pairs( self.DefenderSquadrons ) do - - self:I( { DefenderSquadron = DefenderSquadron.Name } ) - - local Airbase = DefenderSquadron.Airbase - local AirbaseCoordinate = Airbase:GetCoordinate() - - local EvaluateDistance = AttackCoordinate:Get2DDistance( AirbaseCoordinate ) + for DefenderSquadronName, DefenderSquadron in pairs( self.DefenderSquadrons ) do - if EvaluateDistance <= ShortestDistance then - ShortestDistance = EvaluateDistance + self:I( { DefenderSquadron = DefenderSquadron.Name } ) + + local Airbase = DefenderSquadron.Airbase + local AirbaseCoordinate = Airbase:GetCoordinate() + + local EvaluateDistance = AttackCoordinate:Get2DDistance( AirbaseCoordinate ) + + if EvaluateDistance <= ShortestDistance then + ShortestDistance = EvaluateDistance + end end + end return ShortestDistance @@ -3660,6 +3677,7 @@ do -- AI_A2A_DISPATCHER --- Shows the tactical display. -- @param #AI_A2A_DISPATCHER self + -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object. function AI_A2A_DISPATCHER:ShowTacticalDisplay( Detection ) local AreaMsg = {} diff --git a/Moose Development/Moose/AI/AI_Patrol.lua b/Moose Development/Moose/AI/AI_Patrol.lua index 6e2b6ff67..031d9aae8 100644 --- a/Moose Development/Moose/AI/AI_Patrol.lua +++ b/Moose Development/Moose/AI/AI_Patrol.lua @@ -667,21 +667,27 @@ function AI_PATROL_ZONE:onafterDetect( Controllable, From, Event, To ) if TargetObject and TargetObject:isExist() and TargetObject.id_ < 50000000 then local TargetUnit = UNIT:Find( TargetObject ) - local TargetUnitName = TargetUnit:GetName() - if self.DetectionZone then - if TargetUnit:IsInZone( self.DetectionZone ) then - self:T( {"Detected ", TargetUnit } ) + -- Check that target is alive due to issue https://github.com/FlightControl-Master/MOOSE/issues/1234 + if TargetUnit and TargetUnit:IsAlive() then + + local TargetUnitName = TargetUnit:GetName() + + if self.DetectionZone then + if TargetUnit:IsInZone( self.DetectionZone ) then + self:T( {"Detected ", TargetUnit } ) + if self.DetectedUnits[TargetUnit] == nil then + self.DetectedUnits[TargetUnit] = true + end + Detected = true + end + else if self.DetectedUnits[TargetUnit] == nil then self.DetectedUnits[TargetUnit] = true end - Detected = true + Detected = true end - else - if self.DetectedUnits[TargetUnit] == nil then - self.DetectedUnits[TargetUnit] = true - end - Detected = true + end end end diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 2c9c5d792..eb9b2e982 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -1438,27 +1438,31 @@ do -- DETECTION_BASE function( PlayerUnitName ) local PlayerUnit = UNIT:FindByName( PlayerUnitName ) - if PlayerUnit and PlayerUnit:GetCoordinate():IsInRadius( DetectedUnitCoord, self.FriendliesRange ) then - --if PlayerUnit and PlayerUnit:IsInZone(DetectionZone) then + -- Fix for issue https://github.com/FlightControl-Master/MOOSE/issues/1225 + if PlayerUnit and PlayerUnit:IsAlive() then + local coord=PlayerUnit:GetCoordinate() + + if coord and coord:IsInRadius( DetectedUnitCoord, self.FriendliesRange ) then - local PlayerUnitCategory = PlayerUnit:GetDesc().category - - if ( not self.FriendliesCategory ) or ( self.FriendliesCategory and ( self.FriendliesCategory == PlayerUnitCategory ) ) then - - local PlayerUnitName = PlayerUnit:GetName() + local PlayerUnitCategory = PlayerUnit:GetDesc().category - DetectedItem.PlayersNearBy = DetectedItem.PlayersNearBy or {} - DetectedItem.PlayersNearBy[PlayerUnitName] = PlayerUnit - - -- Friendlies are sorted per unit category. - DetectedItem.FriendliesNearBy = DetectedItem.FriendliesNearBy or {} - DetectedItem.FriendliesNearBy[PlayerUnitCategory] = DetectedItem.FriendliesNearBy[PlayerUnitCategory] or {} - DetectedItem.FriendliesNearBy[PlayerUnitCategory][PlayerUnitName] = PlayerUnit - - local Distance = DetectedUnitCoord:Get2DDistance( PlayerUnit:GetCoordinate() ) - DetectedItem.FriendliesDistance = DetectedItem.FriendliesDistance or {} - DetectedItem.FriendliesDistance[Distance] = PlayerUnit - + if ( not self.FriendliesCategory ) or ( self.FriendliesCategory and ( self.FriendliesCategory == PlayerUnitCategory ) ) then + + local PlayerUnitName = PlayerUnit:GetName() + + DetectedItem.PlayersNearBy = DetectedItem.PlayersNearBy or {} + DetectedItem.PlayersNearBy[PlayerUnitName] = PlayerUnit + + -- Friendlies are sorted per unit category. + DetectedItem.FriendliesNearBy = DetectedItem.FriendliesNearBy or {} + DetectedItem.FriendliesNearBy[PlayerUnitCategory] = DetectedItem.FriendliesNearBy[PlayerUnitCategory] or {} + DetectedItem.FriendliesNearBy[PlayerUnitCategory][PlayerUnitName] = PlayerUnit + + local Distance = DetectedUnitCoord:Get2DDistance( PlayerUnit:GetCoordinate() ) + DetectedItem.FriendliesDistance = DetectedItem.FriendliesDistance or {} + DetectedItem.FriendliesDistance[Distance] = PlayerUnit + + end end end end diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index b5d773b98..b42085516 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -3480,3 +3480,48 @@ function CONTROLLABLE:IsAirPlane() return nil end + +--- Returns if the Controllable contains Helicopters. +-- @param #CONTROLLABLE self +-- @return #boolean true if Controllable contains Helicopters. +function CONTROLLABLE:IsHelicopter() + self:F2() + + local DCSObject = self:GetDCSObject() + + if DCSObject then + local Category = DCSObject:getDesc().category + return Category == Unit.Category.HELICOPTER + end + + return nil +end + +--- Sets Controllable Option for Restriction of Afterburner. +-- @param #CONTROLLABLE self +-- @param #boolean RestrictBurner If true, restrict burner. If false or nil, allow (unrestrict) burner. +function CONTROLLABLE:OptionRestrictBurner(RestrictBurner) + self:F2({self.ControllableName}) + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + local Controller = self:_GetController() + + if Controller then + + -- Issue https://github.com/FlightControl-Master/MOOSE/issues/1216 + if RestrictBurner == true then + if self:IsAir() then + Controller:setOption(16, true) + end + else + if self:IsAir() then + Controller:setOption(16, false) + end + end + + end + end + +end