mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
-- New SEAD, BAI and CAS files.
-- Correct handling of task assignments. -- Added Weapon stuff in DCS.lua. -- Dispatcher optimizations.
This commit is contained in:
parent
921ec8732c
commit
d098930351
@ -489,7 +489,7 @@ function AI_A2A:onafterStatus()
|
||||
not self:Is( "Fuel" ) and
|
||||
not self:Is( "Damaged" ) and
|
||||
not self:Is( "Home" ) then
|
||||
if self.IdleCount >= 2 then
|
||||
if self.IdleCount >= 3 then
|
||||
if Damage ~= InitialLife then
|
||||
self:Damaged()
|
||||
else
|
||||
|
||||
172
Moose Development/Moose/AI/AI_A2G_BAI.lua
Normal file
172
Moose Development/Moose/AI/AI_A2G_BAI.lua
Normal file
@ -0,0 +1,172 @@
|
||||
--- **AI** -- Models the process of air to ground BAI engagement for airplanes and helicopters.
|
||||
--
|
||||
-- This is a class used in the @{AI_A2G_Dispatcher}.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module AI.AI_A2G_BAI
|
||||
-- @image AI_Air_To_Ground_Engage.JPG
|
||||
|
||||
|
||||
|
||||
--- @type AI_A2G_BAI
|
||||
-- @extends AI.AI_A2A_Engage#AI_A2A_Engage
|
||||
|
||||
|
||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_A2G_BAI
|
||||
AI_A2G_BAI = {
|
||||
ClassName = "AI_A2G_BAI",
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- Creates a new AI_A2G_BAI object
|
||||
-- @param #AI_A2G_BAI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
-- @return #AI_A2G_BAI
|
||||
function AI_A2G_BAI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed ) ) -- #AI_A2G_BAI
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- onafter event handler for Start event.
|
||||
-- @param #AI_A2G_BAI 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_BAI:onafterStart( AIGroup, From, Event, To )
|
||||
|
||||
self:GetParent( self ).onafterStart( self, AIGroup, From, Event, To )
|
||||
AIGroup:HandleEvent( EVENTS.Takeoff, nil, self )
|
||||
|
||||
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 )
|
||||
|
||||
self:F( { DefenderGroup, From, Event, To, AttackSetUnit} )
|
||||
|
||||
local DefenderGroupName = DefenderGroup:GetName()
|
||||
|
||||
self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT
|
||||
|
||||
local AttackCount = self.AttackSetUnit:Count()
|
||||
|
||||
if AttackCount > 0 then
|
||||
|
||||
if DefenderGroup:IsAlive() then
|
||||
|
||||
-- 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:GetCoordinate()
|
||||
local TargetCoord = self.AttackSetUnit:GetFirst():GetCoordinate()
|
||||
|
||||
local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord )
|
||||
|
||||
if TargetDistance >= 50000 then
|
||||
|
||||
local EngageRoute = {}
|
||||
|
||||
local ToTargetSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed )
|
||||
|
||||
--- Calculate the target route point.
|
||||
|
||||
local FromWP = DefenderCoord:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
EngageRoute[#EngageRoute+1] = FromWP
|
||||
|
||||
local ToCoord = self.AttackSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetTargetDistance( ToCoord ) -- For RTB status check
|
||||
|
||||
local FromEngageAngle = ToCoord:GetAngleDegrees( ToCoord:GetDirectionVec3( DefenderCoord ) )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToWP = ToCoord:Translate( 50000, FromEngageAngle ):WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
self:F( { Angle = FromEngageAngle, ToTargetSpeed = ToTargetSpeed } )
|
||||
self:F( { self.EngageMinSpeed, self.EngageMaxSpeed, ToTargetSpeed } )
|
||||
|
||||
EngageRoute[#EngageRoute+1] = ToWP
|
||||
|
||||
local AttackTasks = {}
|
||||
|
||||
for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do
|
||||
if AttackUnit:IsAlive() and AttackUnit:IsGround() then
|
||||
self:T( { "Engage Unit evaluation:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsGround() } )
|
||||
local HasRadar = AttackUnit:HasSEAD()
|
||||
if HasRadar then
|
||||
self:T( { "Eliminating Unit:", AttackUnit:GetName() } )
|
||||
AttackTasks[#AttackTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #AttackTasks == 0 then
|
||||
self:E( DefenderGroupName .. ": No targets found -> Going RTB")
|
||||
self:Return()
|
||||
self:__RTB( 0.5 )
|
||||
else
|
||||
DefenderGroup:OptionROEOpenFire()
|
||||
DefenderGroup:OptionROTEvadeFire()
|
||||
|
||||
AttackTasks[#AttackTasks+1] = DefenderGroup:TaskFunction( "AI_A2G_ENGAGE.EngageRoute", self )
|
||||
EngageRoute[#EngageRoute].task = DefenderGroup:TaskCombo( AttackTasks )
|
||||
end
|
||||
|
||||
DefenderGroup:Route( EngageRoute, 0 )
|
||||
|
||||
else
|
||||
local AttackTasks = {}
|
||||
--local AttackUnit = self.AttackSetUnit:GetRandom() -- Wrapper.Unit#UNIT
|
||||
for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do
|
||||
if AttackUnit:IsAlive() and AttackUnit:IsGround() then
|
||||
local HasRadar = AttackUnit:HasSEAD()
|
||||
if HasRadar then
|
||||
self:T( { "Eliminating Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsGround() } )
|
||||
AttackTasks[#AttackTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit )
|
||||
end
|
||||
end
|
||||
end
|
||||
AttackTasks[#AttackTasks+1] = DefenderGroup:TaskFunction( "AI_A2G_ENGAGE.EngageRoute", self )
|
||||
local DefenderTask = DefenderGroup:TaskCombo( AttackTasks )
|
||||
DefenderGroup:SetTask( DefenderTask, 0 )
|
||||
end
|
||||
end
|
||||
else
|
||||
self:E( DefenderGroupName .. ": No targets found -> Going RTB")
|
||||
self:Return()
|
||||
self:__RTB( 0.5 )
|
||||
end
|
||||
end
|
||||
173
Moose Development/Moose/AI/AI_A2G_CAS.lua
Normal file
173
Moose Development/Moose/AI/AI_A2G_CAS.lua
Normal file
@ -0,0 +1,173 @@
|
||||
--- **AI** -- Models the process of air to ground engagement for airplanes and helicopters.
|
||||
--
|
||||
-- This is a class used in the @{AI_A2G_Dispatcher}.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module AI.AI_A2G_CAS
|
||||
-- @image AI_Air_To_Ground_Engage.JPG
|
||||
|
||||
|
||||
|
||||
--- @type AI_A2G_CAS
|
||||
-- @extends AI.AI_A2G_Engage#AI_A2G_Engage
|
||||
|
||||
|
||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_A2G_CAS
|
||||
AI_A2G_CAS = {
|
||||
ClassName = "AI_A2G_CAS",
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- Creates a new AI_A2G_CAS object
|
||||
-- @param #AI_A2G_CAS self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
-- @return #AI_A2G_CAS
|
||||
function AI_A2G_CAS:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed ) ) -- #AI_A2G_CAS
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- onafter event handler for Start event.
|
||||
-- @param #AI_A2G_CAS 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_CAS:onafterStart( AIGroup, From, Event, To )
|
||||
|
||||
self:GetParent( self ).onafterStart( self, AIGroup, From, Event, To )
|
||||
AIGroup:HandleEvent( EVENTS.Takeoff, nil, self )
|
||||
|
||||
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 )
|
||||
|
||||
self:F( { DefenderGroup, From, Event, To, AttackSetUnit} )
|
||||
|
||||
local DefenderGroupName = DefenderGroup:GetName()
|
||||
|
||||
self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT
|
||||
|
||||
local AttackCount = self.AttackSetUnit:Count()
|
||||
|
||||
if AttackCount > 0 then
|
||||
|
||||
if DefenderGroup:IsAlive() then
|
||||
|
||||
-- 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:GetCoordinate()
|
||||
local TargetCoord = self.AttackSetUnit:GetFirst():GetCoordinate()
|
||||
|
||||
local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord )
|
||||
|
||||
if TargetDistance >= 50000 then
|
||||
|
||||
local EngageRoute = {}
|
||||
|
||||
local ToTargetSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed )
|
||||
|
||||
--- Calculate the target route point.
|
||||
|
||||
local FromWP = DefenderCoord:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
EngageRoute[#EngageRoute+1] = FromWP
|
||||
|
||||
local ToCoord = self.AttackSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetTargetDistance( ToCoord ) -- For RTB status check
|
||||
|
||||
local FromEngageAngle = ToCoord:GetAngleDegrees( ToCoord:GetDirectionVec3( DefenderCoord ) )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToWP = ToCoord:Translate( 50000, FromEngageAngle ):WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
self:F( { Angle = FromEngageAngle, ToTargetSpeed = ToTargetSpeed } )
|
||||
self:F( { self.EngageMinSpeed, self.EngageMaxSpeed, ToTargetSpeed } )
|
||||
|
||||
EngageRoute[#EngageRoute+1] = ToWP
|
||||
|
||||
local AttackTasks = {}
|
||||
|
||||
for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do
|
||||
if AttackUnit:IsAlive() and AttackUnit:IsGround() then
|
||||
self:T( { "Engage Unit evaluation:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsGround() } )
|
||||
local HasRadar = AttackUnit:HasSEAD()
|
||||
if HasRadar then
|
||||
self:T( { "Eliminating Unit:", AttackUnit:GetName() } )
|
||||
AttackTasks[#AttackTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #AttackTasks == 0 then
|
||||
self:E( DefenderGroupName .. ": No targets found -> Going RTB")
|
||||
self:Return()
|
||||
self:__RTB( 0.5 )
|
||||
else
|
||||
DefenderGroup:OptionROEOpenFire()
|
||||
DefenderGroup:OptionROTEvadeFire()
|
||||
|
||||
AttackTasks[#AttackTasks+1] = DefenderGroup:TaskFunction( "AI_A2G_ENGAGE.EngageRoute", self )
|
||||
EngageRoute[#EngageRoute].task = DefenderGroup:TaskCombo( AttackTasks )
|
||||
end
|
||||
|
||||
DefenderGroup:Route( EngageRoute, 0 )
|
||||
|
||||
else
|
||||
local AttackTasks = {}
|
||||
--local AttackUnit = self.AttackSetUnit:GetRandom() -- Wrapper.Unit#UNIT
|
||||
for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do
|
||||
if AttackUnit:IsAlive() and AttackUnit:IsGround() then
|
||||
local HasRadar = AttackUnit:HasSEAD()
|
||||
if HasRadar then
|
||||
self:T( { "Eliminating Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsGround() } )
|
||||
AttackTasks[#AttackTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit )
|
||||
end
|
||||
end
|
||||
end
|
||||
AttackTasks[#AttackTasks+1] = DefenderGroup:TaskFunction( "AI_A2G_ENGAGE.EngageRoute", self )
|
||||
local DefenderTask = DefenderGroup:TaskCombo( AttackTasks )
|
||||
DefenderGroup:SetTask( DefenderTask, 0 )
|
||||
end
|
||||
end
|
||||
else
|
||||
self:E( DefenderGroupName .. ": No targets found -> Going RTB")
|
||||
self:Return()
|
||||
self:__RTB( 0.5 )
|
||||
end
|
||||
end
|
||||
|
||||
@ -810,6 +810,7 @@ do -- AI_A2G_DISPATCHER
|
||||
if Squadron then
|
||||
self:F( { SquadronName = Squadron.Name } )
|
||||
local LandingMethod = self:GetSquadronLanding( Squadron.Name )
|
||||
|
||||
if LandingMethod == AI_A2G_DISPATCHER.Landing.AtRunway then
|
||||
local DefenderSize = Defender:GetSize()
|
||||
if DefenderSize == 1 then
|
||||
@ -1395,6 +1396,8 @@ do -- AI_A2G_DISPATCHER
|
||||
local DefenderSquadron = self:GetSquadron( SquadronName )
|
||||
|
||||
DefenderSquadron.Uncontrolled = true
|
||||
self:SetSquadronTakeoffFromParkingCold( SquadronName )
|
||||
self:SetSquadronLandingAtEngineShutdown( SquadronName )
|
||||
|
||||
for SpawnTemplate, DefenderSpawn in pairs( self.DefenderSpawns ) do
|
||||
DefenderSpawn:InitUnControlled()
|
||||
@ -2856,13 +2859,16 @@ do -- AI_A2G_DISPATCHER
|
||||
if DefenderUnitIndex == 1 then
|
||||
DefenderPatrolTemplate = UTILS.DeepCopy( DefenderTemplate )
|
||||
self.DefenderPatrolIndex = self.DefenderPatrolIndex + 1
|
||||
DefenderPatrolTemplate.name = SquadronName .. "#" .. self.DefenderPatrolIndex .. "#" .. GroupName
|
||||
--DefenderPatrolTemplate.name = SquadronName .. "#" .. self.DefenderPatrolIndex .. "#" .. GroupName
|
||||
DefenderPatrolTemplate.name = GroupName
|
||||
DefenderName = DefenderPatrolTemplate.name
|
||||
else
|
||||
-- Add the unit in the template to the DefenderPatrolTemplate.
|
||||
local DefenderUnitTemplate = DefenderTemplate.units[1]
|
||||
DefenderPatrolTemplate.units[DefenderUnitIndex] = DefenderUnitTemplate
|
||||
end
|
||||
DefenderPatrolTemplate.units[DefenderUnitIndex].name = string.format( DefenderPatrolTemplate.name .. '-%02d', DefenderUnitIndex )
|
||||
DefenderPatrolTemplate.units[DefenderUnitIndex].unitId = nil
|
||||
DefenderUnitIndex = DefenderUnitIndex + 1
|
||||
DefenderSquadron.Resources[TemplateID][GroupName] = nil
|
||||
if DefenderUnitIndex > DefenderGrouping then
|
||||
@ -2880,8 +2886,8 @@ do -- AI_A2G_DISPATCHER
|
||||
DefenderPatrolTemplate.route.points[1].type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
|
||||
DefenderPatrolTemplate.route.points[1].action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
|
||||
local Defender = _DATABASE:Spawn( DefenderPatrolTemplate )
|
||||
|
||||
self:AddDefenderToSquadron( DefenderSquadron, Defender, DefenderGrouping )
|
||||
Defender:Activate()
|
||||
return Defender, DefenderGrouping
|
||||
end
|
||||
else
|
||||
@ -2993,6 +2999,8 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
self:F( { From, Event, To, AttackerDetection.Index, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing, DefenderFriendlies = DefenderFriendlies } )
|
||||
|
||||
AttackerDetection.Type = DefenseTaskType -- This is set to report the task type in the status panel.
|
||||
|
||||
local AttackerSet = AttackerDetection.Set
|
||||
local AttackerUnit = AttackerSet:GetFirst()
|
||||
|
||||
@ -3103,7 +3111,9 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
DefenderCount = DefenderCount - DefenderGrouping / DefenderOverhead
|
||||
|
||||
local Fsm = AI_A2G_ENGAGE:New( DefenderGroup, Defense.EngageMinSpeed, Defense.EngageMaxSpeed )
|
||||
local AI_A2G_ENGAGE = { SEAD = AI_A2G_SEAD, BAI = AI_A2G_BAI, CAS = AI_A2G_CAS }
|
||||
|
||||
local Fsm = AI_A2G_ENGAGE[DefenseTaskType]:New( DefenderGroup, Defense.EngageMinSpeed, Defense.EngageMaxSpeed ) -- AI.AI_A2G_ENGAGE
|
||||
Fsm:SetDispatcher( self )
|
||||
Fsm:SetHomeAirbase( DefenderSquadron.Airbase )
|
||||
Fsm:SetFuelThreshold( DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold, 60 )
|
||||
@ -3121,6 +3131,8 @@ do -- AI_A2G_DISPATCHER
|
||||
local Squadron = Dispatcher:GetSquadronFromDefender( Defender )
|
||||
local DefenderTarget = Dispatcher:GetDefenderTaskTarget( Defender )
|
||||
|
||||
self:F( { DefenderTarget = DefenderTarget } )
|
||||
|
||||
if DefenderTarget then
|
||||
Fsm:__Engage( 2, DefenderTarget.Set ) -- Engage on the TargetSetUnit
|
||||
end
|
||||
@ -3141,10 +3153,10 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
local Dispatcher = Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||
local Squadron = Dispatcher:GetSquadronFromDefender( Defender )
|
||||
if Defender:IsAboveRunway() then
|
||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||
Defender:Destroy()
|
||||
end
|
||||
--if Defender:IsAboveRunway() then
|
||||
--Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||
--Defender:Destroy()
|
||||
--end
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
@ -3298,8 +3310,8 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
for DefenderGroup, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
||||
local DefenderGroup = DefenderGroup -- Wrapper.Group#GROUP
|
||||
local DefenderTaskFsm = self:GetDefenderTaskFsm( DefenderGroup )
|
||||
if not DefenderGroup:IsAlive() then
|
||||
local DefenderTaskFsm = self:GetDefenderTaskFsm( DefenderGroup )
|
||||
self:F( { Defender = DefenderGroup:GetName(), DefenderState = DefenderTaskFsm:GetState() } )
|
||||
if not DefenderTaskFsm:Is( "Started" ) then
|
||||
self:ClearDefenderTask( DefenderGroup )
|
||||
@ -3312,10 +3324,10 @@ do -- AI_A2G_DISPATCHER
|
||||
self:ClearDefenderTaskTarget( DefenderGroup )
|
||||
else
|
||||
if DefenderTask.Target.Set then
|
||||
local AttackerCount = DefenderTask.Target.Set:Count()
|
||||
if AttackerCount == 0 then
|
||||
local TargetCount = DefenderTask.Target.Set:Count()
|
||||
if TargetCount == 0 then
|
||||
self:F( { "All Targets destroyed in Target, removing:", DefenderTask.Target.Index } )
|
||||
self:ClearDefenderTaskTarget( DefenderGroup )
|
||||
self:ClearDefenderTask( DefenderGroup )
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -3410,7 +3422,7 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
if self.TacticalDisplay then
|
||||
-- Show tactical situation
|
||||
Report:Add( string.format( "\n - Target %s ( %s ): ( #%d ) %s" , DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Set:GetObjectNames() ) )
|
||||
Report:Add( string.format( "\n - %s %s ( %s ): ( #%d ) %s" , DetectedItem.Type or " --- ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Set:GetObjectNames() ) )
|
||||
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
||||
local Defender = Defender -- Wrapper.Group#GROUP
|
||||
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
|
||||
--- @type AI_A2G_ENGAGE
|
||||
-- @extends AI.AI_A2A#AI_A2A
|
||||
-- @extends AI.AI_A2G#AI_A2G
|
||||
|
||||
|
||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||
@ -266,7 +266,8 @@ end
|
||||
-- @param #string To The To State string.
|
||||
function AI_A2G_ENGAGE:onafterStart( AIGroup, From, Event, To )
|
||||
|
||||
self:GetParent( self ).onafterStart( self, AIGroup, From, Event, To )
|
||||
self:GetParent( self, AI_A2G_ENGAGE ).onafterStart( self, AIGroup, From, Event, To )
|
||||
|
||||
AIGroup:HandleEvent( EVENTS.Takeoff, nil, self )
|
||||
|
||||
end
|
||||
@ -327,81 +328,14 @@ end
|
||||
|
||||
|
||||
--- @param #AI_A2G_ENGAGE self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The GroupGroup managed by the FSM.
|
||||
-- @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:onafterEngage( AIGroup, From, Event, To, AttackSetUnit )
|
||||
function AI_A2G_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit )
|
||||
|
||||
self:F( { AIGroup, From, Event, To, AttackSetUnit} )
|
||||
|
||||
self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT
|
||||
self:F( { DefenderGroup, From, Event, To, AttackSetUnit} )
|
||||
|
||||
local FirstAttackUnit = self.AttackSetUnit:GetFirst()
|
||||
|
||||
if FirstAttackUnit and FirstAttackUnit:IsAlive() then
|
||||
|
||||
if AIGroup:IsAlive() then
|
||||
|
||||
local EngageRoute = {}
|
||||
|
||||
local CurrentCoord = AIGroup:GetCoordinate()
|
||||
|
||||
--- Calculate the target route point.
|
||||
|
||||
local CurrentCoord = AIGroup:GetCoordinate()
|
||||
|
||||
local ToTargetCoord = self.AttackSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
|
||||
|
||||
local ToTargetSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed )
|
||||
local ToEngageAngle = CurrentCoord:GetAngleDegrees( CurrentCoord:GetDirectionVec3( ToTargetCoord ) )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToPatrolRoutePoint = CurrentCoord:Translate( 15000, ToEngageAngle ):WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
self:F( { Angle = ToEngageAngle, 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:IsGround() then
|
||||
self:T( { "Eliminating Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsGround() } )
|
||||
AttackTasks[#AttackTasks+1] = AIGroup:TaskAttackUnit( AttackUnit )
|
||||
end
|
||||
end
|
||||
|
||||
if #AttackTasks == 0 then
|
||||
self:E("No targets found -> Going RTB")
|
||||
self:Return()
|
||||
self:__RTB( 0.5 )
|
||||
else
|
||||
AIGroup:OptionROEOpenFire()
|
||||
AIGroup:OptionROTEvadeFire()
|
||||
|
||||
AttackTasks[#AttackTasks+1] = AIGroup:TaskFunction( "AI_A2G_ENGAGE.EngageRoute", self )
|
||||
EngageRoute[#EngageRoute].task = AIGroup:TaskCombo( AttackTasks )
|
||||
end
|
||||
|
||||
AIGroup:Route( EngageRoute, 0.5 )
|
||||
|
||||
end
|
||||
else
|
||||
self:E("No targets found -> Going RTB")
|
||||
self:Return()
|
||||
self:__RTB( 0.5 )
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_ENGAGE self
|
||||
|
||||
@ -112,7 +112,7 @@ AI_A2G_PATROL = {
|
||||
function AI_A2G_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, AI_A2A_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_A2G_PATROL
|
||||
local self = BASE:Inherit( self, AI_A2G:New( AIPatrol ) ) -- #AI_A2G_PATROL
|
||||
|
||||
self.Accomplished = false
|
||||
self.Engaging = false
|
||||
@ -290,7 +290,6 @@ end
|
||||
-- @param #string To The To State string.
|
||||
function AI_A2G_PATROL:onafterStart( AIPatrol, From, Event, To )
|
||||
|
||||
self:GetParent( self ).onafterStart( self, AIPatrol, From, Event, To )
|
||||
AIPatrol:HandleEvent( EVENTS.Takeoff, nil, self )
|
||||
|
||||
end
|
||||
|
||||
218
Moose Development/Moose/AI/AI_A2G_SEAD.lua
Normal file
218
Moose Development/Moose/AI/AI_A2G_SEAD.lua
Normal file
@ -0,0 +1,218 @@
|
||||
--- **AI** -- Models the process of air to ground SEAD engagement for airplanes and helicopters.
|
||||
--
|
||||
-- This is a class used in the @{AI_A2G_Dispatcher}.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module AI.AI_A2G_SEAD
|
||||
-- @image AI_Air_To_Ground_Engage.JPG
|
||||
|
||||
|
||||
|
||||
--- @type AI_A2G_SEAD
|
||||
-- @extends AI.AI_A2G_Engage#AI_A2G_Engage
|
||||
|
||||
|
||||
--- Implements the core functions to SEAD intruders. Use the Engage trigger to intercept intruders.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_A2G_SEAD is assigned a @{Wrapper.Group} and this must be done before the AI_A2G_SEAD process can be started using the **Start** event.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||
-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- This cycle will continue.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- When enemies are detected, the AI will automatically engage the enemy.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## 1. AI_A2G_SEAD constructor
|
||||
--
|
||||
-- * @{#AI_A2G_SEAD.New}(): Creates a new AI_A2G_SEAD object.
|
||||
--
|
||||
-- ## 3. Set the Range of Engagement
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional range can be set in meters,
|
||||
-- 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_SEAD.SetEngageRange}() to define that range.
|
||||
--
|
||||
-- ## 4. Set the Zone of Engagement
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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_SEAD.SetEngageZone}() to define that Zone.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_A2G_SEAD
|
||||
AI_A2G_SEAD = {
|
||||
ClassName = "AI_A2G_SEAD",
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- Creates a new AI_A2G_SEAD object
|
||||
-- @param #AI_A2G_SEAD self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
-- @return #AI_A2G_SEAD
|
||||
function AI_A2G_SEAD:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed ) ) -- #AI_A2G_SEAD
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @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 or self.AttackSetUnit -- Core.Set#SET_UNIT
|
||||
|
||||
local AttackCount = self.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 DefenderCoord = DefenderGroup:GetCoordinate()
|
||||
local TargetCoord = self.AttackSetUnit:GetFirst():GetCoordinate()
|
||||
|
||||
local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord )
|
||||
|
||||
-- if TargetDistance >= 50000 then
|
||||
|
||||
local EngageRoute = {}
|
||||
|
||||
local ToTargetSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed )
|
||||
|
||||
--- Calculate the target route point.
|
||||
|
||||
local FromWP = DefenderCoord:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
EngageRoute[#EngageRoute+1] = FromWP
|
||||
|
||||
local ToCoord = self.AttackSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetTargetDistance( ToCoord ) -- For RTB status check
|
||||
|
||||
local FromEngageAngle = ToCoord:GetAngleDegrees( ToCoord:GetDirectionVec3( DefenderCoord ) )
|
||||
|
||||
--- Create a route point of type air, 50km from the center of the attack point.
|
||||
local ToWP = ToCoord:Translate( 50000, FromEngageAngle ):WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
self:F( { Angle = FromEngageAngle, ToTargetSpeed = ToTargetSpeed } )
|
||||
self:F( { self.EngageMinSpeed, self.EngageMaxSpeed, ToTargetSpeed } )
|
||||
|
||||
EngageRoute[#EngageRoute+1] = ToWP
|
||||
|
||||
local AttackTasks = {}
|
||||
|
||||
for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do
|
||||
if AttackUnit:IsAlive() and AttackUnit:IsGround() then
|
||||
self:T( { "Engage Unit evaluation:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsGround() } )
|
||||
local HasRadar = AttackUnit:HasSEAD()
|
||||
if HasRadar then
|
||||
self:T( { "Eliminating Unit:", AttackUnit:GetName() } )
|
||||
AttackTasks[#AttackTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #AttackTasks == 0 then
|
||||
self:E( DefenderGroupName .. ": No targets found -> Going RTB")
|
||||
self:Return()
|
||||
self:__RTB( 0.5 )
|
||||
else
|
||||
DefenderGroup:OptionROEOpenFire()
|
||||
DefenderGroup:OptionROTVertical()
|
||||
DefenderGroup:OptionKeepWeaponsOnThreat()
|
||||
--DefenderGroup:OptionRTBAmmo( Weapon.flag.AnyASM )
|
||||
|
||||
AttackTasks[#AttackTasks+1] = DefenderGroup:TaskFunction( "AI_A2G_ENGAGE.EngageRoute", self )
|
||||
EngageRoute[#EngageRoute].task = DefenderGroup:TaskCombo( AttackTasks )
|
||||
end
|
||||
|
||||
DefenderGroup:Route( EngageRoute, 2 )
|
||||
|
||||
-- else
|
||||
-- local AttackTasks = {}
|
||||
-- --local AttackUnit = self.AttackSetUnit:GetRandom() -- Wrapper.Unit#UNIT
|
||||
-- for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do
|
||||
-- if AttackUnit:IsAlive() and AttackUnit:IsGround() then
|
||||
-- local HasRadar = AttackUnit:HasSEAD()
|
||||
-- if HasRadar then
|
||||
-- self:T( { "Eliminating Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsGround() } )
|
||||
-- AttackTasks[#AttackTasks+1] = DefenderGroup:TaskAttackUnit( AttackUnit )
|
||||
-- AttackTasks[#AttackTasks+1] = DefenderGroup:TaskFunction( "AI_A2G_ENGAGE.EngageRoute", self )
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- local DefenderTask = DefenderGroup:TaskCombo( AttackTasks )
|
||||
--
|
||||
-- DefenderGroup:OptionROEOpenFire()
|
||||
-- DefenderGroup:OptionROTVertical()
|
||||
-- DefenderGroup:OptionKeepWeaponsOnThreat()
|
||||
-- DefenderGroup:OptionRTBAmmo( Weapon.flag.AnyASM )
|
||||
--
|
||||
-- DefenderGroup:SetTask( DefenderTask, 0 )
|
||||
-- end
|
||||
end
|
||||
else
|
||||
self:E( DefenderGroupName .. ": No targets found -> Going RTB")
|
||||
self:Return()
|
||||
self:__RTB( 0.5 )
|
||||
end
|
||||
end
|
||||
|
||||
@ -475,7 +475,7 @@ function AI_AIR:onafterStatus()
|
||||
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
|
||||
@ -484,7 +484,7 @@ function AI_AIR:onafterStatus()
|
||||
not self:Is( "Fuel" ) and
|
||||
not self:Is( "Damaged" ) and
|
||||
not self:Is( "Home" ) then
|
||||
if self.IdleCount >= 2 then
|
||||
if self.IdleCount >= 10 then
|
||||
if Damage ~= InitialLife then
|
||||
self:Damaged()
|
||||
else
|
||||
@ -547,7 +547,7 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
||||
self:E( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
|
||||
|
||||
self:ClearTargetDistance()
|
||||
AIGroup:ClearTasks()
|
||||
--AIGroup:ClearTasks()
|
||||
|
||||
local EngageRoute = {}
|
||||
|
||||
|
||||
@ -430,6 +430,8 @@ do -- Types
|
||||
|
||||
end --
|
||||
|
||||
|
||||
|
||||
do -- Object
|
||||
|
||||
--- [DCS Class Object](https://wiki.hoggitworld.com/view/DCS_Class_Object)
|
||||
@ -527,6 +529,126 @@ do -- CoalitionObject
|
||||
end -- CoalitionObject
|
||||
|
||||
|
||||
do -- Weapon
|
||||
|
||||
--- [DCS Class Weapon](https://wiki.hoggitworld.com/view/DCS_Class_Weapon)
|
||||
-- @type Weapon
|
||||
-- @extends #CoalitionObject
|
||||
-- @field #Weapon.flag flag enum stores weapon flags. Some of them are combination of another flags.
|
||||
-- @field #Weapon.Category Category enum that stores weapon categories.
|
||||
-- @field #Weapon.GuidanceType GuidanceType enum that stores guidance methods. Available only for guided weapon (Weapon.Category.MISSILE and some Weapon.Category.BOMB).
|
||||
-- @field #Weapon.MissileCategory MissileCategory enum that stores missile category. Available only for missiles (Weapon.Category.MISSILE).
|
||||
-- @field #Weapon.WarheadType WarheadType enum that stores warhead types.
|
||||
-- @field #Weapon.Desc Desc The descriptor of a weapon.
|
||||
|
||||
--- enum stores weapon flags. Some of them are combination of another flags.
|
||||
-- @type Weapon.flag
|
||||
-- @field LGB
|
||||
-- @field TvGB
|
||||
-- @field SNSGB
|
||||
-- @field HEBomb
|
||||
-- @field Penetrator
|
||||
-- @field NapalmBomb
|
||||
-- @field FAEBomb
|
||||
-- @field ClusterBomb
|
||||
-- @field Dispencer
|
||||
-- @field CandleBomb
|
||||
-- @field ParachuteBomb
|
||||
-- @field GuidedBomb = LGB + TvGB + SNSGB
|
||||
-- @field AnyUnguidedBomb = HEBomb + Penetrator + NapalmBomb + FAEBomb + ClusterBomb + Dispencer + CandleBomb + ParachuteBomb
|
||||
-- @field AnyBomb = GuidedBomb + AnyUnguidedBomb
|
||||
-- @field LightRocket
|
||||
-- @field MarkerRocket
|
||||
-- @field CandleRocket
|
||||
-- @field HeavyRocket
|
||||
-- @field AnyRocket = LightRocket + HeavyRocket + MarkerRocket + CandleRocket
|
||||
-- @field AntiRadarMissile
|
||||
-- @field AntiShipMissile
|
||||
-- @field AntiTankMissile
|
||||
-- @field FireAndForgetASM
|
||||
-- @field LaserASM
|
||||
-- @field TeleASM
|
||||
-- @field CruiseMissile
|
||||
-- @field GuidedASM = LaserASM + TeleASM
|
||||
-- @field TacticASM = GuidedASM + FireAndForgetASM
|
||||
-- @field AnyASM = AntiRadarMissile + AntiShipMissile + AntiTankMissile + FireAndForgetASM + GuidedASM + CruiseMissile
|
||||
-- @field SRAAM
|
||||
-- @field MRAAM
|
||||
-- @field LRAAM
|
||||
-- @field IR_AAM
|
||||
-- @field SAR_AAM
|
||||
-- @field AR_AAM
|
||||
-- @field AnyAAM = IR_AAM + SAR_AAM + AR_AAM + SRAAM + MRAAM + LRAAM
|
||||
-- @field AnyMissile = AnyASM + AnyAAM
|
||||
-- @field AnyAutonomousMissile = IR_AAM + AntiRadarMissile + AntiShipMissile + FireAndForgetASM + CruiseMissile
|
||||
-- @field GUN_POD
|
||||
-- @field BuiltInCannon
|
||||
-- @field Cannons = GUN_POD + BuiltInCannon
|
||||
-- @field AnyAGWeapon = BuiltInCannon + GUN_POD + AnyBomb + AnyRocket + AnyASM
|
||||
-- @field AnyAAWeapon = BuiltInCannon + GUN_POD + AnyAAM
|
||||
-- @field UnguidedWeapon = Cannons + BuiltInCannon + GUN_POD + AnyUnguidedBomb + AnyRocket
|
||||
-- @field GuidedWeapon = GuidedBomb + AnyASM + AnyAAM
|
||||
-- @field AnyWeapon = AnyBomb + AnyRocket + AnyMissile + Cannons
|
||||
-- @field MarkerWeapon = MarkerRocket + CandleRocket + CandleBomb
|
||||
-- @field ArmWeapon = AnyWeapon - MarkerWeapon
|
||||
|
||||
--- Weapon.Category enum that stores weapon categories.
|
||||
-- @type Weapon.Category
|
||||
-- @field SHELL
|
||||
-- @field MISSILE
|
||||
-- @field ROCKET
|
||||
-- @field BOMB
|
||||
|
||||
|
||||
--- Weapon.GuidanceType enum that stores guidance methods. Available only for guided weapon (Weapon.Category.MISSILE and some Weapon.Category.BOMB).
|
||||
-- @type Weapon.GuidanceType
|
||||
-- @field INS
|
||||
-- @field IR
|
||||
-- @field RADAR_ACTIVE
|
||||
-- @field RADAR_SEMI_ACTIVE
|
||||
-- @field RADAR_PASSIVE
|
||||
-- @field TV
|
||||
-- @field LASER
|
||||
-- @field TELE
|
||||
|
||||
|
||||
--- Weapon.MissileCategory enum that stores missile category. Available only for missiles (Weapon.Category.MISSILE).
|
||||
-- @type Weapon.MissileCategory
|
||||
-- @field AAM
|
||||
-- @field SAM
|
||||
-- @field BM
|
||||
-- @field ANTI_SHIP
|
||||
-- @field CRUISE
|
||||
-- @field OTHER
|
||||
|
||||
--- Weapon.WarheadType enum that stores warhead types.
|
||||
-- @type Weapon.WarheadType
|
||||
-- @field AP
|
||||
-- @field HE
|
||||
-- @field SHAPED_EXPLOSIVE
|
||||
|
||||
--- Returns the unit that launched the weapon.
|
||||
-- @function [parent=#Weapon] getLauncher
|
||||
-- @param #Weapon self
|
||||
-- @return #Unit
|
||||
|
||||
--- returns target of the guided weapon. Unguided weapons and guided weapon that is targeted at the point on the ground will return nil.
|
||||
-- @function [parent=#Weapon] getTarget
|
||||
-- @param #Weapon self
|
||||
-- @return #Object
|
||||
|
||||
--- returns weapon descriptor. Descriptor type depends on weapon category.
|
||||
-- @function [parent=#Weapon] getDesc
|
||||
-- @param #Weapon self
|
||||
-- @return #Weapon.Desc
|
||||
|
||||
|
||||
|
||||
Weapon = {} --#Weapon
|
||||
|
||||
end -- Weapon
|
||||
|
||||
|
||||
do -- Airbase
|
||||
|
||||
--- [DCS Class Airbase](https://wiki.hoggitworld.com/view/DCS_Class_Airbase)
|
||||
|
||||
@ -168,6 +168,11 @@
|
||||
-- * @{#CONTROLLABLE.OptionAlarmStateGreen}
|
||||
-- * @{#CONTROLLABLE.OptionAlarmStateRed}
|
||||
--
|
||||
-- ## 5.4) Jettison weapons:
|
||||
--
|
||||
-- * @{#CONTROLLABLE.OptionAllowJettisonWeaponsOnThreat}
|
||||
-- * @{#CONTROLLABLE.OptionKeepWeaponsOnThreat}
|
||||
--
|
||||
-- @field #CONTROLLABLE
|
||||
CONTROLLABLE = {
|
||||
ClassName = "CONTROLLABLE",
|
||||
@ -302,7 +307,7 @@ end
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE
|
||||
function CONTROLLABLE:ClearTasks()
|
||||
self:F2()
|
||||
self:E( "ClearTasks" )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
|
||||
@ -366,13 +371,15 @@ end
|
||||
-- @param #number WaitTime Time in seconds, before the task is set.
|
||||
-- @return Wrapper.Controllable#CONTROLLABLE self
|
||||
function CONTROLLABLE:SetTask( DCSTask, WaitTime )
|
||||
self:F2( { DCSTask = DCSTask } )
|
||||
self:E( { "SetTask", WaitTime, DCSTask = DCSTask } )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
|
||||
if DCSControllable then
|
||||
|
||||
local DCSControllableName = self:GetName()
|
||||
|
||||
self:E( "Controllable Name = " .. DCSControllableName )
|
||||
|
||||
-- When a controllable SPAWNs, it takes about a second to get the controllable in the simulator. Setting tasks to unspawned controllables provides unexpected results.
|
||||
-- Therefore we schedule the functions to set the mission and options for the Controllable.
|
||||
@ -1659,6 +1666,7 @@ function CONTROLLABLE:TaskFunction( FunctionString, ... )
|
||||
|
||||
local DCSScript = {}
|
||||
DCSScript[#DCSScript+1] = "local MissionControllable = GROUP:Find( ... ) "
|
||||
DCSScript[#DCSScript+1] = "env.info( 'TaskFunction: ' .. ( MissionControllable and MissionControllable:GetName() ) or 'No Group' )"
|
||||
|
||||
if arg and arg.n > 0 then
|
||||
local ArgumentKey = '_' .. tostring( arg ):match("table: (.*)")
|
||||
@ -2922,7 +2930,7 @@ function CONTROLLABLE:OptionRTBAmmo( WeaponsFlag )
|
||||
local Controller = self:_GetController()
|
||||
|
||||
if self:IsAir() then
|
||||
Controller:setOption( AI.Option.GROUND.id.RTB_ON_OUT_OF_AMMO, WeaponsFlag )
|
||||
Controller:setOption( AI.Option.Air.id.RTB_ON_OUT_OF_AMMO, WeaponsFlag )
|
||||
end
|
||||
|
||||
return self
|
||||
@ -2932,6 +2940,47 @@ function CONTROLLABLE:OptionRTBAmmo( WeaponsFlag )
|
||||
end
|
||||
|
||||
|
||||
--- Allow to Jettison of weapons upon threat.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:OptionAllowJettisonWeaponsOnThreat()
|
||||
self:F2( { self.ControllableName } )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
if DCSControllable then
|
||||
local Controller = self:_GetController()
|
||||
|
||||
if self:IsAir() then
|
||||
Controller:setOption( AI.Option.Air.id.PROHIBIT_JETT, false )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Keep weapons upon threat.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:OptionKeepWeaponsOnThreat()
|
||||
self:F2( { self.ControllableName } )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
if DCSControllable then
|
||||
local Controller = self:_GetController()
|
||||
|
||||
if self:IsAir() then
|
||||
Controller:setOption( AI.Option.Air.id.PROHIBIT_JETT, true )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -68,6 +68,9 @@ AI/AI_A2A_Gci.lua
|
||||
AI/AI_A2A_Dispatcher.lua
|
||||
AI/AI_A2G.lua
|
||||
AI/AI_A2G_Engage.lua
|
||||
AI/AI_A2G_BAI.lua
|
||||
AI/AI_A2G_CAS.lua
|
||||
AI/AI_A2G_SEAD.lua
|
||||
AI/AI_A2G_Patrol.lua
|
||||
AI/AI_A2G_Dispatcher.lua
|
||||
AI/AI_Patrol.lua
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user