mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Merge branch 'master' into develop
This commit is contained in:
commit
43680c2fc3
@ -880,8 +880,8 @@ do -- SET_GROUP
|
|||||||
--
|
--
|
||||||
-- * @{#SET_GROUP.FilterCoalitions}: Builds the SET_GROUP with the groups belonging to the coalition(s).
|
-- * @{#SET_GROUP.FilterCoalitions}: Builds the SET_GROUP with the groups belonging to the coalition(s).
|
||||||
-- * @{#SET_GROUP.FilterCategories}: Builds the SET_GROUP with the groups belonging to the category(ies).
|
-- * @{#SET_GROUP.FilterCategories}: Builds the SET_GROUP with the groups belonging to the category(ies).
|
||||||
-- * @{#SET_GROUP.FilterCountries}: Builds the SET_GROUP with the gruops belonging to the country(ies).
|
-- * @{#SET_GROUP.FilterCountries}: Builds the SET_GROUP with the groups belonging to the country(ies).
|
||||||
-- * @{#SET_GROUP.FilterPrefixes}: Builds the SET_GROUP with the groups starting with the same prefix string(s).
|
-- * @{#SET_GROUP.FilterPrefixes}: Builds the SET_GROUP with the groups *containing* the given string in the group name. **Attention!** Bad naming convention, as this not really filtering *prefixes*.
|
||||||
-- * @{#SET_GROUP.FilterActive}: Builds the SET_GROUP with the groups that are only active. Groups that are inactive (late activation) won't be included in the set!
|
-- * @{#SET_GROUP.FilterActive}: Builds the SET_GROUP with the groups that are only active. Groups that are inactive (late activation) won't be included in the set!
|
||||||
--
|
--
|
||||||
-- For the Category Filter, extra methods have been added:
|
-- For the Category Filter, extra methods have been added:
|
||||||
@ -1241,10 +1241,10 @@ do -- SET_GROUP
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of groups of defined GROUP prefixes.
|
--- Builds a set of groups that contain the given string in their group name.
|
||||||
-- All the groups starting with the given prefixes will be included within the set.
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all groups that **contain** the string.
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @param #string Prefixes The prefix of which the group name starts with.
|
-- @param #string Prefixes The string pattern(s) that needs to be contained in the group name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_GROUP self
|
-- @return #SET_GROUP self
|
||||||
function SET_GROUP:FilterPrefixes( Prefixes )
|
function SET_GROUP:FilterPrefixes( Prefixes )
|
||||||
if not self.Filter.GroupPrefixes then
|
if not self.Filter.GroupPrefixes then
|
||||||
@ -1843,7 +1843,7 @@ do -- SET_UNIT
|
|||||||
-- * @{#SET_UNIT.FilterCategories}: Builds the SET_UNIT with the units belonging to the category(ies).
|
-- * @{#SET_UNIT.FilterCategories}: Builds the SET_UNIT with the units belonging to the category(ies).
|
||||||
-- * @{#SET_UNIT.FilterTypes}: Builds the SET_UNIT with the units belonging to the unit type(s).
|
-- * @{#SET_UNIT.FilterTypes}: Builds the SET_UNIT with the units belonging to the unit type(s).
|
||||||
-- * @{#SET_UNIT.FilterCountries}: Builds the SET_UNIT with the units belonging to the country(ies).
|
-- * @{#SET_UNIT.FilterCountries}: Builds the SET_UNIT with the units belonging to the country(ies).
|
||||||
-- * @{#SET_UNIT.FilterPrefixes}: Builds the SET_UNIT with the units starting with the same prefix string(s).
|
-- * @{#SET_UNIT.FilterPrefixes}: Builds the SET_UNIT with the units sharing the same string(s) in their name. **ATTENTION!** Bad naming convention as this *does not* only filter *prefixes*.
|
||||||
-- * @{#SET_UNIT.FilterActive}: Builds the SET_UNIT with the units that are only active. Units that are inactive (late activation) won't be included in the set!
|
-- * @{#SET_UNIT.FilterActive}: Builds the SET_UNIT with the units that are only active. Units that are inactive (late activation) won't be included in the set!
|
||||||
--
|
--
|
||||||
-- Once the filter criteria have been set for the SET_UNIT, you can start filtering using:
|
-- Once the filter criteria have been set for the SET_UNIT, you can start filtering using:
|
||||||
@ -2105,10 +2105,10 @@ do -- SET_UNIT
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of units of defined unit prefixes.
|
--- Builds a set of UNITs that contain a given string in their unit name.
|
||||||
-- All the units starting with the given prefixes will be included within the set.
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all units that **contain** the string.
|
||||||
-- @param #SET_UNIT self
|
-- @param #SET_UNIT self
|
||||||
-- @param #string Prefixes The prefix of which the unit name starts with.
|
-- @param #string Prefixes The string pattern(s) that needs to be contained in the unit name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_UNIT self
|
-- @return #SET_UNIT self
|
||||||
function SET_UNIT:FilterPrefixes( Prefixes )
|
function SET_UNIT:FilterPrefixes( Prefixes )
|
||||||
if not self.Filter.UnitPrefixes then
|
if not self.Filter.UnitPrefixes then
|
||||||
@ -2963,7 +2963,7 @@ do -- SET_STATIC
|
|||||||
-- * @{#SET_STATIC.FilterCategories}: Builds the SET_STATIC with the units belonging to the category(ies).
|
-- * @{#SET_STATIC.FilterCategories}: Builds the SET_STATIC with the units belonging to the category(ies).
|
||||||
-- * @{#SET_STATIC.FilterTypes}: Builds the SET_STATIC with the units belonging to the unit type(s).
|
-- * @{#SET_STATIC.FilterTypes}: Builds the SET_STATIC with the units belonging to the unit type(s).
|
||||||
-- * @{#SET_STATIC.FilterCountries}: Builds the SET_STATIC with the units belonging to the country(ies).
|
-- * @{#SET_STATIC.FilterCountries}: Builds the SET_STATIC with the units belonging to the country(ies).
|
||||||
-- * @{#SET_STATIC.FilterPrefixes}: Builds the SET_STATIC with the units starting with the same prefix string(s).
|
-- * @{#SET_STATIC.FilterPrefixes}: Builds the SET_STATIC with the units containing the same string(s) in their name. **ATTENTION** bad naming convention as this *does not** only filter *prefixes*.
|
||||||
--
|
--
|
||||||
-- Once the filter criteria have been set for the SET_STATIC, you can start filtering using:
|
-- Once the filter criteria have been set for the SET_STATIC, you can start filtering using:
|
||||||
--
|
--
|
||||||
@ -3176,10 +3176,10 @@ do -- SET_STATIC
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of units of defined unit prefixes.
|
--- Builds a set of STATICs that contain the given string in their name.
|
||||||
-- All the units starting with the given prefixes will be included within the set.
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all statics that **contain** the string.
|
||||||
-- @param #SET_STATIC self
|
-- @param #SET_STATIC self
|
||||||
-- @param #string Prefixes The prefix of which the unit name starts with.
|
-- @param #string Prefixes The string pattern(s) that need to be contained in the static name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_STATIC self
|
-- @return #SET_STATIC self
|
||||||
function SET_STATIC:FilterPrefixes( Prefixes )
|
function SET_STATIC:FilterPrefixes( Prefixes )
|
||||||
if not self.Filter.StaticPrefixes then
|
if not self.Filter.StaticPrefixes then
|
||||||
@ -3675,7 +3675,7 @@ do -- SET_CLIENT
|
|||||||
-- * @{#SET_CLIENT.FilterCategories}: Builds the SET_CLIENT with the clients belonging to the category(ies).
|
-- * @{#SET_CLIENT.FilterCategories}: Builds the SET_CLIENT with the clients belonging to the category(ies).
|
||||||
-- * @{#SET_CLIENT.FilterTypes}: Builds the SET_CLIENT with the clients belonging to the client type(s).
|
-- * @{#SET_CLIENT.FilterTypes}: Builds the SET_CLIENT with the clients belonging to the client type(s).
|
||||||
-- * @{#SET_CLIENT.FilterCountries}: Builds the SET_CLIENT with the clients belonging to the country(ies).
|
-- * @{#SET_CLIENT.FilterCountries}: Builds the SET_CLIENT with the clients belonging to the country(ies).
|
||||||
-- * @{#SET_CLIENT.FilterPrefixes}: Builds the SET_CLIENT with the clients starting with the same prefix string(s).
|
-- * @{#SET_CLIENT.FilterPrefixes}: Builds the SET_CLIENT with the clients containing the same string(s) in their unit/pilot name. **ATTENTION!** Bad naming convention as this *does not* only filter *prefixes*.
|
||||||
-- * @{#SET_CLIENT.FilterActive}: Builds the SET_CLIENT with the units that are only active. Units that are inactive (late activation) won't be included in the set!
|
-- * @{#SET_CLIENT.FilterActive}: Builds the SET_CLIENT with the units that are only active. Units that are inactive (late activation) won't be included in the set!
|
||||||
--
|
--
|
||||||
-- Once the filter criteria have been set for the SET_CLIENT, you can start filtering using:
|
-- Once the filter criteria have been set for the SET_CLIENT, you can start filtering using:
|
||||||
@ -3858,10 +3858,10 @@ do -- SET_CLIENT
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of clients of defined client prefixes.
|
--- Builds a set of CLIENTs that contain the given string in their unit/pilot name.
|
||||||
-- All the clients starting with the given prefixes will be included within the set.
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all clients that **contain** the string.
|
||||||
-- @param #SET_CLIENT self
|
-- @param #SET_CLIENT self
|
||||||
-- @param #string Prefixes The prefix of which the client name starts with.
|
-- @param #string Prefixes The string pattern(s) that needs to be contained in the unit/pilot name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_CLIENT self
|
-- @return #SET_CLIENT self
|
||||||
function SET_CLIENT:FilterPrefixes( Prefixes )
|
function SET_CLIENT:FilterPrefixes( Prefixes )
|
||||||
if not self.Filter.ClientPrefixes then
|
if not self.Filter.ClientPrefixes then
|
||||||
@ -4114,7 +4114,7 @@ do -- SET_PLAYER
|
|||||||
-- * @{#SET_PLAYER.FilterCategories}: Builds the SET_PLAYER with the clients belonging to the category(ies).
|
-- * @{#SET_PLAYER.FilterCategories}: Builds the SET_PLAYER with the clients belonging to the category(ies).
|
||||||
-- * @{#SET_PLAYER.FilterTypes}: Builds the SET_PLAYER with the clients belonging to the client type(s).
|
-- * @{#SET_PLAYER.FilterTypes}: Builds the SET_PLAYER with the clients belonging to the client type(s).
|
||||||
-- * @{#SET_PLAYER.FilterCountries}: Builds the SET_PLAYER with the clients belonging to the country(ies).
|
-- * @{#SET_PLAYER.FilterCountries}: Builds the SET_PLAYER with the clients belonging to the country(ies).
|
||||||
-- * @{#SET_PLAYER.FilterPrefixes}: Builds the SET_PLAYER with the clients starting with the same prefix string(s).
|
-- * @{#SET_PLAYER.FilterPrefixes}: Builds the SET_PLAYER with the clients sharing the same string(s) in their unit/pilot name. **ATTENTION** Bad naming convention as this *does not* only filter prefixes.
|
||||||
--
|
--
|
||||||
-- Once the filter criteria have been set for the SET_PLAYER, you can start filtering using:
|
-- Once the filter criteria have been set for the SET_PLAYER, you can start filtering using:
|
||||||
--
|
--
|
||||||
@ -4293,10 +4293,10 @@ do -- SET_PLAYER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of clients of defined client prefixes.
|
--- Builds a set of PLAYERs that contain the given string in their unit/pilot name.
|
||||||
-- All the clients starting with the given prefixes will be included within the set.
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all player clients that **contain** the string.
|
||||||
-- @param #SET_PLAYER self
|
-- @param #SET_PLAYER self
|
||||||
-- @param #string Prefixes The prefix of which the client name starts with.
|
-- @param #string Prefixes The string pattern(s) that needs to be contained in the unit/pilot name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_PLAYER self
|
-- @return #SET_PLAYER self
|
||||||
function SET_PLAYER:FilterPrefixes( Prefixes )
|
function SET_PLAYER:FilterPrefixes( Prefixes )
|
||||||
if not self.Filter.ClientPrefixes then
|
if not self.Filter.ClientPrefixes then
|
||||||
@ -4874,7 +4874,7 @@ do -- SET_CARGO
|
|||||||
-- Filter criteria are defined by:
|
-- Filter criteria are defined by:
|
||||||
--
|
--
|
||||||
-- * @{#SET_CARGO.FilterCoalitions}: Builds the SET_CARGO with the cargos belonging to the coalition(s).
|
-- * @{#SET_CARGO.FilterCoalitions}: Builds the SET_CARGO with the cargos belonging to the coalition(s).
|
||||||
-- * @{#SET_CARGO.FilterPrefixes}: Builds the SET_CARGO with the cargos containing the prefix string(s).
|
-- * @{#SET_CARGO.FilterPrefixes}: Builds the SET_CARGO with the cargos containing the same string(s). **ATTENTION** Bad naming convention as this *does not* only filter *prefixes*.
|
||||||
-- * @{#SET_CARGO.FilterTypes}: Builds the SET_CARGO with the cargos belonging to the cargo type(s).
|
-- * @{#SET_CARGO.FilterTypes}: Builds the SET_CARGO with the cargos belonging to the cargo type(s).
|
||||||
-- * @{#SET_CARGO.FilterCountries}: Builds the SET_CARGO with the cargos belonging to the country(ies).
|
-- * @{#SET_CARGO.FilterCountries}: Builds the SET_CARGO with the cargos belonging to the country(ies).
|
||||||
--
|
--
|
||||||
@ -5036,10 +5036,10 @@ do -- SET_CARGO
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (R2.1) Builds a set of cargos of defined cargo prefixes.
|
--- Builds a set of CARGOs that contain a given string in their name.
|
||||||
-- All the cargos starting with the given prefixes will be included within the set.
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all cargos that **contain** the string.
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @param #string Prefixes The prefix of which the cargo name starts with.
|
-- @param #string Prefixes The string pattern(s) that need to be in the cargo name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_CARGO self
|
-- @return #SET_CARGO self
|
||||||
function SET_CARGO:FilterPrefixes( Prefixes ) --R2.1
|
function SET_CARGO:FilterPrefixes( Prefixes ) --R2.1
|
||||||
if not self.Filter.CargoPrefixes then
|
if not self.Filter.CargoPrefixes then
|
||||||
@ -5315,7 +5315,7 @@ do -- SET_ZONE
|
|||||||
-- You can set filter criteria to build the collection of zones in SET_ZONE.
|
-- You can set filter criteria to build the collection of zones in SET_ZONE.
|
||||||
-- Filter criteria are defined by:
|
-- Filter criteria are defined by:
|
||||||
--
|
--
|
||||||
-- * @{#SET_ZONE.FilterPrefixes}: Builds the SET_ZONE with the zones having a certain text pattern of prefix.
|
-- * @{#SET_ZONE.FilterPrefixes}: Builds the SET_ZONE with the zones having a certain text pattern in their name. **ATTENTION!** Bad naming convention as this *does not* only filter *prefixes*.
|
||||||
--
|
--
|
||||||
-- Once the filter criteria have been set for the SET_ZONE, you can start filtering using:
|
-- Once the filter criteria have been set for the SET_ZONE, you can start filtering using:
|
||||||
--
|
--
|
||||||
@ -5450,10 +5450,10 @@ do -- SET_ZONE
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of zones of defined zone prefixes.
|
--- Builds a set of ZONEs that contain the given string in their name.
|
||||||
-- All the zones starting with the given prefixes will be included within the set.
|
-- **ATTENTION!** Bad naming convention as this **does not** filter only **prefixes** but all zones that **contain** the string.
|
||||||
-- @param #SET_ZONE self
|
-- @param #SET_ZONE self
|
||||||
-- @param #string Prefixes The prefix of which the zone name starts with.
|
-- @param #string Prefixes The string pattern(s) that need to be contained in the zone name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_ZONE self
|
-- @return #SET_ZONE self
|
||||||
function SET_ZONE:FilterPrefixes( Prefixes )
|
function SET_ZONE:FilterPrefixes( Prefixes )
|
||||||
if not self.Filter.Prefixes then
|
if not self.Filter.Prefixes then
|
||||||
@ -5652,7 +5652,7 @@ do -- SET_ZONE_GOAL
|
|||||||
-- You can set filter criteria to build the collection of zones in SET_ZONE_GOAL.
|
-- You can set filter criteria to build the collection of zones in SET_ZONE_GOAL.
|
||||||
-- Filter criteria are defined by:
|
-- Filter criteria are defined by:
|
||||||
--
|
--
|
||||||
-- * @{#SET_ZONE_GOAL.FilterPrefixes}: Builds the SET_ZONE_GOAL with the zones having a certain text pattern of prefix.
|
-- * @{#SET_ZONE_GOAL.FilterPrefixes}: Builds the SET_ZONE_GOAL with the zones having a certain text pattern in their name. **ATTENTION!** Bad naming convention as this *does not* only filter *prefixes*.
|
||||||
--
|
--
|
||||||
-- Once the filter criteria have been set for the SET_ZONE_GOAL, you can start filtering using:
|
-- Once the filter criteria have been set for the SET_ZONE_GOAL, you can start filtering using:
|
||||||
--
|
--
|
||||||
@ -5768,10 +5768,10 @@ do -- SET_ZONE_GOAL
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of zones of defined zone prefixes.
|
--- Builds a set of ZONE_GOALs that contain the given string in their name.
|
||||||
-- All the zones starting with the given prefixes will be included within the set.
|
-- **ATTENTION!** Bad naming convention as this **does not** filter only **prefixes** but all zones that **contain** the string.
|
||||||
-- @param #SET_ZONE_GOAL self
|
-- @param #SET_ZONE_GOAL self
|
||||||
-- @param #string Prefixes The prefix of which the zone name starts with.
|
-- @param #string Prefixes The string pattern(s) that needs to be contained in the zone name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_ZONE_GOAL self
|
-- @return #SET_ZONE_GOAL self
|
||||||
function SET_ZONE_GOAL:FilterPrefixes( Prefixes )
|
function SET_ZONE_GOAL:FilterPrefixes( Prefixes )
|
||||||
if not self.Filter.Prefixes then
|
if not self.Filter.Prefixes then
|
||||||
|
|||||||
@ -1001,7 +1001,13 @@ do -- DESIGNATE
|
|||||||
local ID = self.Detection:GetDetectedItemID( DetectedItem )
|
local ID = self.Detection:GetDetectedItemID( DetectedItem )
|
||||||
local MenuText = ID --.. ", " .. Coord:ToStringA2G( AttackGroup )
|
local MenuText = ID --.. ", " .. Coord:ToStringA2G( AttackGroup )
|
||||||
|
|
||||||
MenuText = string.format( "(%3s) %s", Designating, MenuText )
|
-- Use injected MenuName from TaskA2GDispatcher if using same Detection Object
|
||||||
|
if DetectedItem.DesignateMenuName then
|
||||||
|
MenuText = string.format( "(%3s) %s", Designating, DetectedItem.DesignateMenuName )
|
||||||
|
else
|
||||||
|
MenuText = string.format( "(%3s) %s", Designating, MenuText )
|
||||||
|
end
|
||||||
|
|
||||||
local DetectedMenu = MENU_GROUP_DELAYED:New( AttackGroup, MenuText, MenuDesignate ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
local DetectedMenu = MENU_GROUP_DELAYED:New( AttackGroup, MenuText, MenuDesignate ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
|
||||||
-- Build the Lasing menu.
|
-- Build the Lasing menu.
|
||||||
|
|||||||
@ -23,21 +23,21 @@
|
|||||||
-- Date: Jan 2021
|
-- Date: Jan 2021
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **MANTIS** class, extends @{#Core.Base#BASE}
|
--- **MANTIS** class, extends #Core.Base#BASE
|
||||||
-- @type MANTIS #MANTIS
|
-- @type MANTIS
|
||||||
-- @field #string Classname
|
-- @field #string Classname
|
||||||
-- @field #string name Name of this Mantis
|
-- @field #string name Name of this Mantis
|
||||||
-- @field #string SAM_Templates_Prefix Prefix to build the #GROUP_SET for SAM sites
|
-- @field #string SAM_Templates_Prefix Prefix to build the #SET_GROUP for SAM sites
|
||||||
-- @field @{#Core.Set#GROUP_SET} SAM_Group The SAM #GROUP_SET
|
-- @field Core.Set#SET_GROUP SAM_Group The SAM #SET_GROUP
|
||||||
-- @field #string EWR_Templates_Prefix Prefix to build the #GROUP_SET for EWR group
|
-- @field #string EWR_Templates_Prefix Prefix to build the #SET_GROUP for EWR group
|
||||||
-- @field @{#Core.Set#GROUP_SET} EWR_Group The EWR #GROUP_SET
|
-- @field Core.Set#SET_GROUP EWR_Group The EWR #SET_GROUP
|
||||||
-- @field @{#Core.Set#GROUP_SET} Adv_EWR_Group The EWR #GROUP_SET used for advanced mode
|
-- @field #Core.Set#SET_GROUP Adv_EWR_Group The EWR #SET_GROUP used for advanced mode
|
||||||
-- @field #string HQ_Template_CC The ME name of the HQ object
|
-- @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 Wrapper.Group#GROUP HQ_CC The #GROUP object of the HQ
|
||||||
-- @field #table SAM_Table Table of SAM sites
|
-- @field #table SAM_Table Table of SAM sites
|
||||||
-- @field #string lid Prefix for logging
|
-- @field #string lid Prefix for logging
|
||||||
-- @field @{#Functional.Detection#DETECTION_AREAS} Detection The #DETECTION_AREAS object for EWR
|
-- @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 Functional.Detection#DETECTION_AREAS AWACS_Detection The #DETECTION_AREAS object for AWACS
|
||||||
-- @field #boolean debug Switch on extra messages
|
-- @field #boolean debug Switch on extra messages
|
||||||
-- @field #boolean verbose Switch on extra logging
|
-- @field #boolean verbose Switch on extra logging
|
||||||
-- @field #number checkradius Radius of the SAM sites
|
-- @field #number checkradius Radius of the SAM sites
|
||||||
@ -51,7 +51,10 @@
|
|||||||
-- @field #number adv_state Advanced mode state tracker
|
-- @field #number adv_state Advanced mode state tracker
|
||||||
-- @field #boolean advAwacs Boolean switch to use Awacs as a separate detection stream
|
-- @field #boolean advAwacs Boolean switch to use Awacs as a separate detection stream
|
||||||
-- @field #number awacsrange Detection range of an optional Awacs unit
|
-- @field #number awacsrange Detection range of an optional Awacs unit
|
||||||
-- @extends @{#Core.Base#BASE}
|
-- @field Functional.Shorad#SHORAD Shorad SHORAD Object, if available
|
||||||
|
-- @field #boolean ShoradLink If true, #MANTIS has #SHORAD enabled
|
||||||
|
-- @field #number ShoradTime Timer in seconds, how long #SHORAD will be active after a detection inside of the defense range
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
--- *The worst thing that can happen to a good cause is, not to be skillfully attacked, but to be ineptly defended.* - Frédéric Bastiat
|
--- *The worst thing that can happen to a good cause is, not to be skillfully attacked, but to be ineptly defended.* - Frédéric Bastiat
|
||||||
@ -163,7 +166,10 @@ MANTIS = {
|
|||||||
AWACS_Prefix = "",
|
AWACS_Prefix = "",
|
||||||
advAwacs = false,
|
advAwacs = false,
|
||||||
verbose = false,
|
verbose = false,
|
||||||
awacsrange = 250000
|
awacsrange = 250000,
|
||||||
|
Shorad = nil,
|
||||||
|
ShoradLink = false,
|
||||||
|
ShoradTime = 600,
|
||||||
}
|
}
|
||||||
|
|
||||||
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
||||||
@ -230,6 +236,9 @@ do
|
|||||||
self.Adv_EWR_Group = nil
|
self.Adv_EWR_Group = nil
|
||||||
self.AWACS_Prefix = awacs or nil
|
self.AWACS_Prefix = awacs or nil
|
||||||
self.awacsrange = 250000 --TODO: 250km, User Function to change
|
self.awacsrange = 250000 --TODO: 250km, User Function to change
|
||||||
|
self.Shorad = nil
|
||||||
|
self.ShoradLink = false
|
||||||
|
self.ShoradTime = 600
|
||||||
if type(awacs) == "string" then
|
if type(awacs) == "string" then
|
||||||
self.advAwacs = true
|
self.advAwacs = true
|
||||||
else
|
else
|
||||||
@ -373,7 +382,7 @@ do
|
|||||||
|
|
||||||
--- Function to set the HQ object for further use
|
--- Function to set the HQ object for further use
|
||||||
-- @param #MANTIS self
|
-- @param #MANTIS self
|
||||||
-- @param Wrapper.GROUP#GROUP The HQ #GROUP object to be set as HQ
|
-- @param Wrapper.GROUP#GROUP group The #GROUP object to be set as HQ
|
||||||
function MANTIS:SetCommandCenter(group)
|
function MANTIS:SetCommandCenter(group)
|
||||||
local group = group or nil
|
local group = group or nil
|
||||||
if group ~= nil then
|
if group ~= nil then
|
||||||
@ -709,6 +718,27 @@ do
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Function to link up #MANTIS with a #SHORAD installation
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param Functional.Shorad#SHORAD Shorad The #SHORAD object
|
||||||
|
-- @param #number Shoradtime Number of seconds #SHORAD stays active post wake-up
|
||||||
|
function MANTIS:AddShorad(Shorad,Shoradtime)
|
||||||
|
local Shorad = Shorad or nil
|
||||||
|
local ShoradTime = Shoradtime or 600
|
||||||
|
local ShoradLink = true
|
||||||
|
if Shorad:IsInstanceOf("SHORAD") then
|
||||||
|
self.ShoradLink = ShoradLink
|
||||||
|
self.Shorad = Shorad --#SHORAD
|
||||||
|
self.ShoradTime = Shoradtime -- #number
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to unlink #MANTIS from a #SHORAD installation
|
||||||
|
-- @param #MANTIS self
|
||||||
|
function MANTIS:RemoveShorad()
|
||||||
|
self.ShoradLink = false
|
||||||
|
end
|
||||||
|
|
||||||
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
||||||
-- MANTIS main functions
|
-- MANTIS main functions
|
||||||
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
||||||
@ -743,8 +773,15 @@ do
|
|||||||
if samgroup:IsAlive() then
|
if samgroup:IsAlive() then
|
||||||
-- switch off SAM
|
-- switch off SAM
|
||||||
samgroup:OptionAlarmStateRed()
|
samgroup:OptionAlarmStateRed()
|
||||||
--samgroup:OptionROEWeaponFree()
|
-- link in to SHORAD if available
|
||||||
--samgroup:SetAIOn()
|
-- TODO Test integration fully
|
||||||
|
if self.ShoradLink then
|
||||||
|
local Shorad = self.Shorad
|
||||||
|
local radius = self.checkradius
|
||||||
|
local ontime = self.ShoradTime
|
||||||
|
Shorad:WakeUpShorad(name, radius, ontime)
|
||||||
|
end
|
||||||
|
-- debug output
|
||||||
local text = string.format("SAM %s switched to alarm state RED!", name)
|
local text = string.format("SAM %s switched to alarm state RED!", name)
|
||||||
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
if self.verbose then env.info(self.lid..text) end
|
if self.verbose then env.info(self.lid..text) end
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
--
|
--
|
||||||
-- ### Authors: **FlightControl**, **applevangelist**
|
-- ### Authors: **FlightControl**, **applevangelist**
|
||||||
--
|
--
|
||||||
-- Last Update: Dec 2020
|
-- Last Update: Feb 2021
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@ -51,9 +51,44 @@ SEAD = {
|
|||||||
EngagementRange = 75 -- default 75% engagement range Feature Request #1355
|
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",
|
||||||
|
["AGM_84"] = "AGM_84",
|
||||||
|
["AGM_45"] = "AGM_45",
|
||||||
|
["ALARN"] = "ALARM",
|
||||||
|
["LD-10"] = "LD-10",
|
||||||
|
["X_58"] = "X_58",
|
||||||
|
["X_28"] = "X_28",
|
||||||
|
["X_25"] = "X_25",
|
||||||
|
["X_31"] = "X_31",
|
||||||
|
["Kh25"] = "Kh25",
|
||||||
|
}
|
||||||
|
|
||||||
--- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles.
|
--- 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...
|
-- 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.
|
-- Chances are big that the missile will miss.
|
||||||
|
-- @param #SEAD self
|
||||||
-- @param table{string,...}|string SEADGroupPrefixes which is a table of Prefixes of the SA Groups in the DCS mission editor on which evasive actions need to be taken.
|
-- @param table{string,...}|string SEADGroupPrefixes which is a table of Prefixes of the SA Groups in the DCS mission editor on which evasive actions need to be taken.
|
||||||
-- @return SEAD
|
-- @return SEAD
|
||||||
-- @usage
|
-- @usage
|
||||||
@ -74,7 +109,7 @@ function SEAD:New( SEADGroupPrefixes )
|
|||||||
end
|
end
|
||||||
|
|
||||||
self:HandleEvent( EVENTS.Shot )
|
self:HandleEvent( EVENTS.Shot )
|
||||||
self:I("*** SEAD - Started Version 0.2.2")
|
self:I("*** SEAD - Started Version 0.2.5")
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -112,7 +147,20 @@ function SEAD:SetEngagementRange(range)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME.
|
--- Check if a known HARM was fired
|
||||||
|
-- @param #SEAD self
|
||||||
|
-- @param #string WeaponName
|
||||||
|
-- @return #boolean Returns true for a match
|
||||||
|
function SEAD:_CheckHarms(WeaponName)
|
||||||
|
self:F( { WeaponName } )
|
||||||
|
local hit = false
|
||||||
|
for _,_name in pairs (SEAD.Harms) do
|
||||||
|
if string.find(WeaponName,_name,1) then hit = true end
|
||||||
|
end
|
||||||
|
return hit
|
||||||
|
end
|
||||||
|
|
||||||
|
--- 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.
|
||||||
-- @see SEAD
|
-- @see SEAD
|
||||||
-- @param #SEAD
|
-- @param #SEAD
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
@ -127,7 +175,7 @@ function SEAD:OnEventShot( EventData )
|
|||||||
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
||||||
self:T({ SEADWeapon })
|
self:T({ SEADWeapon })
|
||||||
|
|
||||||
--check for SEAD missiles
|
--[[check for SEAD missiles
|
||||||
if SEADWeaponName == "weapons.missiles.X_58" --Kh-58U anti-radiation missiles fired
|
if SEADWeaponName == "weapons.missiles.X_58" --Kh-58U anti-radiation missiles fired
|
||||||
or
|
or
|
||||||
SEADWeaponName == "weapons.missiles.Kh25MP_PRGS1VP" --Kh-25MP anti-radiation missiles fired
|
SEADWeaponName == "weapons.missiles.Kh25MP_PRGS1VP" --Kh-25MP anti-radiation missiles fired
|
||||||
@ -155,12 +203,13 @@ function SEAD:OnEventShot( EventData )
|
|||||||
SEADWeaponName == "weapons.missiles.AGM_84A" --AGM84 anti-radiation missiles fired
|
SEADWeaponName == "weapons.missiles.AGM_84A" --AGM84 anti-radiation missiles fired
|
||||||
or
|
or
|
||||||
SEADWeaponName == "weapons.missiles.AGM_84H" --AGM84 anti-radiation missiles fired
|
SEADWeaponName == "weapons.missiles.AGM_84H" --AGM84 anti-radiation missiles fired
|
||||||
then
|
--]]
|
||||||
|
if self:_CheckHarms(SEADWeaponName) then
|
||||||
|
|
||||||
local _evade = math.random (1,100) -- random number for chance of evading action
|
local _evade = math.random (1,100) -- random number for chance of evading action
|
||||||
local _targetMim = EventData.Weapon:getTarget() -- Identify target
|
local _targetMim = EventData.Weapon:getTarget() -- Identify target
|
||||||
local _targetMimname = Unit.getName(_targetMim) -- Unit name
|
local _targetMimname = Unit.getName(_targetMim) -- Unit name
|
||||||
local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) --targeted grouo
|
local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) --targeted group
|
||||||
local _targetMimgroupName = _targetMimgroup:getName() -- group name
|
local _targetMimgroupName = _targetMimgroup:getName() -- group name
|
||||||
local _targetskill = _DATABASE.Templates.Units[_targetMimname].Template.skill
|
local _targetskill = _DATABASE.Templates.Units[_targetMimname].Template.skill
|
||||||
self:T( self.SEADGroupPrefixes )
|
self:T( self.SEADGroupPrefixes )
|
||||||
|
|||||||
460
Moose Development/Moose/Functional/Shorad.lua
Normal file
460
Moose Development/Moose/Functional/Shorad.lua
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
--- **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 **
|
||||||
|
--
|
||||||
|
-- @module Functional.Shorad
|
||||||
|
-- @image Functional.Shorad.jpg
|
||||||
|
--
|
||||||
|
-- Date: Feb 2021
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
--- **SHORAD** class, extends Core.Base#BASE
|
||||||
|
-- @type SHORAD
|
||||||
|
-- @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 #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
|
||||||
|
-- @field #string Coalition The coalition of this Shorad
|
||||||
|
-- @field #number ActiveTimer How long a Shorad stays active after wake-up in seconds
|
||||||
|
-- @field #table ActiveGroups Table for the timer function
|
||||||
|
-- @field #string lid The log ID for the dcs.log
|
||||||
|
-- @field #boolean DefendHarms Default true, intercept incoming HARMS
|
||||||
|
-- @field #boolean DefendMavs Default true, intercept incoming AG-Missiles
|
||||||
|
-- @field #number DefenseLowProb Default 70, minimum detection limit
|
||||||
|
-- @field #number DefenseHighProb Default 90, maximim detection limit
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
--- *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.
|
||||||
|
-- Easily integrated with @{Functional.Mantis#MANTIS} to complete the defensive system setup.
|
||||||
|
--
|
||||||
|
-- ## Usage
|
||||||
|
--
|
||||||
|
-- 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.
|
||||||
|
--
|
||||||
|
-- ### 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")`
|
||||||
|
--
|
||||||
|
-- ## Customize options
|
||||||
|
--
|
||||||
|
-- * SHORAD:SwitchDebug(debug)
|
||||||
|
-- * SHORAD:SwitchHARMDefense(onoff)
|
||||||
|
-- * SHORAD:SwitchAGMDefense(onoff)
|
||||||
|
-- * SHORAD:SetDefenseLimits(low,high)
|
||||||
|
-- * SHORAD:SetActiveTimer(seconds)
|
||||||
|
-- * SHORAD:SetDefenseRadius(meters)
|
||||||
|
--
|
||||||
|
-- @field #SHORAD
|
||||||
|
SHORAD = {
|
||||||
|
ClassName = "SHORAD",
|
||||||
|
name = "MyShorad",
|
||||||
|
debug = false,
|
||||||
|
Prefixes = "",
|
||||||
|
Radius = 20000,
|
||||||
|
Groupset = nil,
|
||||||
|
Samset = nil,
|
||||||
|
Coalition = nil,
|
||||||
|
ActiveTimer = 600, --stay on 10 mins
|
||||||
|
ActiveGroups = {},
|
||||||
|
lid = "",
|
||||||
|
DefendHarms = true,
|
||||||
|
DefendMavs = true,
|
||||||
|
DefenseLowProb = 70,
|
||||||
|
DefenseHighProb = 90,
|
||||||
|
}
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
-- SHORAD System
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
do
|
||||||
|
-- TODO Complete list?
|
||||||
|
--- 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",
|
||||||
|
["AGM_84"] = "AGM_84",
|
||||||
|
["AGM_45"] = "AGM_45",
|
||||||
|
["ALARN"] = "ALARM",
|
||||||
|
["LD-10"] = "LD-10",
|
||||||
|
["X_58"] = "X_58",
|
||||||
|
["X_28"] = "X_28",
|
||||||
|
["X_25"] = "X_25",
|
||||||
|
["X_31"] = "X_31",
|
||||||
|
["Kh25"] = "Kh25",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- TODO complete list?
|
||||||
|
-- @field Mavs
|
||||||
|
SHORAD.Mavs = {
|
||||||
|
["AGM"] = "AGM",
|
||||||
|
["C-701"] = "C-701",
|
||||||
|
["Kh25"] = "Kh25",
|
||||||
|
["Kh29"] = "Kh29",
|
||||||
|
["Kh31"] = "Kh31",
|
||||||
|
["Kh66"] = "Kh66",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Instantiates a new SHORAD object
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #string Name Name of this SHORAD
|
||||||
|
-- @param #string ShoradPrefix Filter for the Shorad #SET_GROUP
|
||||||
|
-- @param Core.Set#SET_GROUP Samset The #SET_GROUP of SAM sites to defend
|
||||||
|
-- @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)
|
||||||
|
local self = BASE:Inherit( self, BASE:New() )
|
||||||
|
self:F({Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition})
|
||||||
|
|
||||||
|
local GroupSet = SET_GROUP:New():FilterPrefixes(ShoradPrefix):FilterCoalitions(Coalition):FilterCategoryGround():FilterStart()
|
||||||
|
|
||||||
|
self.name = Name or "MyShorad"
|
||||||
|
self.Prefixes = ShoradPrefix or "SAM SHORAD"
|
||||||
|
self.Radius = Radius or 20000
|
||||||
|
self.Coalition = Coalition or "blue"
|
||||||
|
self.Samset = Samset or GroupSet
|
||||||
|
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:I("*** SHORAD - Started Version 0.0.2")
|
||||||
|
-- Set the string id for output to DCS.log file.
|
||||||
|
self.lid=string.format("SHORAD %s | ", self.name)
|
||||||
|
self:_InitState()
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initially set all groups to alarm state GREEN
|
||||||
|
-- @param #SHORAD self
|
||||||
|
function SHORAD:_InitState()
|
||||||
|
local table = {}
|
||||||
|
local set = self.Groupset
|
||||||
|
self:T({set = set})
|
||||||
|
local aliveset = set:GetAliveSet() --#table
|
||||||
|
for _,_group in pairs (aliveset) do
|
||||||
|
_group:OptionAlarmStateGreen() --Wrapper.Group#GROUP
|
||||||
|
end
|
||||||
|
-- gather entropy
|
||||||
|
for i=1,10 do
|
||||||
|
math.random()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Switch debug state
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #boolean debug Switch debug on (true) or off (false)
|
||||||
|
function SHORAD:SwitchDebug(debug)
|
||||||
|
self:F( { debug } )
|
||||||
|
local onoff = debug or false
|
||||||
|
if debug then
|
||||||
|
self.debug = true
|
||||||
|
--tracing
|
||||||
|
BASE:TraceOn()
|
||||||
|
BASE:TraceClass("SHORAD")
|
||||||
|
else
|
||||||
|
self.debug = false
|
||||||
|
BASE:TraceOff()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Switch defense for HARMs
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #boolean onoff
|
||||||
|
function SHORAD:SwitchHARMDefense(onoff)
|
||||||
|
self:F( { onoff } )
|
||||||
|
local onoff = onoff or true
|
||||||
|
self.DefendHarms = onoff
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Switch defense for AGMs
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #boolean onoff
|
||||||
|
function SHORAD:SwitchAGMDefense(onoff)
|
||||||
|
self:F( { onoff } )
|
||||||
|
local onoff = onoff or true
|
||||||
|
self.DefendMavs = onoff
|
||||||
|
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:F( { low, high } )
|
||||||
|
local low = low or 70
|
||||||
|
local high = high or 90
|
||||||
|
if (low < 0) or (low > 100) or (low > high) then
|
||||||
|
low = 70
|
||||||
|
end
|
||||||
|
if (high < 0) or (high > 100) or (high < low ) then
|
||||||
|
high = 90
|
||||||
|
end
|
||||||
|
self.DefenseLowProb = low
|
||||||
|
self.DefenseHighProb = high
|
||||||
|
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)
|
||||||
|
local timer = seconds or 600
|
||||||
|
if timer < 0 then
|
||||||
|
timer = 600
|
||||||
|
end
|
||||||
|
self.ActiveTimer = timer
|
||||||
|
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
|
||||||
|
function SHORAD:SetDefenseRadius(meters)
|
||||||
|
local radius = meters or 20000
|
||||||
|
if radius < 0 then
|
||||||
|
radius = 20000
|
||||||
|
end
|
||||||
|
self.Radius = radius
|
||||||
|
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:F( { WeaponName } )
|
||||||
|
local hit = false
|
||||||
|
if self.DefendHarms then
|
||||||
|
for _,_name in pairs (SHORAD.Harms) do
|
||||||
|
if string.find(WeaponName,_name,1) then hit = true end
|
||||||
|
end
|
||||||
|
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:F( { WeaponName } )
|
||||||
|
local hit = false
|
||||||
|
if self.DefendMavs then
|
||||||
|
for _,_name in pairs (SHORAD.Mavs) do
|
||||||
|
if string.find(WeaponName,_name,1) then hit = true end
|
||||||
|
end
|
||||||
|
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)
|
||||||
|
local owncoalition = self.Coalition
|
||||||
|
local othercoalition = ""
|
||||||
|
if Coalition == 0 then
|
||||||
|
othercoalition = "neutral"
|
||||||
|
elseif Coalition == 1 then
|
||||||
|
othercoalition = "red"
|
||||||
|
else
|
||||||
|
othercoalition = "blue"
|
||||||
|
end
|
||||||
|
self:T({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)
|
||||||
|
local tgtgrp = TargetGroupName
|
||||||
|
local shorad = self.Groupset
|
||||||
|
local shoradset = shorad:GetAliveSet() --#table
|
||||||
|
local returnname = false
|
||||||
|
for _,_groups in pairs (shoradset) do
|
||||||
|
local groupname = _groups:GetName()
|
||||||
|
if string.find(groupname, tgtgrp, 1) then
|
||||||
|
returnname = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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)
|
||||||
|
local tgtgrp = TargetGroupName
|
||||||
|
local shorad = self.Samset
|
||||||
|
local shoradset = shorad:GetAliveSet() --#table
|
||||||
|
local returnname = false
|
||||||
|
for _,_groups in pairs (shoradset) do
|
||||||
|
local groupname = _groups:GetName()
|
||||||
|
if string.find(groupname, tgtgrp, 1) then
|
||||||
|
returnname = true
|
||||||
|
end
|
||||||
|
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()
|
||||||
|
local IsDetected = false
|
||||||
|
local DetectionProb = math.random(self.DefenseLowProb, self.DefenseHighProb) -- reference value
|
||||||
|
local ActualDetection = math.random(1,100) -- value for this shot
|
||||||
|
if ActualDetection <= DetectionProb then
|
||||||
|
IsDetected = true
|
||||||
|
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
|
||||||
|
-- @usage Use this function to integrate with other systems.
|
||||||
|
function SHORAD:WakeUpShorad(TargetGroup, Radius, ActiveTimer)
|
||||||
|
self:F({TargetGroup, Radius, ActiveTimer})
|
||||||
|
local targetgroup = GROUP:FindByName(TargetGroup)
|
||||||
|
local targetzone = ZONE_GROUP:New("Shorad",targetgroup,Radius) -- create a defense zone to check
|
||||||
|
local groupset = self.Groupset --Core.Set#SET_GROUP
|
||||||
|
local shoradset = groupset:GetAliveSet() --#table
|
||||||
|
-- local function to switch off shorad again
|
||||||
|
local function SleepShorad(group)
|
||||||
|
local groupname = group:GetName()
|
||||||
|
self.ActiveGroups[groupname] = nil
|
||||||
|
group:OptionAlarmStateGreen()
|
||||||
|
local text = string.format("Sleeping SHORAD %s", group:GetName())
|
||||||
|
self:T(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)
|
||||||
|
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||||
|
_group:OptionAlarmStateRed()
|
||||||
|
local groupname = _group:GetName()
|
||||||
|
if self.ActiveGroups[groupname] == nil then -- no timer yet for this group
|
||||||
|
self.ActiveGroups[groupname] = { Timing = ActiveTimer }
|
||||||
|
local endtime = timer.getTime() + (ActiveTimer * math.random(75,100) / 100 ) -- randomize wakeup a bit
|
||||||
|
timer.scheduleFunction(SleepShorad, _group, endtime)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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:F( { EventData } )
|
||||||
|
|
||||||
|
--local ShootingUnit = EventData.IniDCSUnit
|
||||||
|
--local ShootingUnitName = EventData.IniDCSUnitName
|
||||||
|
local ShootingWeapon = EventData.Weapon -- Identify the weapon fired
|
||||||
|
local ShootingWeaponName = EventData.WeaponName -- return weapon type
|
||||||
|
-- get firing coalition
|
||||||
|
local weaponcoalition = EventData.IniGroup:GetCoalition()
|
||||||
|
-- get detection probability
|
||||||
|
if self:_CheckCoalition(weaponcoalition) then --avoid overhead on friendly fire
|
||||||
|
local IsDetected = self:_ShotIsDetected()
|
||||||
|
-- convert to text
|
||||||
|
local DetectedText = "false"
|
||||||
|
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 )
|
||||||
|
local m = MESSAGE:New(text,15,"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 targetunitname = Unit.getName(targetdata) -- Unit name
|
||||||
|
local targetgroup = Unit.getGroup(Weapon.getTarget(ShootingWeapon)) --targeted group
|
||||||
|
local targetgroupname = targetgroup:getName() -- group name
|
||||||
|
-- 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:WakeUpShorad(targetgroupname, self.Radius, self.ActiveTimer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--
|
||||||
|
end
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
-- SHORAD end
|
||||||
|
-----------------------------------------------------------------------
|
||||||
@ -69,6 +69,7 @@ __Moose.Include( 'Scripts/Moose/Functional/PseudoATC.lua' )
|
|||||||
__Moose.Include( 'Scripts/Moose/Functional/Warehouse.lua' )
|
__Moose.Include( 'Scripts/Moose/Functional/Warehouse.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Functional/Fox.lua' )
|
__Moose.Include( 'Scripts/Moose/Functional/Fox.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Functional/Mantis.lua' )
|
__Moose.Include( 'Scripts/Moose/Functional/Mantis.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Functional/Shorad.lua' )
|
||||||
|
|
||||||
__Moose.Include( 'Scripts/Moose/Ops/Airboss.lua' )
|
__Moose.Include( 'Scripts/Moose/Ops/Airboss.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Ops/RecoveryTanker.lua' )
|
__Moose.Include( 'Scripts/Moose/Ops/RecoveryTanker.lua' )
|
||||||
|
|||||||
@ -753,6 +753,7 @@ do -- TASK_A2G_DISPATCHER
|
|||||||
local TargetSetUnit = self:EvaluateSEAD( DetectedItem ) -- Returns a SetUnit if there are targets to be SEADed...
|
local TargetSetUnit = self:EvaluateSEAD( DetectedItem ) -- Returns a SetUnit if there are targets to be SEADed...
|
||||||
if TargetSetUnit then
|
if TargetSetUnit then
|
||||||
Task = TASK_A2G_SEAD:New( Mission, self.SetGroup, string.format( "SEAD.%03d", DetectedItemID ), TargetSetUnit )
|
Task = TASK_A2G_SEAD:New( Mission, self.SetGroup, string.format( "SEAD.%03d", DetectedItemID ), TargetSetUnit )
|
||||||
|
DetectedItem.DesignateMenuName = string.format( "SEAD.%03d", DetectedItemID ) --inject a name for DESIGNATE, if using same DETECTION object
|
||||||
Task:SetDetection( Detection, DetectedItem )
|
Task:SetDetection( Detection, DetectedItem )
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -761,6 +762,7 @@ do -- TASK_A2G_DISPATCHER
|
|||||||
local TargetSetUnit = self:EvaluateCAS( DetectedItem ) -- Returns a SetUnit if there are targets to be CASed...
|
local TargetSetUnit = self:EvaluateCAS( DetectedItem ) -- Returns a SetUnit if there are targets to be CASed...
|
||||||
if TargetSetUnit then
|
if TargetSetUnit then
|
||||||
Task = TASK_A2G_CAS:New( Mission, self.SetGroup, string.format( "CAS.%03d", DetectedItemID ), TargetSetUnit )
|
Task = TASK_A2G_CAS:New( Mission, self.SetGroup, string.format( "CAS.%03d", DetectedItemID ), TargetSetUnit )
|
||||||
|
DetectedItem.DesignateMenuName = string.format( "CAS.%03d", DetectedItemID ) --inject a name for DESIGNATE, if using same DETECTION object
|
||||||
Task:SetDetection( Detection, DetectedItem )
|
Task:SetDetection( Detection, DetectedItem )
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -769,6 +771,7 @@ do -- TASK_A2G_DISPATCHER
|
|||||||
local TargetSetUnit = self:EvaluateBAI( DetectedItem, self.Mission:GetCommandCenter():GetPositionable():GetCoalition() ) -- Returns a SetUnit if there are targets to be BAIed...
|
local TargetSetUnit = self:EvaluateBAI( DetectedItem, self.Mission:GetCommandCenter():GetPositionable():GetCoalition() ) -- Returns a SetUnit if there are targets to be BAIed...
|
||||||
if TargetSetUnit then
|
if TargetSetUnit then
|
||||||
Task = TASK_A2G_BAI:New( Mission, self.SetGroup, string.format( "BAI.%03d", DetectedItemID ), TargetSetUnit )
|
Task = TASK_A2G_BAI:New( Mission, self.SetGroup, string.format( "BAI.%03d", DetectedItemID ), TargetSetUnit )
|
||||||
|
DetectedItem.DesignateMenuName = string.format( "BAI.%03d", DetectedItemID ) --inject a name for DESIGNATE, if using same DETECTION object
|
||||||
Task:SetDetection( Detection, DetectedItem )
|
Task:SetDetection( Detection, DetectedItem )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -311,3 +311,52 @@ ENUMS.Morse.N8="- - - * *"
|
|||||||
ENUMS.Morse.N9="- - - - *"
|
ENUMS.Morse.N9="- - - - *"
|
||||||
ENUMS.Morse.N0="- - - - -"
|
ENUMS.Morse.N0="- - - - -"
|
||||||
ENUMS.Morse[" "]=" "
|
ENUMS.Morse[" "]=" "
|
||||||
|
|
||||||
|
--- ISO (639-1) 2-letter Language Codes. See the [Wikipedia](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).
|
||||||
|
--
|
||||||
|
-- @type ENUMS.ISOLang
|
||||||
|
ENUMS.ISOLang =
|
||||||
|
{
|
||||||
|
Arabic = 'AR',
|
||||||
|
Chinese = 'ZH',
|
||||||
|
English = 'EN',
|
||||||
|
French = 'FR',
|
||||||
|
German = 'DE',
|
||||||
|
Russian = 'RU',
|
||||||
|
Spanish = 'ES',
|
||||||
|
Japanese = 'JA',
|
||||||
|
Italian = 'IT',
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Phonetic Alphabet (NATO). See the [Wikipedia](https://en.wikipedia.org/wiki/NATO_phonetic_alphabet).
|
||||||
|
--
|
||||||
|
-- @type ENUMS.Phonetic
|
||||||
|
ENUMS.Phonetic =
|
||||||
|
{
|
||||||
|
A = 'Alpha',
|
||||||
|
B = 'Bravo',
|
||||||
|
C = 'Charlie',
|
||||||
|
D = 'Delta',
|
||||||
|
E = 'Echo',
|
||||||
|
F = 'Foxtrot',
|
||||||
|
G = 'Golf',
|
||||||
|
H = 'Hotel',
|
||||||
|
I = 'India',
|
||||||
|
J = 'Juliett',
|
||||||
|
K = 'Kilo',
|
||||||
|
L = 'Lima',
|
||||||
|
M = 'Mike',
|
||||||
|
N = 'November',
|
||||||
|
O = 'Oscar',
|
||||||
|
P = 'Papa',
|
||||||
|
Q = 'Quebec',
|
||||||
|
R = 'Romeo',
|
||||||
|
S = 'Sierra',
|
||||||
|
T = 'Tango',
|
||||||
|
U = 'Uniform',
|
||||||
|
V = 'Victor',
|
||||||
|
W = 'Whiskey',
|
||||||
|
X = 'Xray',
|
||||||
|
Y = 'Yankee',
|
||||||
|
Z = 'Zulu',
|
||||||
|
}
|
||||||
@ -97,7 +97,7 @@ CALLSIGN={
|
|||||||
JTAC={
|
JTAC={
|
||||||
Axeman=1,
|
Axeman=1,
|
||||||
Darknight=2,
|
Darknight=2,
|
||||||
Warrier=3,
|
Warrior=3,
|
||||||
Pointer=4,
|
Pointer=4,
|
||||||
Eyeball=5,
|
Eyeball=5,
|
||||||
Moonbeam=6,
|
Moonbeam=6,
|
||||||
|
|||||||
@ -68,6 +68,8 @@ Functional/Suppression.lua
|
|||||||
Functional/PseudoATC.lua
|
Functional/PseudoATC.lua
|
||||||
Functional/Warehouse.lua
|
Functional/Warehouse.lua
|
||||||
Functional/Fox.lua
|
Functional/Fox.lua
|
||||||
|
Functional/Mantis.lua
|
||||||
|
Functional/Shorad.lua
|
||||||
|
|
||||||
Ops/Airboss.lua
|
Ops/Airboss.lua
|
||||||
Ops/RecoveryTanker.lua
|
Ops/RecoveryTanker.lua
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user