diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 23faabb3f..bb6fbe45e 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -191,7 +191,7 @@ MANTIS = { ShoradLink = false, ShoradTime = 600, ShoradActDistance = 15000, - UseEmOnOff = true, + UseEmOnOff = false, } ----------------------------------------------------------------------- @@ -208,7 +208,7 @@ do --@param #string coaltion Coalition side of your setup, e.g. "blue", "red" or "neutral" --@param #boolean dynamic Use constant (true) filtering or just filter once (false, default) (optional) --@param #string awacs Group name of your Awacs (optional) - --@param #boolean EmOnOff Make MANTIS switch Emissions on and off instead of changing the alarm state between RED and GREEN (optional, deault true) + --@param #boolean EmOnOff Make MANTIS switch Emissions on and off instead of changing the alarm state between RED and GREEN --@return #MANTIS self --@usage Start up your MANTIS with a basic setting -- @@ -267,6 +267,8 @@ do if EmOnOff then if EmOnOff == false then self.UseEmOnOff = false + else + self.UseEmOnOff = true end end diff --git a/Moose Development/Moose/Functional/Sead.lua b/Moose Development/Moose/Functional/Sead.lua index 8eb98d4f4..ec568b627 100644 --- a/Moose Development/Moose/Functional/Sead.lua +++ b/Moose Development/Moose/Functional/Sead.lua @@ -1,26 +1,26 @@ --- **Functional** -- Make SAM sites execute evasive and defensive behaviour when being fired upon. --- +-- -- === --- +-- -- ## Features: --- +-- -- * When SAM sites are being fired upon, the SAMs will take evasive action will reposition themselves when possible. -- * When SAM sites are being fired upon, the SAMs will take defensive action by shutting down their radars. --- +-- -- === --- +-- -- ## Missions: --- +-- -- [SEV - SEAD Evasion](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SEV%20-%20SEAD%20Evasion) --- +-- -- === --- +-- -- ### Authors: **FlightControl**, **applevangelist** --- --- Last Update: April 2021 --- +-- +-- Last Update: Feb 2021 +-- -- === --- +-- -- @module Functional.Sead -- @image SEAD.JPG @@ -28,49 +28,32 @@ -- @extends Core.Base#BASE --- Make SAM sites execute evasive and defensive behaviour when being fired upon. --- +-- -- This class is very easy to use. Just setup a SEAD object by using @{#SEAD.New}() and SAMs will evade and take defensive action when being fired upon. --- +-- -- # Constructor: --- +-- -- Use the @{#SEAD.New}() constructor to create a new SEAD object. --- +-- -- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } ) --- +-- -- @field #SEAD SEAD = { - ClassName = "SEAD", - TargetSkill = { - Average = { Evade = 30, DelayOn = { 40, 60 } } , - Good = { Evade = 20, DelayOn = { 30, 50 } } , - High = { Evade = 15, DelayOn = { 20, 40 } } , - Excellent = { Evade = 10, DelayOn = { 10, 30 } } - }, - SEADGroupPrefixes = {}, - SuppressedGroups = {}, - EngagementRange = 75 -- default 75% engagement range Feature Request #1355 + ClassName = "SEAD", + TargetSkill = { + Average = { Evade = 30, DelayOn = { 40, 60 } } , + Good = { Evade = 20, DelayOn = { 30, 50 } } , + High = { Evade = 15, DelayOn = { 20, 40 } } , + Excellent = { Evade = 10, DelayOn = { 10, 30 } } + }, + SEADGroupPrefixes = {}, + SuppressedGroups = {}, + EngagementRange = 75 -- default 75% engagement range Feature Request #1355 } - -- TODO Complete list? --- Missile enumerators -- @field Harms SEAD.Harms = { - --[[ - ["X58"] = "weapons.missiles.X_58", --Kh-58X anti-radiation missiles fired - ["Kh25"] = "weapons.missiles.Kh25MP_PRGS1VP", --Kh-25MP anti-radiation missiles fired - ["X25"] = "weapons.missiles.X_25MP", --Kh-25MPU anti-radiation missiles fired - ["X28"] = "weapons.missiles.X_28", --Kh-28 anti-radiation missiles fired - ["X31"] = "weapons.missiles.X_31P", --Kh-31P anti-radiation missiles fired - ["AGM45A"] = "weapons.missiles.AGM_45A", --AGM-45A anti-radiation missiles fired - ["AGM45"] = "weapons.missiles.AGM_45", --AGM-45B anti-radiation missiles fired - ["AGM88"] = "weapons.missiles.AGM_88", --AGM-88C anti-radiation missiles fired - ["AGM122"] = "weapons.missiles.AGM_122", --AGM-122 Sidearm anti-radiation missiles fired - ["LD10"] = "weapons.missiles.LD-10", --LD-10 anti-radiation missiles fired - ["ALARM"] = "weapons.missiles.ALARM", --ALARM anti-radiation missiles fired - ["AGM84E"] = "weapons.missiles.AGM_84E", --AGM84 anti-radiation missiles fired - ["AGM84A"] = "weapons.missiles.AGM_84A", --AGM84 anti-radiation missiles fired - ["AGM84H"] = "weapons.missiles.AGM_84H", --AGM84 anti-radiation missiles fired - --]] ["AGM_88"] = "AGM_88", ["AGM_45"] = "AGM_45", ["AGM_122"] = "AGM_122", @@ -84,7 +67,7 @@ SEAD = { ["X_31"] = "X_31", ["Kh25"] = "Kh25", } - + --- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles. -- When an anti radiation missile is fired (KH-58, KH-31P, KH-31A, KH-25MPU, HARM missiles), the SA will shut down their radars and will take evasive actions... -- Chances are big that the missile will miss. @@ -97,20 +80,20 @@ SEAD = { -- 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 ) - local self = BASE:Inherit( self, BASE:New() ) - self:F( SEADGroupPrefixes ) - - if type( SEADGroupPrefixes ) == 'table' then - for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do - self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix - end - else - self.SEADGroupPrefixes[SEADGroupPrefixes] = SEADGroupPrefixes - end - - self:HandleEvent( EVENTS.Shot ) - self:I("*** SEAD - Started Version 0.2.7") - return self + local self = BASE:Inherit( self, BASE:New() ) + self:F( SEADGroupPrefixes ) + + if type( SEADGroupPrefixes ) == 'table' then + for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do + self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix + end + else + self.SEADGroupPrefixes[SEADGroupPrefixes] = SEADGroupPrefixes + end + + self:HandleEvent( EVENTS.Shot, self.HandleEventShot ) + self:I("*** SEAD - Started Version 0.2.8") + return self end --- Update the active SEAD Set @@ -120,7 +103,7 @@ end function SEAD:UpdateSet( SEADGroupPrefixes ) self:F( SEADGroupPrefixes ) - + if type( SEADGroupPrefixes ) == 'table' then for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix @@ -164,112 +147,83 @@ end -- @see SEAD -- @param #SEAD -- @param Core.Event#EVENTDATA EventData -function SEAD:OnEventShot( EventData ) - self:T( { EventData } ) +function SEAD:HandleEventShot( EventData ) + self:T( { EventData } ) - local SEADUnit = EventData.IniDCSUnit - local SEADUnitName = EventData.IniDCSUnitName - local SEADWeapon = EventData.Weapon -- Identify the weapon fired - local SEADWeaponName = EventData.WeaponName -- return weapon type + 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 }) - - --[[check for SEAD missiles - if SEADWeaponName == "weapons.missiles.X_58" --Kh-58U anti-radiation missiles fired - or - SEADWeaponName == "weapons.missiles.Kh25MP_PRGS1VP" --Kh-25MP anti-radiation missiles fired - or - SEADWeaponName == "weapons.missiles.X_25MP" --Kh-25MPU anti-radiation missiles fired - or - SEADWeaponName == "weapons.missiles.X_28" --Kh-28 anti-radiation missiles fired - or - SEADWeaponName == "weapons.missiles.X_31P" --Kh-31P anti-radiation missiles fired - or - SEADWeaponName == "weapons.missiles.AGM_45A" --AGM-45A anti-radiation missiles fired - or - SEADWeaponName == "weapons.missiles.AGM_45" --AGM-45B anti-radiation missiles fired - or - SEADWeaponName == "weapons.missiles.AGM_88" --AGM-88C anti-radiation missiles fired - or - SEADWeaponName == "weapons.missiles.AGM_122" --AGM-122 Sidearm anti-radiation missiles fired - or - SEADWeaponName == "weapons.missiles.LD-10" --LD-10 anti-radiation missiles fired - or - SEADWeaponName == "weapons.missiles.ALARM" --ALARM anti-radiation missiles fired - or - SEADWeaponName == "weapons.missiles.AGM_84E" --AGM84 anti-radiation missiles fired - or - SEADWeaponName == "weapons.missiles.AGM_84A" --AGM84 anti-radiation missiles fired - or - SEADWeaponName == "weapons.missiles.AGM_84H" --AGM84 anti-radiation missiles fired - --]] + self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName) + self:T({ SEADWeapon }) + if self:_CheckHarms(SEADWeaponName) then local _targetskill = "Random" local _targetMimgroupName = "none" - local _evade = math.random (1,100) -- random number for chance of evading action - local _targetMim = EventData.Weapon:getTarget() -- Identify target - local _targetUnit = UNIT:Find(_targetMim) -- Unit name by DCS Object - if _targetUnit and _targetUnit:IsAlive() then - local _targetMimgroup = _targetUnit:GetGroup() - local _targetMimgroupName = _targetMimgroup:GetName() -- group name - --local _targetskill = _DATABASE.Templates.Units[_targetUnit].Template.skill - self:T( self.SEADGroupPrefixes ) - self:T( _targetMimgroupName ) - end - -- see if we are shot at - local SEADGroupFound = false - for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do - if string.find( _targetMimgroupName, SEADGroupPrefix, 1, true ) then - SEADGroupFound = true - self:T( '*** SEAD - Group Found' ) - break - end - end - if SEADGroupFound == true then -- yes we are being attacked - if _targetskill == "Random" then -- when skill is random, choose a skill - local Skills = { "Average", "Good", "High", "Excellent" } - _targetskill = Skills[ math.random(1,4) ] - end - self:T( _targetskill ) - if self.TargetSkill[_targetskill] then - if (_evade > self.TargetSkill[_targetskill].Evade) then + local _evade = math.random (1,100) -- random number for chance of evading action + local _targetMim = EventData.Weapon:getTarget() -- Identify target + local _targetUnit = UNIT:Find(_targetMim) -- Unit name by DCS Object + if _targetUnit and _targetUnit:IsAlive() then + local _targetMimgroup = _targetUnit:GetGroup() + local _targetMimgroupName = _targetMimgroup:GetName() -- group name + --local _targetskill = _DATABASE.Templates.Units[_targetUnit].Template.skill + self:T( self.SEADGroupPrefixes ) + self:T( _targetMimgroupName ) + end + -- see if we are shot at + local SEADGroupFound = false + for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do + if string.find( _targetMimgroupName, SEADGroupPrefix, 1, true ) then + SEADGroupFound = true + self:T( '*** SEAD - Group Found' ) + break + end + end + if SEADGroupFound == true then -- yes we are being attacked + if _targetskill == "Random" then -- when skill is random, choose a skill + local Skills = { "Average", "Good", "High", "Excellent" } + _targetskill = Skills[ math.random(1,4) ] + end + self:T( _targetskill ) + if self.TargetSkill[_targetskill] then + if (_evade > self.TargetSkill[_targetskill].Evade) then + + self:T( string.format("*** SEAD - Evading, target skill " ..string.format(_targetskill)) ) + + local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) + local _targetMimcont= _targetMimgroup:getController() + + routines.groupRandomDistSelf(_targetMimgroup,300,'Diamond',250,20) -- move randomly + + --tracker ID table to switch groups off and on again + local id = { + groupName = _targetMimgroup, + ctrl = _targetMimcont + } - self:T( string.format("*** SEAD - Evading, target skill " ..string.format(_targetskill)) ) - - local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) - local _targetMimcont= _targetMimgroup:getController() - - routines.groupRandomDistSelf(_targetMimgroup,300,'Diamond',250,20) -- move randomly - - --tracker ID table to switch groups off and on again - local id = { - groupName = _targetMimgroup, - ctrl = _targetMimcont - } - - local function SuppressionEnd(id) --switch group back on - local range = self.EngagementRange -- Feature Request #1355 - self:T(string.format("*** SEAD - Engagement Range is %d", range)) - id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.RED) - --id.groupName:enableEmission(true) - id.ctrl:setOption(AI.Option.Ground.id.AC_ENGAGEMENT_RANGE_RESTRICTION,range) --Feature Request #1355 - self.SuppressedGroups[id.groupName] = nil --delete group id from table when done - end - -- randomize switch-on time - local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2]) - local SuppressionEndTime = timer.getTime() + delay - --create entry - if self.SuppressedGroups[id.groupName] == nil then --no timer entry for this group yet - self.SuppressedGroups[id.groupName] = { - SuppressionEndTime = delay - } - Controller.setOption(_targetMimcont, AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) - --_targetMimgroup:enableEmission(false) - timer.scheduleFunction(SuppressionEnd, id, SuppressionEndTime) --Schedule the SuppressionEnd() function - end - end - end - end - end + local function SuppressionEnd(id) --switch group back on + local range = self.EngagementRange -- Feature Request #1355 + self:T(string.format("*** SEAD - Engagement Range is %d", range)) + id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.RED) + --id.groupName:enableEmission(true) + id.ctrl:setOption(AI.Option.Ground.id.AC_ENGAGEMENT_RANGE_RESTRICTION,range) --Feature Request #1355 + self.SuppressedGroups[id.groupName] = nil --delete group id from table when done + end + -- randomize switch-on time + local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2]) + local SuppressionEndTime = timer.getTime() + delay + --create entry + if self.SuppressedGroups[id.groupName] == nil then --no timer entry for this group yet + self.SuppressedGroups[id.groupName] = { + SuppressionEndTime = delay + } + Controller.setOption(_targetMimcont, AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) + --_targetMimgroup:enableEmission(false) + timer.scheduleFunction(SuppressionEnd, id, SuppressionEndTime) --Schedule the SuppressionEnd() function + end + end + end + end + end end diff --git a/Moose Development/Moose/Functional/Shorad.lua b/Moose Development/Moose/Functional/Shorad.lua index 1dbff94f4..36ca8ecdf 100644 --- a/Moose Development/Moose/Functional/Shorad.lua +++ b/Moose Development/Moose/Functional/Shorad.lua @@ -1,24 +1,24 @@ --- **Functional** -- Short Range Air Defense System --- +-- -- === --- +-- -- **SHORAD** - Short Range Air Defense System -- Controls a network of short range air/missile defense groups. --- +-- -- === --- +-- -- ## Missions: -- -- ### [SHORAD - Short Range Air Defense](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SRD%20-%20SHORAD%20Defense) --- +-- -- === --- --- ### Author : **applevangelist** --- +-- +-- ### Author : **applevangelist ** +-- -- @module Functional.Shorad -- @image Functional.Shorad.jpg -- --- Date: May 2021 +-- Date: July 2021 ------------------------------------------------------------------------- --- **SHORAD** class, extends Core.Base#BASE @@ -26,7 +26,7 @@ -- @field #string ClassName -- @field #string name Name of this Shorad -- @field #boolean debug Set the debug state --- @field #string Prefixes String to be used to build the @{#Core.Set#SET_GROUP} +-- @field #string Prefixes String to be used to build the @{#Core.Set#SET_GROUP} -- @field #number Radius Shorad defense radius in meters -- @field Core.Set#SET_GROUP Groupset The set of Shorad groups -- @field Core.Set#SET_GROUP Samset The set of SAM groups to defend @@ -41,10 +41,10 @@ -- @field #boolean UseEmOnOff Decide if we are using Emission on/off (default) or AlarmState red/green. -- @extends Core.Base#BASE ---- *Good friends are worth defending.* Mr Tushman, Wonder (the Movie) --- +--- *Good friends are worth defending.* Mr Tushman, Wonder (the Movie) +-- -- Simple Class for a more intelligent Short Range Air Defense System --- +-- -- #SHORAD -- Moose derived missile intercepting short range defense system. -- Protects a network of SAM sites. Uses events to switch on the defense groups closest to the enemy. @@ -52,26 +52,26 @@ -- -- ## Usage -- --- Set up a #SET_GROUP for the SAM sites to be protected: --- --- `local SamSet = SET_GROUP:New():FilterPrefixes("Red SAM"):FilterCoalitions("red"):FilterStart()` --- +-- Set up a #SET_GROUP for the SAM sites to be protected: +-- +-- `local SamSet = SET_GROUP:New():FilterPrefixes("Red SAM"):FilterCoalitions("red"):FilterStart()` +-- -- By default, SHORAD will defense against both HARMs and AG-Missiles with short to medium range. The default defense probability is 70-90%. --- When a missile is detected, SHORAD will activate defense groups in the given radius around the target for 10 minutes. It will *not* react to friendly fire. --- +-- When a missile is detected, SHORAD will activate defense groups in the given radius around the target for 10 minutes. It will *not* react to friendly fire. +-- -- ### Start a new SHORAD system, parameters are: +-- +-- * Name: Name of this SHORAD. +-- * ShoradPrefix: Filter for the Shorad #SET_GROUP. +-- * Samset: The #SET_GROUP of SAM sites to defend. +-- * Radius: Defense radius in meters. +-- * ActiveTimer: Determines how many seconds the systems stay on red alert after wake-up call. +-- * Coalition: Coalition, i.e. "blue", "red", or "neutral".* +-- +-- `myshorad = SHORAD:New("RedShorad", "Red SHORAD", SamSet, 25000, 600, "red")` -- --- * Name: Name of this SHORAD. --- * ShoradPrefix: Filter for the Shorad #SET_GROUP. --- * Samset: The #SET_GROUP of SAM sites to defend. --- * Radius: Defense radius in meters. --- * ActiveTimer: Determines how many seconds the systems stay on red alert after wake-up call. --- * Coalition: Coalition, i.e. "blue", "red", or "neutral".* --- --- `myshorad = SHORAD:New("RedShorad", "Red SHORAD", SamSet, 25000, 600, "red")` --- --- ## Customize options --- +-- ## Customize options +-- -- * SHORAD:SwitchDebug(debug) -- * SHORAD:SwitchHARMDefense(onoff) -- * SHORAD:SwitchAGMDefense(onoff) @@ -94,9 +94,9 @@ SHORAD = { lid = "", DefendHarms = true, DefendMavs = true, - DefenseLowProb = 75, + DefenseLowProb = 70, DefenseHighProb = 90, - UseEmOnOff = false, + UseEmOnOff = false, } ----------------------------------------------------------------------- @@ -108,22 +108,6 @@ do --- Missile enumerators -- @field Harms SHORAD.Harms = { - --[[ - ["X58"] = "weapons.missiles.X_58", --Kh-58X anti-radiation missiles fired - ["Kh25"] = "weapons.missiles.Kh25MP_PRGS1VP", --Kh-25MP anti-radiation missiles fired - ["X25"] = "weapons.missiles.X_25MP", --Kh-25MPU anti-radiation missiles fired - ["X28"] = "weapons.missiles.X_28", --Kh-28 anti-radiation missiles fired - ["X31"] = "weapons.missiles.X_31P", --Kh-31P anti-radiation missiles fired - ["AGM45A"] = "weapons.missiles.AGM_45A", --AGM-45A anti-radiation missiles fired - ["AGM45"] = "weapons.missiles.AGM_45", --AGM-45B anti-radiation missiles fired - ["AGM88"] = "weapons.missiles.AGM_88", --AGM-88C anti-radiation missiles fired - ["AGM122"] = "weapons.missiles.AGM_122", --AGM-122 Sidearm anti-radiation missiles fired - ["LD10"] = "weapons.missiles.LD-10", --LD-10 anti-radiation missiles fired - ["ALARM"] = "weapons.missiles.ALARM", --ALARM anti-radiation missiles fired - ["AGM84E"] = "weapons.missiles.AGM_84E", --AGM84 anti-radiation missiles fired - ["AGM84A"] = "weapons.missiles.AGM_84A", --AGM84 anti-radiation missiles fired - ["AGM84H"] = "weapons.missiles.AGM_84H", --AGM84 anti-radiation missiles fired - --]] ["AGM_88"] = "AGM_88", ["AGM_45"] = "AGM_45", ["AGM_122"] = "AGM_122", @@ -137,7 +121,7 @@ do ["X_31"] = "X_31", ["Kh25"] = "Kh25", } - + --- TODO complete list? -- @field Mavs SHORAD.Mavs = { @@ -148,7 +132,7 @@ do ["Kh31"] = "Kh31", ["Kh66"] = "Kh66", } - + --- Instantiates a new SHORAD object -- @param #SHORAD self -- @param #string Name Name of this SHORAD @@ -157,10 +141,12 @@ do -- @param #number Radius Defense radius in meters, used to switch on groups -- @param #number ActiveTimer Determines how many seconds the systems stay on red alert after wake-up call -- @param #string Coalition Coalition, i.e. "blue", "red", or "neutral" - function SHORAD:New(Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition) + -- @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() ) - self:T({Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition}) - + self:I({Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition}) + local GroupSet = SET_GROUP:New():FilterPrefixes(ShoradPrefix):FilterCoalitions(Coalition):FilterCategoryGround():FilterStart() self.name = Name or "MyShorad" @@ -171,81 +157,101 @@ do self.ActiveTimer = ActiveTimer or 600 self.ActiveGroups = {} self.Groupset = GroupSet - self:HandleEvent( EVENTS.Shot ) self.DefendHarms = true self.DefendMavs = true self.DefenseLowProb = 70 -- probability to detect a missile shot, low margin self.DefenseHighProb = 90 -- probability to detect a missile shot, high margin - self.UseEmOnOff = true -- Decide if we are using Emission on/off (default) or AlarmState red/green - self:I("*** SHORAD - Started Version 0.2.5") + 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.8") -- 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) return self end - + --- Initially set all groups to alarm state GREEN -- @param #SHORAD self function SHORAD:_InitState() + self:I(self.lid .. " _InitState") local table = {} local set = self.Groupset - self:T({set = set}) + self:I({set = set}) local aliveset = set:GetAliveSet() --#table for _,_group in pairs (aliveset) do if self.UseEmOnOff then --_group:SetAIOff() _group:EnableEmission(false) + _group:OptionAlarmStateRed() --Wrapper.Group#GROUP else _group:OptionAlarmStateGreen() --Wrapper.Group#GROUP end + _group:OptionDisperseOnAttack(30) end -- gather entropy - for i=1,10 do + for i=1,100 do math.random() end + return self end - - --- Switch debug state + + --- Switch debug state on -- @param #SHORAD self -- @param #boolean debug Switch debug on (true) or off (false) - function SHORAD:SwitchDebug(debug) - self:T( { debug } ) - local onoff = debug or false - if debug then - self.debug = true - --tracing - BASE:TraceOn() - BASE:TraceClass("SHORAD") + function SHORAD:SwitchDebug(onoff) + self:I( { onoff } ) + if onoff then + self:SwitchDebugOn() else - self.debug = false - BASE:TraceOff() + self.SwitchDebugOff() end + return self end - + + --- Switch debug state on + -- @param #SHORAD self + function SHORAD:SwitchDebugOn() + self.debug = true + --tracing + BASE:TraceOn() + BASE:TraceClass("SHORAD") + return self + end + + --- Switch debug state off + -- @param #SHORAD self + function SHORAD:SwitchDebugOff() + self.debug = false + BASE:TraceOff() + return self + end + --- Switch defense for HARMs -- @param #SHORAD self -- @param #boolean onoff function SHORAD:SwitchHARMDefense(onoff) - self:T( { onoff } ) + self:I( { onoff } ) local onoff = onoff or true self.DefendHarms = onoff + return self end - + --- Switch defense for AGMs -- @param #SHORAD self -- @param #boolean onoff function SHORAD:SwitchAGMDefense(onoff) - self:T( { onoff } ) + self:I( { onoff } ) local onoff = onoff or true self.DefendMavs = onoff + return self end - + --- Set defense probability limits -- @param #SHORAD self -- @param #number low Minimum detection limit, integer 1-100 -- @param #number high Maximum detection limit integer 1-100 function SHORAD:SetDefenseLimits(low,high) - self:T( { low, high } ) + self:I( { low, high } ) local low = low or 70 local high = high or 90 if (low < 0) or (low > 100) or (low > high) then @@ -256,43 +262,51 @@ do end self.DefenseLowProb = low self.DefenseHighProb = high + return self end - + --- Set the number of seconds a SHORAD site will stay active -- @param #SHORAD self -- @param #number seconds Number of seconds systems stay active function SHORAD:SetActiveTimer(seconds) + self:I(self.lid .. " SetActiveTimer") local timer = seconds or 600 if timer < 0 then timer = 600 end self.ActiveTimer = timer + return self end --- Set the number of meters for the SHORAD defense zone -- @param #SHORAD self - -- @param #number meters Radius of the defense search zone in meters. #SHORADs in this range around a targeted group will go active + -- @param #number meters Radius of the defense search zone in meters. #SHORADs in this range around a targeted group will go active function SHORAD:SetDefenseRadius(meters) + self:I(self.lid .. " SetDefenseRadius") local radius = meters or 20000 if radius < 0 then radius = 20000 end self.Radius = radius + return self end - + --- Set using Emission on/off instead of changing alarm state -- @param #SHORAD self -- @param #boolean switch Decide if we are changing alarm state or AI state function SHORAD:SetUsingEmOnOff(switch) + self:I(self.lid .. " SetUsingEmOnOff") self.UseEmOnOff = switch or false + return self end - + --- Check if a HARM was fired -- @param #SHORAD self -- @param #string WeaponName -- @return #boolean Returns true for a match function SHORAD:_CheckHarms(WeaponName) - self:T( { WeaponName } ) + self:I(self.lid .. " _CheckHarms") + self:I( { WeaponName } ) local hit = false if self.DefendHarms then for _,_name in pairs (SHORAD.Harms) do @@ -301,13 +315,14 @@ do end return hit end - + --- Check if an AGM was fired -- @param #SHORAD self -- @param #string WeaponName -- @return #boolean Returns true for a match function SHORAD:_CheckMavs(WeaponName) - self:T( { WeaponName } ) + self:I(self.lid .. " _CheckMavs") + self:I( { WeaponName } ) local hit = false if self.DefendMavs then for _,_name in pairs (SHORAD.Mavs) do @@ -316,34 +331,36 @@ do end return hit end - + --- Check the coalition of the attacker -- @param #SHORAD self -- @param #string Coalition name -- @return #boolean Returns false for a match function SHORAD:_CheckCoalition(Coalition) + self:I(self.lid .. " _CheckCoalition") local owncoalition = self.Coalition local othercoalition = "" - if Coalition == 0 then + if Coalition == 0 then othercoalition = "neutral" elseif Coalition == 1 then othercoalition = "red" else othercoalition = "blue" end - self:T({owncoalition = owncoalition, othercoalition = othercoalition}) + self:I({owncoalition = owncoalition, othercoalition = othercoalition}) if owncoalition ~= othercoalition then return true else return false end end - + --- Check if the missile is aimed at a SHORAD -- @param #SHORAD self -- @param #string TargetGroupName Name of the target group -- @return #boolean Returns true for a match, else false function SHORAD:_CheckShotAtShorad(TargetGroupName) + self:I(self.lid .. " _CheckShotAtShorad") local tgtgrp = TargetGroupName local shorad = self.Groupset local shoradset = shorad:GetAliveSet() --#table @@ -352,17 +369,18 @@ do local groupname = _groups:GetName() if string.find(groupname, tgtgrp, 1) then returnname = true - _groups:RelocateGroundRandomInRadius(7,100,false,false) -- be a bit evasive + --_groups:RelocateGroundRandomInRadius(7,100,false,false) -- be a bit evasive end end - return returnname + return returnname end - + --- Check if the missile is aimed at a SAM site -- @param #SHORAD self -- @param #string TargetGroupName Name of the target group -- @return #boolean Returns true for a match, else false function SHORAD:_CheckShotAtSams(TargetGroupName) + self:I(self.lid .. " _CheckShotAtSams") local tgtgrp = TargetGroupName local shorad = self.Samset --local shoradset = shorad:GetAliveSet() --#table @@ -376,11 +394,12 @@ do end return returnname end - + --- Calculate if the missile shot is detected -- @param #SHORAD self -- @return #boolean Returns true for a detection, else false function SHORAD:_ShotIsDetected() + self:I(self.lid .. " _ShotIsDetected") local IsDetected = false local DetectionProb = math.random(self.DefenseLowProb, self.DefenseHighProb) -- reference value local ActualDetection = math.random(1,100) -- value for this shot @@ -389,15 +408,15 @@ do end return IsDetected end - + --- Wake up #SHORADs in a zone with diameter Radius for ActiveTimer seconds -- @param #SHORAD self -- @param #string TargetGroup Name of the target group used to build the #ZONE -- @param #number Radius Radius of the #ZONE -- @param #number ActiveTimer Number of seconds to stay active -- @param #number TargetCat (optional) Category, i.e. Object.Category.UNIT or Object.Category.STATIC - -- @usage Use this function to integrate with other systems, example - -- + -- @usage Use this function to integrate with other systems, example + -- -- local SamSet = SET_GROUP:New():FilterPrefixes("Blue SAM"):FilterCoalitions("blue"):FilterStart() -- myshorad = SHORAD:New("BlueShorad", "Blue SHORAD", SamSet, 22000, 600, "blue") -- myshorad:SwitchDebug(true) @@ -405,7 +424,8 @@ do -- mymantis:AddShorad(myshorad,720) -- mymantis:Start() function SHORAD:WakeUpShorad(TargetGroup, Radius, ActiveTimer, TargetCat) - self:T({TargetGroup, Radius, ActiveTimer, TargetCat}) + self:I(self.lid .. " WakeUpShorad") + self:I({TargetGroup, Radius, ActiveTimer, TargetCat}) local targetcat = TargetCat or Object.Category.UNIT local targetgroup = TargetGroup local targetvec2 = nil @@ -432,17 +452,17 @@ do group:OptionAlarmStateGreen() end local text = string.format("Sleeping SHORAD %s", group:GetName()) - self:T(text) + self:I(text) local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug) end -- go through set and find the one(s) to activate for _,_group in pairs (shoradset) do if _group:IsAnyInZone(targetzone) then local text = string.format("Waking up SHORAD %s", _group:GetName()) - self:T(text) + self:I(text) local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug) if self.UseEmOnOff then - _group:SetAIOn() + --_group:SetAIOn() _group:EnableEmission(true) end _group:OptionAlarmStateRed() @@ -454,14 +474,15 @@ do 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 - function SHORAD:OnEventShot( EventData ) - self:T( { EventData } ) - + function SHORAD:HandleEventShot( EventData ) + self:I( { EventData } ) + self:I(self.lid .. " HandleEventShot") --local ShootingUnit = EventData.IniDCSUnit --local ShootingUnitName = EventData.IniDCSUnitName local ShootingWeapon = EventData.Weapon -- Identify the weapon fired @@ -473,24 +494,24 @@ do local IsDetected = self:_ShotIsDetected() -- convert to text local DetectedText = "false" - if IsDetected then + if IsDetected then DetectedText = "true" end local text = string.format("%s Missile Launched = %s | Detected probability state is %s", self.lid, ShootingWeaponName, DetectedText) - self:T( text ) + self:I( text ) local m = MESSAGE:New(text,10,"Info"):ToAllIf(self.debug) -- if (self:_CheckHarms(ShootingWeaponName) or self:_CheckMavs(ShootingWeaponName)) and IsDetected then -- get target data local targetdata = EventData.Weapon:getTarget() -- Identify target local targetcat = targetdata:getCategory() -- Identify category - self:T(string.format("Target Category (3=STATIC, 1=UNIT)= %s",tostring(targetcat))) + self:I(string.format("Target Category (3=STATIC, 1=UNIT)= %s",tostring(targetcat))) local targetunit = nil if targetcat == Object.Category.UNIT then -- UNIT targetunit = UNIT:Find(targetdata) elseif targetcat == Object.Category.STATIC then -- STATIC targetunit = STATIC:Find(targetdata) - end + end --local targetunitname = Unit.getName(targetdata) -- Unit name if targetunit and targetunit:IsAlive() then local targetunitname = targetunit:GetName() @@ -505,23 +526,23 @@ do targetgroupname = targetunitname end local text = string.format("%s Missile Target = %s", self.lid, tostring(targetgroupname)) - self:T( text ) + self:I( text ) local m = MESSAGE:New(text,10,"Info"):ToAllIf(self.debug) - -- check if we or a SAM site are the target + -- check if we or a SAM site are the target --local TargetGroup = EventData.TgtGroup -- Wrapper.Group#GROUP local shotatus = self:_CheckShotAtShorad(targetgroupname) --#boolean local shotatsams = self:_CheckShotAtSams(targetgroupname) --#boolean -- if being shot at, find closest SHORADs to activate if shotatsams or shotatus then - self:T({shotatsams=shotatsams,shotatus=shotatus}) + self:I({shotatsams=shotatsams,shotatus=shotatus}) self:WakeUpShorad(targetgroupname, self.Radius, self.ActiveTimer, targetcat) end - end + end end end - end + end -- end ----------------------------------------------------------------------- -- SHORAD end ------------------------------------------------------------------------ +----------------------------------------------------------------------- \ No newline at end of file