mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
SEAD - calculate HARM impact point from firing position if no target data is given
SHORAD - ignore HARM AGM-88 is not fired at a specific target
This commit is contained in:
parent
0ac00efda6
commit
ab4411e5bb
@ -59,6 +59,7 @@ SEAD = {
|
|||||||
Padding = 10,
|
Padding = 10,
|
||||||
CallBack = nil,
|
CallBack = nil,
|
||||||
UseCallBack = false,
|
UseCallBack = false,
|
||||||
|
debug = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Missile enumerators
|
--- Missile enumerators
|
||||||
@ -112,7 +113,7 @@ SEAD = {
|
|||||||
-- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } )
|
-- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } )
|
||||||
function SEAD:New( SEADGroupPrefixes, Padding )
|
function SEAD:New( SEADGroupPrefixes, Padding )
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() )
|
local self = BASE:Inherit( self, FSM:New() )
|
||||||
self:T( SEADGroupPrefixes )
|
self:T( SEADGroupPrefixes )
|
||||||
|
|
||||||
if type( SEADGroupPrefixes ) == 'table' then
|
if type( SEADGroupPrefixes ) == 'table' then
|
||||||
@ -128,12 +129,20 @@ function SEAD:New( SEADGroupPrefixes, Padding )
|
|||||||
self.Padding = padding
|
self.Padding = padding
|
||||||
self.UseEmissionsOnOff = true
|
self.UseEmissionsOnOff = true
|
||||||
|
|
||||||
|
self.debug = false
|
||||||
|
|
||||||
self.CallBack = nil
|
self.CallBack = nil
|
||||||
self.UseCallBack = false
|
self.UseCallBack = false
|
||||||
|
self:AddTransition("*", "ManageEvasion", "*")
|
||||||
|
self:AddTransition("*", "CalculateHitZone", "*")
|
||||||
|
|
||||||
self:HandleEvent( EVENTS.Shot, self.HandleEventShot )
|
self:HandleEvent( EVENTS.Shot, self.HandleEventShot )
|
||||||
|
|
||||||
self:I("*** SEAD - Started Version 0.3.6")
|
-- Start State.
|
||||||
|
self:SetStartState("Running")
|
||||||
|
|
||||||
|
|
||||||
|
self:I("*** SEAD - Started Version 0.4.1")
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -253,65 +262,83 @@ function SEAD:_GetDistance(_point1, _point2)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) Detects if an SAM site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME.
|
--- (Internal) Calculate hit zone of an AGM-88
|
||||||
-- @param #SEAD self
|
-- @param #SEAD self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param #table SEADWeapon DCS.Weapon object
|
||||||
|
-- @param Core.Point#COORDINATE pos0 Position of the plane when it fired
|
||||||
|
-- @param #number height Height when the missile was fired
|
||||||
|
-- @param Wrapper.Group#GROUP SEADGroup Attacker group
|
||||||
-- @return #SEAD self
|
-- @return #SEAD self
|
||||||
function SEAD:HandleEventShot( EventData )
|
function SEAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADGroup)
|
||||||
self:T( { EventData.id } )
|
self:T("**** Calculating hit zone")
|
||||||
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
|
if SEADWeapon and SEADWeapon:isExist() then
|
||||||
local SEADGroup = EventData.IniGroup -- Wrapper.Group#GROUP
|
--local pos = SEADWeapon:getPoint()
|
||||||
local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE
|
|
||||||
local SEADUnit = EventData.IniDCSUnit
|
|
||||||
local SEADUnitName = EventData.IniDCSUnitName
|
|
||||||
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
|
|
||||||
local SEADWeaponName = EventData.WeaponName -- return weapon type
|
|
||||||
|
|
||||||
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
-- postion and height
|
||||||
--self:T({ SEADWeapon })
|
local position = SEADWeapon:getPosition()
|
||||||
|
local mheight = height
|
||||||
if self:_CheckHarms(SEADWeaponName) then
|
-- heading
|
||||||
self:T( '*** SEAD - Weapon Match' )
|
local wph = math.atan2(position.x.z, position.x.x)
|
||||||
local _targetskill = "Random"
|
if wph < 0 then
|
||||||
local _targetgroupname = "none"
|
wph=wph+2*math.pi
|
||||||
local _target = EventData.Weapon:getTarget() -- Identify target
|
|
||||||
local targetcat = _target:getCategory() -- Identify category
|
|
||||||
local _targetUnit = nil -- Wrapper.Unit#UNIT
|
|
||||||
local _targetgroup = nil -- Wrapper.Group#GROUP
|
|
||||||
self:T(string.format("*** Targetcat = %d",targetcat))
|
|
||||||
if targetcat == Object.Category.UNIT then -- UNIT
|
|
||||||
self:T("*** Target Category UNIT")
|
|
||||||
_targetUnit = UNIT:Find(_target) -- Wrapper.Unit#UNIT
|
|
||||||
if _targetUnit and _targetUnit:IsAlive() then
|
|
||||||
_targetgroup = _targetUnit:GetGroup()
|
|
||||||
_targetgroupname = _targetgroup:GetName() -- group name
|
|
||||||
local _targetUnitName = _targetUnit:GetName()
|
|
||||||
_targetUnit:GetSkill()
|
|
||||||
_targetskill = _targetUnit:GetSkill()
|
|
||||||
end
|
end
|
||||||
elseif targetcat == Object.Category.STATIC then
|
wph=math.deg(wph)
|
||||||
self:T("*** Target Category STATIC")
|
|
||||||
|
-- velocity
|
||||||
|
local wpndata = SEAD.HarmData["AGM_88"]
|
||||||
|
local mveloc = math.floor(wpndata[2] * 340.29)
|
||||||
|
local c1 = (2*mheight*9.81)/(mveloc^2)
|
||||||
|
local c2 = (mveloc^2) / 9.81
|
||||||
|
local Ropt = c2 * math.sqrt(c1+1)
|
||||||
|
if height <= 5000 then
|
||||||
|
Ropt = Ropt * 0.72
|
||||||
|
elseif height <= 7500 then
|
||||||
|
Ropt = Ropt * 0.82
|
||||||
|
elseif height <= 10000 then
|
||||||
|
Ropt = Ropt * 0.87
|
||||||
|
elseif height <= 12500 then
|
||||||
|
Ropt = Ropt * 0.98
|
||||||
|
end
|
||||||
|
|
||||||
|
local predpos= pos0:Translate(Ropt,wph)
|
||||||
|
if predpos then
|
||||||
|
|
||||||
|
local targetzone = ZONE_RADIUS:New("Target Zone",predpos:GetVec2(),20000)
|
||||||
|
|
||||||
|
if self.debug then
|
||||||
|
predpos:MarkToAll(string.format("height=%dm | heading=%d | velocity=%d | Ropt=%dm",mheight,wph,mveloc,Ropt),false)
|
||||||
|
targetzone:DrawZone(coalition.side.BLUE,{0,0,1},0.2,nil,nil,3,true)
|
||||||
|
end
|
||||||
|
|
||||||
local seadset = SET_GROUP:New():FilterPrefixes(self.SEADGroupPrefixes):FilterOnce()
|
local seadset = SET_GROUP:New():FilterPrefixes(self.SEADGroupPrefixes):FilterOnce()
|
||||||
local tgtcoord = COORDINATE:NewFromVec3(_target:getPoint())
|
local tgtcoord = targetzone:GetRandomPointVec2()
|
||||||
local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
|
local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||||
|
local _targetgroup = nil
|
||||||
|
local _targetgroupname = "none"
|
||||||
|
local _targetskill = "Random"
|
||||||
if tgtgrp and tgtgrp:IsAlive() then
|
if tgtgrp and tgtgrp:IsAlive() then
|
||||||
_targetgroup = tgtgrp
|
_targetgroup = tgtgrp
|
||||||
_targetgroupname = tgtgrp:GetName() -- group name
|
_targetgroupname = tgtgrp:GetName() -- group name
|
||||||
_targetskill = tgtgrp:GetUnit(1):GetSkill()
|
_targetskill = tgtgrp:GetUnit(1):GetSkill()
|
||||||
self:T("*** Found Target = ".. _targetgroupname)
|
self:T("*** Found Target = ".. _targetgroupname)
|
||||||
|
self:ManageEvasion(_targetskill,_targetgroup,pos0,"AGM_88",SEADGroup, 20)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- see if we are shot at
|
|
||||||
local SEADGroupFound = false
|
|
||||||
for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do
|
|
||||||
self:T("Target = ".. _targetgroupname .. " | Prefix = " .. SEADGroupPrefix )
|
|
||||||
if string.find( _targetgroupname, SEADGroupPrefix,1,true ) then
|
|
||||||
SEADGroupFound = true
|
|
||||||
self:T( '*** SEAD - Group Match Found' )
|
|
||||||
break
|
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
if SEADGroupFound == true then -- yes we are being attacked
|
|
||||||
|
--- (Internal) Handle Evasion
|
||||||
|
-- @param #SEAD self
|
||||||
|
-- @param #string _targetskill
|
||||||
|
-- @param Wrapper.Group#GROUP _targetgroup
|
||||||
|
-- @param Core.Point#COORDINATE SEADPlanePos
|
||||||
|
-- @param #string SEADWeaponName
|
||||||
|
-- @param Wrapper.Group#GROUP SEADGroup Attacker Group
|
||||||
|
-- @param #number timeoffset Offset for tti calc
|
||||||
|
-- @return #SEAD self
|
||||||
|
function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,timeoffset)
|
||||||
|
local timeoffset = timeoffset or 0
|
||||||
if _targetskill == "Random" then -- when skill is random, choose a skill
|
if _targetskill == "Random" then -- when skill is random, choose a skill
|
||||||
local Skills = { "Average", "Good", "High", "Excellent" }
|
local Skills = { "Average", "Good", "High", "Excellent" }
|
||||||
_targetskill = Skills[ math.random(1,4) ]
|
_targetskill = Skills[ math.random(1,4) ]
|
||||||
@ -335,7 +362,7 @@ function SEAD:HandleEventShot( EventData )
|
|||||||
wpnspeed = math.floor(mach * 340.29)
|
wpnspeed = math.floor(mach * 340.29)
|
||||||
end
|
end
|
||||||
-- time to impact
|
-- time to impact
|
||||||
local _tti = math.floor(_distance / wpnspeed) -- estimated impact time
|
local _tti = math.floor(_distance / wpnspeed) - timeoffset -- estimated impact time
|
||||||
if _distance > 0 then
|
if _distance > 0 then
|
||||||
_distance = math.floor(_distance / 1000) -- km
|
_distance = math.floor(_distance / 1000) -- km
|
||||||
else
|
else
|
||||||
@ -386,7 +413,7 @@ function SEAD:HandleEventShot( EventData )
|
|||||||
|
|
||||||
local SuppressionStartTime = timer.getTime() + delay
|
local SuppressionStartTime = timer.getTime() + delay
|
||||||
local SuppressionEndTime = timer.getTime() + _tti + self.Padding
|
local SuppressionEndTime = timer.getTime() + _tti + self.Padding
|
||||||
|
local _targetgroupname = _targetgroup:GetName()
|
||||||
if not self.SuppressedGroups[_targetgroupname] then
|
if not self.SuppressedGroups[_targetgroupname] then
|
||||||
self:T(string.format("*** SEAD - %s | Parameters TTI %ds | Switch-Off in %ds",_targetgroupname,_tti,delay))
|
self:T(string.format("*** SEAD - %s | Parameters TTI %ds | Switch-Off in %ds",_targetgroupname,_tti,delay))
|
||||||
timer.scheduleFunction(SuppressionStart,{_targetgroup,_targetgroupname, SEADGroup},SuppressionStartTime)
|
timer.scheduleFunction(SuppressionStart,{_targetgroup,_targetgroupname, SEADGroup},SuppressionStartTime)
|
||||||
@ -401,6 +428,77 @@ function SEAD:HandleEventShot( EventData )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (Internal) Detects if an SAM site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME.
|
||||||
|
-- @param #SEAD self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
|
-- @return #SEAD self
|
||||||
|
function SEAD:HandleEventShot( EventData )
|
||||||
|
self:T( { EventData.id } )
|
||||||
|
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
|
||||||
|
local SEADGroup = EventData.IniGroup -- Wrapper.Group#GROUP
|
||||||
|
local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
|
local SEADUnit = EventData.IniDCSUnit
|
||||||
|
local SEADUnitName = EventData.IniDCSUnitName
|
||||||
|
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
|
||||||
|
local SEADWeaponName = EventData.WeaponName -- return weapon type
|
||||||
|
|
||||||
|
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
||||||
|
--self:T({ SEADWeapon })
|
||||||
|
|
||||||
|
if self:_CheckHarms(SEADWeaponName) then
|
||||||
|
self:T( '*** SEAD - Weapon Match' )
|
||||||
|
local _targetskill = "Random"
|
||||||
|
local _targetgroupname = "none"
|
||||||
|
local _target = EventData.Weapon:getTarget() -- Identify target
|
||||||
|
if not _target then
|
||||||
|
if string.find(SEADWeaponName,"AGM_88",1,true) then
|
||||||
|
local pos0 = SEADPlane:GetCoordinate()
|
||||||
|
local fheight = SEADPlane:GetHeight()
|
||||||
|
self:__CalculateHitZone(20,SEADWeapon,pos0,fheight,SEADGroup)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local targetcat = _target:getCategory() -- Identify category
|
||||||
|
local _targetUnit = nil -- Wrapper.Unit#UNIT
|
||||||
|
local _targetgroup = nil -- Wrapper.Group#GROUP
|
||||||
|
self:T(string.format("*** Targetcat = %d",targetcat))
|
||||||
|
if targetcat == Object.Category.UNIT then -- UNIT
|
||||||
|
self:T("*** Target Category UNIT")
|
||||||
|
_targetUnit = UNIT:Find(_target) -- Wrapper.Unit#UNIT
|
||||||
|
if _targetUnit and _targetUnit:IsAlive() then
|
||||||
|
_targetgroup = _targetUnit:GetGroup()
|
||||||
|
_targetgroupname = _targetgroup:GetName() -- group name
|
||||||
|
local _targetUnitName = _targetUnit:GetName()
|
||||||
|
_targetUnit:GetSkill()
|
||||||
|
_targetskill = _targetUnit:GetSkill()
|
||||||
|
end
|
||||||
|
elseif targetcat == Object.Category.STATIC then
|
||||||
|
self:T("*** Target Category STATIC")
|
||||||
|
local seadset = SET_GROUP:New():FilterPrefixes(self.SEADGroupPrefixes):FilterOnce()
|
||||||
|
local tgtcoord = COORDINATE:NewFromVec3(_target:getPoint())
|
||||||
|
local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||||
|
if tgtgrp and tgtgrp:IsAlive() then
|
||||||
|
_targetgroup = tgtgrp
|
||||||
|
_targetgroupname = tgtgrp:GetName() -- group name
|
||||||
|
_targetskill = tgtgrp:GetUnit(1):GetSkill()
|
||||||
|
self:T("*** Found Target = ".. _targetgroupname)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- see if we are shot at
|
||||||
|
local SEADGroupFound = false
|
||||||
|
for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do
|
||||||
|
self:T("Target = ".. _targetgroupname .. " | Prefix = " .. SEADGroupPrefix )
|
||||||
|
if string.find( _targetgroupname, SEADGroupPrefix,1,true ) then
|
||||||
|
SEADGroupFound = true
|
||||||
|
self:T( '*** SEAD - Group Match Found' )
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if SEADGroupFound == true then -- yes we are being attacked
|
||||||
|
self:ManageEvasion(_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
|
|||||||
@ -164,7 +164,7 @@ do
|
|||||||
self.DefenseLowProb = 70 -- probability to detect a missile shot, low margin
|
self.DefenseLowProb = 70 -- probability to detect a missile shot, low margin
|
||||||
self.DefenseHighProb = 90 -- probability to detect a missile shot, high margin
|
self.DefenseHighProb = 90 -- probability to detect a missile shot, high margin
|
||||||
self.UseEmOnOff = UseEmOnOff or false -- Decide if we are using Emission on/off (default) or AlarmState red/green
|
self.UseEmOnOff = UseEmOnOff or false -- Decide if we are using Emission on/off (default) or AlarmState red/green
|
||||||
self:I("*** SHORAD - Started Version 0.2.9")
|
self:I("*** SHORAD - Started Version 0.2.10")
|
||||||
-- Set the string id for output to DCS.log file.
|
-- Set the string id for output to DCS.log file.
|
||||||
self.lid=string.format("SHORAD %s | ", self.name)
|
self.lid=string.format("SHORAD %s | ", self.name)
|
||||||
self:_InitState()
|
self:_InitState()
|
||||||
@ -506,6 +506,9 @@ do
|
|||||||
if (self:_CheckHarms(ShootingWeaponName) or self:_CheckMavs(ShootingWeaponName)) and IsDetected then
|
if (self:_CheckHarms(ShootingWeaponName) or self:_CheckMavs(ShootingWeaponName)) and IsDetected then
|
||||||
-- get target data
|
-- get target data
|
||||||
local targetdata = EventData.Weapon:getTarget() -- Identify target
|
local targetdata = EventData.Weapon:getTarget() -- Identify target
|
||||||
|
-- Is there target data?
|
||||||
|
if not targetdata then return end
|
||||||
|
|
||||||
local targetcat = targetdata:getCategory() -- Identify category
|
local targetcat = targetdata:getCategory() -- Identify category
|
||||||
self:T(string.format("Target Category (3=STATIC, 1=UNIT)= %s",tostring(targetcat)))
|
self:T(string.format("Target Category (3=STATIC, 1=UNIT)= %s",tostring(targetcat)))
|
||||||
self:T({targetdata})
|
self:T({targetdata})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user