Merge branch 'master' into develop

This commit is contained in:
Frank 2020-12-27 17:59:57 +01:00
commit 9708de70c7

View File

@ -32,11 +32,12 @@
-- @field #string EWR_Templates_Prefix Prefix to build the #GROUP_SET for EWR group
-- @field @{Core.Set#GROUP_SET} EWR_Group The EWR #GROUP_SET
-- @field @{Core.Set#GROUP_SET} Adv_EWR_Group The EWR #GROUP_SET used for advanced mode
-- @field #string SEAD_Template_CC The ME name of the HQ object
-- @field @{Wrapper.Group#GROUP} SEAD_CC The #GROUP object of the HQ
-- @field #string HQ_Template_CC The ME name of the HQ object
-- @field @{Wrapper.Group#GROUP} HQ_CC The #GROUP object of the HQ
-- @field #table SAM_Table Table of SAM sites
-- @field #string lid Prefix for logging
-- @field @{Functional.Detection#DETECTION_AREAS} Detection The #DETECTION_AREAS object
-- @field @{Functional.Detection#DETECTION_AREAS} Detection The #DETECTION_AREAS object for EWR
-- @field @{Functional.Detection#DETECTION_AREAS} AWACS_Detection The #DETECTION_AREAS object for AWACS
-- @field #boolean debug Switch on extra messages
-- @field #boolean verbose Switch on extra logging
-- @field #number checkradius Radius of the SAM sites
@ -48,6 +49,8 @@
-- @field #boolean advanced Use advanced mode, will decrease reactivity of MANTIS, if HQ and/or EWR network dies. Set SAMs to RED state if both are dead. Requires usage of an HQ object
-- @field #number adv_ratio Percentage to use for advanced mode, defaults to 100%
-- @field #number adv_state Advanced mode state tracker
-- @field #boolean advAwacs Boolean switch to use Awacs as a separate detection stream
-- @field #number awacsrange Detection range of an optional Awacs unit
-- @extends @{Core.Base#BASE}
@ -65,7 +68,33 @@
-- Set up your EWR system in the mission editor. Name the groups with common prefix like "Red EWR". Can be e.g. AWACS or a combination of AWACS and Search Radars like e.g. EWR 1L13 etc.
-- [optional] Set up your HQ. Can be any group, e.g. a command vehicle.
--
-- # 1. Start up your MANTIS
-- # 1. Basic tactical considerations when setting up your SAM sites
--
-- ## 1.1 Radar systems and AWACS
--
-- Typically, your setup should consist of EWR (early warning) radars to detect and track targets, accompanied by AWACS if your scenario forsees that. Ensure that your EWR radars have a good coverage of the area you want to track.
-- **Location** is of highest importantance here. Whilst AWACS in DCS has almost the "all seeing eye", EWR don't have that. Choose your location wisely, against a mountain backdrop or inside a valley even the best EWR system
-- doesn't work well. Prefer higher-up locations with a good view; use F7 in-game to check where you actually placed your EWR and have a look around. Apart from the obvious choice, do also consider other radar units
-- for this role, most have "SR" (search radar) or "STR" (search and track radar) in their names, use the encyclopedia to see what they actually do.
--
-- ## 1.2 SAM sites
--
-- Typically your SAM should cover all attack ranges. The closer the enemy gets, the more systems you will need to deploy to defend your location. Use a combination of long-range systems like the SA-10/11, midrange like SA-6 and short-range like
-- SA-2 for defense (Patriot, Hawk, Gepard, Blindfire for the blue side). For close-up defense and defense against HARMs or low-flying aircraft, helicopters it is also advisable to deploy SA-15 TOR systems, Shilka, Strela and Tunguska units, as well as manpads (Think Gepard, Avenger, Chaparral,
-- Linebacker, Roland systems for the blue side). If possible, overlap ranges for mutual coverage.
--
-- ## 1.3 Typical problems
--
-- Often times, people complain because the detection cannot "see" oncoming targets and/or Mantis switches on too late. Three typial problems here are
--
-- * bad placement of radar units,
-- * overestimation how far units can "see" and
-- * not taking into account that a SAM site will take (e.g for a SA-6) 30-40 seconds between switching to RED, acquiring the target and firing.
--
-- An attacker doing 350knots will cover ca 180meters/second or thus more than 6km until the SA-6 fires. Use triggers zones and the ruler in the missione editor to understand distances and zones. Take into account that the ranges given by the circles
-- in the mission editor are absolute maximum ranges; in-game this is rather 50-75% of that depending on the system. Fiddle with placement and options to see what works best for your scenario, and remember **everything in here is in meters**.
--
-- # 2. Start up your MANTIS with a basic setting
--
-- `myredmantis = MANTIS:New("myredmantis","Red SAM","Red EWR",nil,"red",false)`
--
@ -80,13 +109,17 @@
-- to fine-tune your setup.
--
-- `myredmantis:Start()`
--
-- If you want to use a separate AWACS unit (default detection range: 250km) to support your EWR system, use e.g. the following setup:
--
-- `mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")`
--
-- # 2. Default settings
-- # 3. Default settings
--
-- By default, the following settings are active:
--
-- * SAM_Templates_Prefix = "Red SAM" - SAM site group names in the mission editor begin with "Red SAM"
-- * EWR_Templates_Prefix = "Red EWR" - EWR group names in the mission editor begin with "Red EWR" - can also be AWACS
-- * EWR_Templates_Prefix = "Red EWR" - EWR group names in the mission editor begin with "Red EWR" - can also be combined with an AWACS unit
-- * checkradius = 25000 (meters) - SAMs will engage enemy flights, if they are within a 25km around each SAM site - `MANTIS:SetSAMRadius(radius)`
-- * grouping = 5000 (meters) - Detection (EWR) will group enemy flights to areas of 5km for tracking - `MANTIS:SetEWRGrouping(radius)`
-- * acceptrange = 80000 (meters) - Detection (EWR) will on consider flights inside a 80km radius - `MANTIS:SetEWRRange(radius)`
@ -96,6 +129,11 @@
-- * autorelocate = false - HQ and (mobile) EWR system will not relocate in random intervals between 30mins and 1 hour - `MANTIS:SetAutoRelocate(hq, ewr)`
-- * debug = false - Debugging reports on screen are set to off - `MANTIS:Debug(onoff)`
--
-- # 4. Advanced Mode
--
-- Advanced mode will *decrease* reactivity of MANTIS, if HQ and/or EWR network dies. Awacs is counted as one EWR unit. It will set SAMs to RED state if both are dead. Requires usage of an **HQ** object and the **dynamic** option.
-- E.g. `mymantis:SetAdvancedMode( true, 90 )`
-- Use this option if you want to make use of or allow advanced SEAD tactics.
--
-- @field #MANTIS
MANTIS = {
@ -106,11 +144,12 @@ MANTIS = {
EWR_Templates_Prefix = "",
EWR_Group = nil,
Adv_EWR_Group = nil,
SEAD_Template_CC = "",
SEAD_CC = nil,
HQ_Template_CC = "",
HQ_CC = nil,
SAM_Table = {},
lid = "",
Detection = nil,
AWACS_Detection = nil,
debug = false,
checkradius = 25000,
grouping = 5000,
@ -121,7 +160,10 @@ MANTIS = {
advanced = false,
adv_ratio = 100,
adv_state = 0,
verbose = false
AWACS_Prefix = "",
advAwacs = false,
verbose = false,
awacsrange = 250000
}
-----------------------------------------------------------------------
@ -133,22 +175,24 @@ do
--@param #MANTIS self
--@param #string name Name of this MANTIS for reporting
--@param #string samprefix Prefixes for the SAM groups from the ME, e.g. all groups starting with "Red Sam..."
--@param #string ewrprefix Prefixes for the EWR and AWACS groups from the ME, e.g. all groups starting with "Red EWR..."
--@param #string ewrprefix Prefixes for the EWR groups from the ME, e.g. all groups starting with "Red EWR..."
--@param #string hq Group name of your HQ (optional)
--@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)
--@param #boolean dynamic Use constant (true) filtering or just filter once (false, default) (optional)
--@param #string awacs Group name of your Awacs (optional)
--@return #MANTIS self
function MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic)
function MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic,awacs)
-- DONE: Create some user functions for these
-- DONE: Make HQ useful
-- DONE: Set SAMs to auto if EWR dies
-- TODO: Refresh SAM table in dynamic mode
-- DONE: Refresh SAM table in dynamic mode
-- DONE: Treat Awacs separately, since they might be >80km off site
self.name = name or "mymantis"
self.SAM_Templates_Prefix = samprefix or "Red SAM"
self.EWR_Templates_Prefix = ewrprefix or "Red EWR"
self.SEAD_Template_CC = hq or nil
self.HQ_Template_CC = hq or nil
self.Coalition = coaltion or "red"
self.SAM_Table = {}
self.dynamic = dynamic or false
@ -164,9 +208,16 @@ do
self.adv_state = 0
self.verbose = false
self.Adv_EWR_Group = nil
self.AWACS_Prefix = awacs or nil
self.awacsrange = 250000 --TODO: 250km, User Function to change
if type(awacs) == "string" then
self.advAwacs = true
else
self.advAwacs = false
end
-- @field #string version
self.version="0.3.0"
self.version="0.3.5"
env.info(string.format("***** Starting MANTIS Version %s *****", self.version))
-- Set the string id for output to DCS.log file.
@ -193,9 +244,8 @@ do
end
-- set up CC
if self.SEAD_Template_CC then
self.SEAD_CC = GROUP:FindByName(self.SEAD_Template_CC)
--self.SEAD_CC = COMMANDCENTER:New(GROUP:FindByName(self.SEAD_Template_CC),self.SEAD_Template_CC)
if self.HQ_Template_CC then
self.HQ_CC = GROUP:FindByName(self.HQ_Template_CC)
end
-- Inherit everything from BASE class.
local self = BASE:Inherit(self, BASE:New()) -- #MANTIS
@ -269,13 +319,25 @@ do
-- @param #MANTIS self
-- @return Wrapper.GROUP#GROUP The HQ #GROUP object or *nil* if it doesn't exist
function MANTIS:GetCommandCenter()
if self.SEAD_CC then
return self.SEAD_CC
if self.HQ_CC then
return self.HQ_CC
else
return nil
end
end
--- Function to set separate AWACS detection instance
-- @param #MANTIS self
-- @param #string prefix Name of the AWACS group in the mission editor
function MANTIS:SetAwacs(prefix)
if prefix ~= nil then
if type(prefix) == "string" then
self.AWACS_Prefix = prefix
self.advAwacs = true
end
end
end
--- Function to set the HQ object for further use
-- @param #MANTIS self
-- @param Wrapper.GROUP#GROUP The HQ #GROUP object to be set as HQ
@ -283,11 +345,11 @@ do
local group = group or nil
if group ~= nil then
if type(group) == "string" then
self.SEAD_CC = GROUP:FindByName(group)
self.SEAD_Template_CC = group
self.HQ_CC = GROUP:FindByName(group)
self.HQ_Template_CC = group
else
self.SEAD_CC = group
self.SEAD_Template_CC = group:GetName()
self.HQ_CC = group
self.HQ_Template_CC = group:GetName()
end
end
end
@ -304,13 +366,13 @@ do
-- @param #MANTIS self
-- @param #boolean onoff If true, will activate Advanced Mode
-- @param #number ratio [optional] Percentage to use for advanced mode, defaults to 100%
-- @usage Advanced mode will *decrease* reactivity of MANTIS, if HQ and/or EWR network dies. Set SAMs to RED state if both are dead. Requires usage of an **HQ** object
-- @usage Advanced mode will *decrease* reactivity of MANTIS, if HQ and/or EWR network dies. Set SAMs to RED state if both are dead. Requires usage of an **HQ** object and the **dynamic** option.
-- E.g. `mymantis:SetAdvancedMode(true, 90)`
function MANTIS:SetAdvancedMode(onoff, ratio)
self:F({onoff, ratio})
local onoff = onoff or false
local ratio = ratio or 100
if (type(self.SEAD_Template_CC) == "string") and onoff and self.dynamic then
if (type(self.HQ_Template_CC) == "string") and onoff and self.dynamic then
self.adv_ratio = ratio
self.advanced = true
self.adv_state = 0
@ -333,7 +395,7 @@ do
if self.verbose then env.info(text) end
-- start check
if self.advanced then
local hq = self.SEAD_Template_CC
local hq = self.HQ_Template_CC
local hqgrp = GROUP:FindByName(hq)
if hqgrp then
if hqgrp:IsAlive() then -- ok we're on, hq exists and as alive
@ -360,6 +422,14 @@ do
local EWR_Group = self.Adv_EWR_Group
--local EWR_Set = EWR_Group.Set
local nalive = EWR_Group:CountAlive()
if self.advAwacs then
local awacs = GROUP:FindByName(self.AWACS_Prefix)
if awacs ~= nil then
if awacs:IsAlive() then
nalive = nalive+1
end
end
end
env.info(self.lid..string.format(" No of EWR alive is %d", nalive))
if nalive > 0 then
return true
@ -426,8 +496,8 @@ do
if self.verbose then env.info(text) end
if self.autorelocate then
-- relocate HQ
if self.autorelocateunits.HQ and self.SEAD_CC then --only relocate if HQ exists
local _hqgrp = self.SEAD_CC
if self.autorelocateunits.HQ and self.HQ_CC then --only relocate if HQ exists
local _hqgrp = self.HQ_CC
self:T(self.lid.." Relocating HQ")
local text = self.lid.." Relocating HQ"
local m= MESSAGE:New(text,10,"MANTIS"):ToAll()
@ -510,6 +580,38 @@ do
return _MANTISdetection
end
--- Function to start the detection via AWACS if defined as separate
-- @param #MANTIS self
-- @return Functional.Detection #DETECTION_AREAS The running detection set
function MANTIS:StartAwacsDetection()
self:F(self.lid.."Starting Awacs Detection")
-- start detection
local group = self.AWACS_Prefix
local groupset = SET_GROUP:New():FilterPrefixes(group):FilterCoalitions(self.Coalition):FilterStart()
local grouping = self.grouping or 5000
--local acceptrange = self.acceptrange or 80000
local interval = self.detectinterval or 60
--@param Functional.Detection #DETECTION_AREAS _MANTISdetection [internal] The MANTIS detection object
_MANTISAwacs = DETECTION_AREAS:New( groupset, grouping ) --[internal] Grouping detected objects to 5000m zones
_MANTISAwacs:FilterCategories({ Unit.Category.AIRPLANE, Unit.Category.HELICOPTER })
_MANTISAwacs:SetAcceptRange(self.awacsrange) --250km
_MANTISAwacs:SetRefreshTimeInterval(interval)
_MANTISAwacs:Start()
function _MANTISAwacs:OnAfterDetectedItem(From,Event,To,DetectedItem)
--BASE:I( { From, Event, To, DetectedItem })
local debug = false
if DetectedItem.IsDetected and debug then
local Coordinate = DetectedItem.Coordinate -- Core.Point#COORDINATE
local text = "Awacs Detection at "..Coordinate:ToStringLLDMS()
local m = MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
end
end
return _MANTISAwacs
end
--- Function to set the SAM start state
-- @param #MANTIS self
-- @return #MANTIS self
@ -524,24 +626,53 @@ do
local engagerange = self.engagerange -- firing range in % of max
--cycle through groups and set alarm state etc
for _i,_group in pairs (SAM_Grps) do
--for i=1,#SAM_Grps do
local group = _group
group:OptionAlarmStateGreen()
--group:OptionROEHoldFire()
--group:SetAIOn()
group:OptionAlarmStateGreen() -- AI off
group:SetOption(AI.Option.Ground.id.AC_ENGAGEMENT_RANGE_RESTRICTION,engagerange) --default engagement will be 75% of firing range
if group:IsGround() then
local grpname = group:GetName()
local grpcoord = group:GetCoordinate()
table.insert( SAM_Tbl, {grpname, grpcoord})
table.insert( SEAD_Grps, grpname )
end
end
self.SAM_Table = SAM_Tbl
-- make SAMs evasive
local mysead = SEAD:New( SEAD_Grps )
mysead:SetEngagementRange(engagerange)
self.mysead = mysead
return self
end
--- (Internal) Function to update SAM table and SEAD state
-- @param #MANTIS self
-- @return #MANTIS self
function MANTIS:_RefreshSAMTable()
self:F(self.lid.."Setting SAM Start States")
-- Requires SEAD 0.2.2 or better
-- get SAM Group
local SAM_SET = self.SAM_Group
local SAM_Grps = SAM_SET.Set --table of objects
local SAM_Tbl = {} -- table of SAM defense zones
local SEAD_Grps = {} -- table of SAM names to make evasive
local engagerange = self.engagerange -- firing range in % of max
--cycle through groups and set alarm state etc
for _i,_group in pairs (SAM_Grps) do
local group = _group
group:SetOption(AI.Option.Ground.id.AC_ENGAGEMENT_RANGE_RESTRICTION,engagerange) --engagement will be 75% of firing range
if group:IsGround() then
local grpname = group:GetName()
local grpcoord = group:GetCoordinate()
--local grpzone = ZONE_UNIT:New(grpname,group:GetUnit(1),5000) -- defense zone around each SAM site 5000 meters
--table.insert( SAM_Tbl, {grpname, grpcoord, grpzone})
table.insert( SAM_Tbl, {grpname, grpcoord}) -- make the table lighter, as I don't really use the zone here
table.insert( SEAD_Grps, grpname )
end
end
self.SAM_Table = SAM_Tbl
-- make SAMs evasive
SEAD:New( SEAD_Grps )
if self.mysead ~= nil then
local mysead = self.mysead
mysead:UpdateSet( SEAD_Grps )
end
return self
end
@ -556,11 +687,19 @@ do
self:F(self.lid.."Starting MANTIS")
self:SetSAMStartState()
self.Detection = self:StartDetection()
if self.advAwacs then
self.AWACS_Detection = self:StartAwacsDetection()
end
-- detection function
local function check(detection)
--get detected set
local detset = detection:GetDetectedItemCoordinates()
self:F("Check:", {detset})
-- randomly update SAM Table
local rand = math.random(1,100)
if rand > 65 then -- 1/3 of cases
self:_RefreshSAMTable()
end
-- switch SAMs on/off if (n)one of the detected groups is inside their reach
local samset = self:_GetSAMTable() -- table of i.1=names, i.2=coordinates
for _,_data in pairs (samset) do
@ -596,7 +735,6 @@ do
end
-- check advanced state
local function checkadvstate()
if self.advanced then
local interval, oldstate = self:_CheckAdvState()
local newstate = self.adv_state
if newstate ~= oldstate then
@ -606,6 +744,10 @@ do
if self.MantisTimer.isrunning then
self.MantisTimer:Stop()
self.MantisTimer.isrunning = false
end -- stop Awacs timer
if self.MantisATimer.isrunning then
self.MantisATimer:Stop()
self.MantisATimer.isrunning = false
end -- stop timer
local samset = self:_GetSAMTable() -- table of i.1=names, i.2=coordinates
for _,_data in pairs (samset) do
@ -621,25 +763,43 @@ do
self.MantisTimer:Stop()
self.MantisTimer.isrunning = false
end
if self.MantisATimer.isrunning then
self.MantisATimer:Stop()
self.MantisATimer.isrunning = false
end
self.MantisTimer = TIMER:New(check,self.Detection)
self.MantisTimer:Start(5,interval,nil)
self.MantisTimer.isrunning = true
if self.advAwacs then
self.MantisATimer = TIMER:New(check,self.AWACS_Detection)
self.MantisATimer:Start(15,interval,nil)
self.MantisATimer.isrunning = true
end
end
end -- end newstate vs oldstate
end -- end advanced
end
-- timers to run the system
local interval = self.detectinterval
self.MantisTimer = TIMER:New(check,self.Detection)
self.MantisTimer:Start(5,interval,nil)
self.MantisTimer.isrunning = true
-- Awacs timer
if self.advAwacs then
self.MantisATimer = TIMER:New(check,self.AWACS_Detection)
self.MantisATimer:Start(15,interval,nil)
self.MantisATimer.isrunning = true
end
-- timer to relocate HQ and EWR
local relointerval = math.random(1800,3600) -- random between 30 and 60 mins
self.MantisReloTimer = TIMER:New(relocate)
self.MantisReloTimer:Start(relointerval,relointerval,nil)
if self.autorelocate then
local relointerval = math.random(1800,3600) -- random between 30 and 60 mins
self.MantisReloTimer = TIMER:New(relocate)
self.MantisReloTimer:Start(relointerval,relointerval,nil)
end
-- timer for advanced state check
self.MantisAdvTimer = TIMER:New(checkadvstate)
self.MantisAdvTimer:Start(30,interval*5,nil)
if self.advanced then
self.MantisAdvTimer = TIMER:New(checkadvstate)
self.MantisAdvTimer:Start(30,interval*5,nil)
end
return self
end
@ -650,6 +810,9 @@ do
if self.MantisTimer.isrunning then
self.MantisTimer:Stop()
end
if self.MantisATimer.isrunning then
self.MantisATimer:Stop()
end
if self.autorelocate then
self.MantisReloTimer:Stop()
end