diff --git a/Moose Development/Moose/Functional/Sead.lua b/Moose Development/Moose/Functional/Sead.lua index 2cf454fb7..478ec0529 100644 --- a/Moose Development/Moose/Functional/Sead.lua +++ b/Moose Development/Moose/Functional/Sead.lua @@ -133,16 +133,15 @@ function SEAD:New( SEADGroupPrefixes, Padding ) self.CallBack = nil self.UseCallBack = false - self:AddTransition("*", "ManageEvasion", "*") - self:AddTransition("*", "CalculateHitZone", "*") self:HandleEvent( EVENTS.Shot, self.HandleEventShot ) -- Start State. self:SetStartState("Running") + self:AddTransition("*", "ManageEvasion", "*") + self:AddTransition("*", "CalculateHitZone", "*") - - self:I("*** SEAD - Started Version 0.4.1") + self:I("*** SEAD - Started Version 0.4.2") return self end @@ -300,28 +299,32 @@ function SEAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADG 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 tgtcoord = targetzone:GetRandomPointVec2() - local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord) - local _targetgroup = nil - local _targetgroupname = "none" - local _targetskill = "Random" - if tgtgrp and tgtgrp:IsAlive() then - _targetgroup = tgtgrp - _targetgroupname = tgtgrp:GetName() -- group name - _targetskill = tgtgrp:GetUnit(1):GetSkill() - self:T("*** Found Target = ".. _targetgroupname) - self:ManageEvasion(_targetskill,_targetgroup,pos0,"AGM_88",SEADGroup, 20) + -- look at a couple of zones across the trajectory + for n=1,3 do + local dist = Ropt - ((n-1)*20000) + local predpos= pos0:Translate(dist,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=%ddeg | 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 tgtcoord = targetzone:GetRandomPointVec2() + local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord) + local _targetgroup = nil + local _targetgroupname = "none" + local _targetskill = "Random" + if tgtgrp and tgtgrp:IsAlive() then + _targetgroup = tgtgrp + _targetgroupname = tgtgrp:GetName() -- group name + _targetskill = tgtgrp:GetUnit(1):GetSkill() + self:T("*** Found Target = ".. _targetgroupname) + self:ManageEvasion(_targetskill,_targetgroup,pos0,"AGM_88",SEADGroup, 20) + end end end end @@ -453,8 +456,9 @@ function SEAD:HandleEventShot( EventData ) local _targetskill = "Random" local _targetgroupname = "none" local _target = EventData.Weapon:getTarget() -- Identify target - if not _target then + if not _target or self.debug then -- AGM-88 w/o target data if string.find(SEADWeaponName,"AGM_88",1,true) then + self:I("**** Tracking AGM-88 with no target data.") local pos0 = SEADPlane:GetCoordinate() local fheight = SEADPlane:GetHeight() self:__CalculateHitZone(20,SEADWeapon,pos0,fheight,SEADGroup) diff --git a/Moose Development/Moose/Functional/Shorad.lua b/Moose Development/Moose/Functional/Shorad.lua index 50d7926a4..f70bb11a5 100644 --- a/Moose Development/Moose/Functional/Shorad.lua +++ b/Moose Development/Moose/Functional/Shorad.lua @@ -146,7 +146,7 @@ do -- @param #boolean UseEmOnOff Use Emissions On/Off rather than Alarm State Red/Green (default: use Emissions switch) -- @retunr #SHORAD self function SHORAD:New(Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition, UseEmOnOff) - local self = BASE:Inherit( self, BASE:New() ) + local self = BASE:Inherit( self, FSM:New() ) self:T({Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition}) local GroupSet = SET_GROUP:New():FilterPrefixes(ShoradPrefix):FilterCoalitions(Coalition):FilterCategoryGround():FilterStart() @@ -164,11 +164,17 @@ do self.DefenseLowProb = 70 -- probability to detect a missile shot, low 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:I("*** SHORAD - Started Version 0.2.10") + self:I("*** SHORAD - Started Version 0.3.1") -- Set the string id for output to DCS.log file. self.lid=string.format("SHORAD %s | ", self.name) self:_InitState() self:HandleEvent(EVENTS.Shot, self.HandleEventShot) + + -- Start State. + self:SetStartState("Running") + self:AddTransition("*", "WakeUpShorad", "*") + self:AddTransition("*", "CalculateHitZone", "*") + return self end @@ -402,6 +408,7 @@ do -- @return #boolean Returns true for a detection, else false function SHORAD:_ShotIsDetected() self:T(self.lid .. " _ShotIsDetected") + if self.debug then return true end local IsDetected = false local DetectionProb = math.random(self.DefenseLowProb, self.DefenseHighProb) -- reference value local ActualDetection = math.random(1,100) -- value for this shot @@ -425,7 +432,7 @@ do -- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs") -- mymantis:AddShorad(myshorad,720) -- mymantis:Start() - function SHORAD:WakeUpShorad(TargetGroup, Radius, ActiveTimer, TargetCat) + function SHORAD:onafterWakeUpShorad(From, Event, To, TargetGroup, Radius, ActiveTimer, TargetCat) self:T(self.lid .. " WakeUpShorad") self:T({TargetGroup, Radius, ActiveTimer, TargetCat}) local targetcat = TargetCat or Object.Category.UNIT @@ -479,6 +486,76 @@ do return self end +--- (Internal) Calculate hit zone of an AGM-88 +-- @param #SHORAD self +-- @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 #SHORAD self +function SHORAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADGroup) + self:T("**** Calculating hit zone") + if SEADWeapon and SEADWeapon:isExist() then + --local pos = SEADWeapon:getPoint() + + -- postion and height + local position = SEADWeapon:getPosition() + local mheight = height + -- heading + local wph = math.atan2(position.x.z, position.x.x) + if wph < 0 then + wph=wph+2*math.pi + end + wph=math.deg(wph) + + -- 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 + + -- look at a couple of zones across the trajectory + for n=1,3 do + local dist = Ropt - ((n-1)*20000) + local predpos= pos0:Translate(dist,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=%ddeg | Ropt=%dm",mheight,wph,mveloc,Ropt),false) + targetzone:DrawZone(coalition.side.BLUE,{0,0,1},0.2,nil,nil,3,true) + end + + local seadset = self.Groupset + local tgtcoord = targetzone:GetRandomPointVec2() + local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord) + local _targetgroup = nil + local _targetgroupname = "none" + local _targetskill = "Random" + if tgtgrp and tgtgrp:IsAlive() then + _targetgroup = tgtgrp + _targetgroupname = tgtgrp:GetName() -- group name + _targetskill = tgtgrp:GetUnit(1):GetSkill() + self:T("*** Found Target = ".. _targetgroupname) + self:WakeUpShorad(_targetgroupname, self.Radius, self.ActiveTimer, Object.Category.UNIT) + end + end + end + end + return self +end + --- Main function - work on the EventData -- @param #SHORAD self -- @param Core.Event#EVENTDATA EventData The event details table data set @@ -507,7 +584,15 @@ do -- get target data local targetdata = EventData.Weapon:getTarget() -- Identify target -- Is there target data? - if not targetdata then return end + if not targetdata or self.debug then + if string.find(ShootingWeaponName,"AGM_88",1,true) then + self:I("**** Tracking AGM-88 with no target data.") + local pos0 = EventData.IniUnit:GetCoordinate() + local fheight = EventData.IniUnit:GetHeight() + self:__CalculateHitZone(20,ShootingWeapon,pos0,fheight,EventData.IniGroup) + end + return self + end local targetcat = targetdata:getCategory() -- Identify category self:T(string.format("Target Category (3=STATIC, 1=UNIT)= %s",tostring(targetcat))) @@ -573,6 +658,7 @@ do end end end + return self end -- end