Merge branch 'develop' into FF/Ops

This commit is contained in:
Frank 2021-03-03 00:03:52 +01:00
commit bab097958f
7 changed files with 434 additions and 154 deletions

View File

@ -33,7 +33,7 @@
-- --
-- ## Infantry health. -- ## Infantry health.
-- --
-- When infantry is unboarded from the APCs, the infantry is actually respawned into the battlefield. -- When infantry is unboarded from the helicopters, the infantry is actually respawned into the battlefield.
-- As a result, the unboarding infantry is very _healthy_ every time it unboards. -- As a result, the unboarding infantry is very _healthy_ every time it unboards.
-- This is due to the limitation of the DCS simulator, which is not able to specify the health of new spawned units as a parameter. -- This is due to the limitation of the DCS simulator, which is not able to specify the health of new spawned units as a parameter.
-- However, infantry that was destroyed when unboarded, won't be respawned again. Destroyed is destroyed. -- However, infantry that was destroyed when unboarded, won't be respawned again. Destroyed is destroyed.
@ -67,18 +67,6 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
self:AddTransition( "Unloaded", "Pickup", "*" ) self:AddTransition( "Unloaded", "Pickup", "*" )
self:AddTransition( "Loaded", "Deploy", "*" ) self:AddTransition( "Loaded", "Deploy", "*" )
--[[
self:AddTransition( { "Unloaded", "Loading" }, "Load", "Boarding" )
self:AddTransition( "Boarding", "Board", "Boarding" )
self:AddTransition( "Boarding", "Loaded", "Loaded" )
self:AddTransition( "Boarding", "PickedUp", "Loaded" )
self:AddTransition( "Boarding", "Deploy", "Loaded" )
self:AddTransition( "Loaded", "Unload", "Unboarding" )
self:AddTransition( "Unboarding", "Unboard", "Unboarding" )
self:AddTransition( "Unboarding", "Unloaded", "Unboarding" )
self:AddTransition( "Unboarding", "Deployed", "Unloaded" )
self:AddTransition( "Unboarding", "Pickup", "Unloaded" )
--]]
self:AddTransition( "*", "Loaded", "Loaded" ) self:AddTransition( "*", "Loaded", "Loaded" )
self:AddTransition( "Unboarding", "Pickup", "Unloaded" ) self:AddTransition( "Unboarding", "Pickup", "Unloaded" )
self:AddTransition( "Unloaded", "Unboard", "Unloaded" ) self:AddTransition( "Unloaded", "Unboard", "Unloaded" )
@ -107,13 +95,31 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
-- @param #string Event -- @param #string Event
-- @param #string To -- @param #string To
-- @param Core.Point#COORDINATE Coordinate -- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. -- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- PickedUp Handler OnAfter for AI_CARGO_HELICOPTER - Cargo set has been picked up, ready to deploy
-- @function [parent=#AI_CARGO_HELICOPTER] OnAfterPickedUp
-- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter The helicopter #GROUP object
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Unit#UNIT Unit The helicopter #UNIT object
--- Unloaded Handler OnAfter for AI_CARGO_HELICOPTER - Cargo unloaded, carrier is empty
-- @function [parent=#AI_CARGO_HELICOPTER] OnAfterUnloaded
-- @param #AI_CARGO_HELICOPTER self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Cargo.CargoGroup#CARGO_GROUP Cargo The #CARGO_GROUP object.
-- @param Wrapper.Unit#UNIT Unit The helicopter #UNIT object
--- Pickup Trigger for AI_CARGO_HELICOPTER --- Pickup Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] Pickup -- @function [parent=#AI_CARGO_HELICOPTER] Pickup
-- @param #AI_CARGO_HELICOPTER self -- @param #AI_CARGO_HELICOPTER self
-- @param Core.Point#COORDINATE Coordinate -- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. -- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- Pickup Asynchronous Trigger for AI_CARGO_HELICOPTER --- Pickup Asynchronous Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] __Pickup -- @function [parent=#AI_CARGO_HELICOPTER] __Pickup
@ -129,7 +135,7 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
-- @param #string Event -- @param #string Event
-- @param #string To -- @param #string To
-- @param Core.Point#COORDINATE Coordinate Place at which cargo is deployed. -- @param Core.Point#COORDINATE Coordinate Place at which cargo is deployed.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. -- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- @return #boolean -- @return #boolean
--- Deploy Handler OnAfter for AI_CARGO_HELICOPTER --- Deploy Handler OnAfter for AI_CARGO_HELICOPTER
@ -139,21 +145,42 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
-- @param #string Event -- @param #string Event
-- @param #string To -- @param #string To
-- @param Core.Point#COORDINATE Coordinate -- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. -- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- Deployed Handler OnAfter for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] OnAfterDeployed
-- @param #AI_CARGO_HELICOPTER self
-- @param #string From
-- @param #string Event
-- @param #string To
--- Deploy Trigger for AI_CARGO_HELICOPTER --- Deploy Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] Deploy -- @function [parent=#AI_CARGO_HELICOPTER] Deploy
-- @param #AI_CARGO_HELICOPTER self -- @param #AI_CARGO_HELICOPTER self
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed. -- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. -- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- Deploy Asynchronous Trigger for AI_CARGO_HELICOPTER --- Deploy Asynchronous Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] __Deploy -- @function [parent=#AI_CARGO_HELICOPTER] __Deploy
-- @param #number Delay Delay in seconds. -- @param #number Delay Delay in seconds.
-- @param #AI_CARGO_HELICOPTER self -- @param #AI_CARGO_HELICOPTER self
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed. -- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. -- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- Home Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] Home
-- @param #AI_CARGO_HELICOPTER self
-- @param Core.Point#COORDINATE Coordinate Place to which the helicopter will go.
-- @param #number Speed (optional) Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- @param #number Height (optional) Height the Helicopter should be flying at.
--- Home Asynchronous Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] __Home
-- @param #number Delay Delay in seconds.
-- @param #AI_CARGO_HELICOPTER self
-- @param Core.Point#COORDINATE Coordinate Place to which the helicopter will go.
-- @param #number Speed (optional) Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- @param #number Height (optional) Height the Helicopter should be flying at.
-- We need to capture the Crash events for the helicopters. -- We need to capture the Crash events for the helicopters.
-- The helicopter reference is used in the semaphore AI_CARGO_QUEUE. -- The helicopter reference is used in the semaphore AI_CARGO_QUEUE.
@ -235,7 +262,7 @@ end
-- @param Event -- @param Event
-- @param To -- @param To
function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To ) function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To )
self:F({From, Event, To})
Helicopter:F( { Name = Helicopter:GetName() } ) Helicopter:F( { Name = Helicopter:GetName() } )
if Helicopter and Helicopter:IsAlive() then if Helicopter and Helicopter:IsAlive() then
@ -276,7 +303,7 @@ end
-- @param Core.Point#COORDINATE Coordinate -- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed -- @param #number Speed
function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordinate, Speed, DeployZone ) function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordinate, Speed, DeployZone )
self:F({From, Event, To, Coordinate, Speed, DeployZone})
local HelicopterInZone = false local HelicopterInZone = false
if Helicopter and Helicopter:IsAlive() == true then if Helicopter and Helicopter:IsAlive() == true then
@ -359,6 +386,7 @@ end
-- @param Core.Point#COORDINATE Coordinate -- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed -- @param #number Speed
function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordinate ) function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordinate )
self:F({From, Event, To, Coordinate})
if Helicopter and Helicopter:IsAlive() then if Helicopter and Helicopter:IsAlive() then
@ -394,7 +422,7 @@ end
-- @param #boolean Deployed Cargo is deployed. -- @param #boolean Deployed Cargo is deployed.
-- @return #boolean True if all cargo has been unloaded. -- @return #boolean True if all cargo has been unloaded.
function AI_CARGO_HELICOPTER:onafterDeployed( Helicopter, From, Event, To, DeployZone ) function AI_CARGO_HELICOPTER:onafterDeployed( Helicopter, From, Event, To, DeployZone )
self:F( { Helicopter, From, Event, To, DeployZone = DeployZone } ) self:F( { From, Event, To, DeployZone = DeployZone } )
self:Orbit( Helicopter:GetCoordinate(), 50 ) self:Orbit( Helicopter:GetCoordinate(), 50 )
@ -416,7 +444,7 @@ end
-- @param Event -- @param Event
-- @param To -- @param To
-- @param Core.Point#COORDINATE Coordinate Pickup place. -- @param Core.Point#COORDINATE Coordinate Pickup place.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. -- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- @param #number Height Height in meters to move to the pickup coordinate. This parameter is ignored for APCs. -- @param #number Height Height in meters to move to the pickup coordinate. This parameter is ignored for APCs.
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided. -- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordinate, Speed, Height, PickupZone ) function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordinate, Speed, Height, PickupZone )
@ -485,10 +513,10 @@ end
-- @param Event -- @param Event
-- @param To -- @param To
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed. -- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. -- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- @param #number Height Height in meters to move to the deploy coordinate. -- @param #number Height Height in meters to move to the deploy coordinate.
function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordinate, Speed, Height, DeployZone ) function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordinate, Speed, Height, DeployZone )
self:F({From, Event, To, Coordinate, Speed, Height, DeployZone})
if Helicopter and Helicopter:IsAlive() ~= nil then if Helicopter and Helicopter:IsAlive() ~= nil then
self.RouteDeploy = true self.RouteDeploy = true
@ -550,10 +578,11 @@ end
-- @param Event -- @param Event
-- @param To -- @param To
-- @param Core.Point#COORDINATE Coordinate Home place. -- @param Core.Point#COORDINATE Coordinate Home place.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. -- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- @param #number Height Height in meters to move to the home coordinate. -- @param #number Height Height in meters to move to the home coordinate.
-- @param Core.Zone#ZONE HomeZone The zone wherein the carrier will return when all cargo has been transported. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE. -- @param Core.Zone#ZONE HomeZone The zone wherein the carrier will return when all cargo has been transported. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinate, Speed, Height, HomeZone ) function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinate, Speed, Height, HomeZone )
self:F({From, Event, To, Coordinate, Speed, Height})
if Helicopter and Helicopter:IsAlive() ~= nil then if Helicopter and Helicopter:IsAlive() ~= nil then
@ -563,7 +592,8 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat
--- Calculate the target route point. --- Calculate the target route point.
Coordinate.y = Height --Coordinate.y = Height
Height = Height or 50
Speed = Speed or Helicopter:GetSpeedMax()*0.5 Speed = Speed or Helicopter:GetSpeedMax()*0.5
@ -576,7 +606,7 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat
--- Create a route point of type air. --- Create a route point of type air.
local CoordinateTo = Coordinate local CoordinateTo = Coordinate
local landheight = CoordinateTo:GetLandHeight() -- get target height local landheight = CoordinateTo:GetLandHeight() -- get target height
CoordinateTo.y = landheight + 50 -- flight height should be 50m above ground CoordinateTo.y = landheight + Height -- flight height should be 50m above ground
local WaypointTo = CoordinateTo:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, Speed, true) local WaypointTo = CoordinateTo:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, Speed, true)
@ -594,7 +624,6 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat
-- Now route the helicopter -- Now route the helicopter
Helicopter:Route(Route, 0) Helicopter:Route(Route, 0)
end end
end end

View File

@ -361,9 +361,9 @@ do -- COORDINATE
-- Adjust height -- Adjust height
if altitude==nil then if altitude==nil then
_coord.y=altitude
else
_coord.y=self:GetLandHeight() _coord.y=self:GetLandHeight()
else
_coord.y=altitude
end end
return _coord return _coord

View File

@ -20,7 +20,7 @@
-- @module Functional.Mantis -- @module Functional.Mantis
-- @image Functional.Mantis.jpg -- @image Functional.Mantis.jpg
-- Date: Jan 2021 -- Date: Feb 2021
------------------------------------------------------------------------- -------------------------------------------------------------------------
--- **MANTIS** class, extends #Core.Base#BASE --- **MANTIS** class, extends #Core.Base#BASE
@ -31,7 +31,7 @@
-- @field Core.Set#SET_GROUP SAM_Group The SAM #SET_GROUP -- @field Core.Set#SET_GROUP SAM_Group The SAM #SET_GROUP
-- @field #string EWR_Templates_Prefix Prefix to build the #SET_GROUP for EWR group -- @field #string EWR_Templates_Prefix Prefix to build the #SET_GROUP for EWR group
-- @field Core.Set#SET_GROUP EWR_Group The EWR #SET_GROUP -- @field Core.Set#SET_GROUP EWR_Group The EWR #SET_GROUP
-- @field #Core.Set#SET_GROUP Adv_EWR_Group The EWR #SET_GROUP 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
@ -54,6 +54,7 @@
-- @field Functional.Shorad#SHORAD Shorad SHORAD Object, if available -- @field Functional.Shorad#SHORAD Shorad SHORAD Object, if available
-- @field #boolean ShoradLink If true, #MANTIS has #SHORAD enabled -- @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 -- @field #number ShoradTime Timer in seconds, how long #SHORAD will be active after a detection inside of the defense range
-- @field #number ShoradActDistance Distance of an attacker in meters from a Mantis SAM site, on which Shorad will be switched on. Useful to not give away Shorad sites too early. Default 15km. Should be smaller than checkradius.
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
@ -127,7 +128,7 @@
-- * grouping = 5000 (meters) - Detection (EWR) will group enemy flights to areas of 5km for tracking - `MANTIS:SetEWRGrouping(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)` -- * acceptrange = 80000 (meters) - Detection (EWR) will on consider flights inside a 80km radius - `MANTIS:SetEWRRange(radius)`
-- * detectinterval = 30 (seconds) - MANTIS will decide every 30 seconds which SAM to activate - `MANTIS:SetDetectInterval(interval)` -- * detectinterval = 30 (seconds) - MANTIS will decide every 30 seconds which SAM to activate - `MANTIS:SetDetectInterval(interval)`
-- * engagerange = 75 (percent) - SAMs will only fire if flights are inside of a 75% radius of their max firerange - `MANTIS:SetSAMRange(range)` -- * engagerange = 85 (percent) - SAMs will only fire if flights are inside of a 85% radius of their max firerange - `MANTIS:SetSAMRange(range)`
-- * dynamic = false - Group filtering is set to once, i.e. newly added groups will not be part of the setup by default - `MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic)` -- * dynamic = false - Group filtering is set to once, i.e. newly added groups will not be part of the setup by default - `MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic)`
-- * autorelocate = false - HQ and (mobile) EWR system will not relocate in random intervals between 30mins and 1 hour - `MANTIS:SetAutoRelocate(hq, ewr)` -- * 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)` -- * debug = false - Debugging reports on screen are set to off - `MANTIS:Debug(onoff)`
@ -135,9 +136,27 @@
-- # 4. Advanced Mode -- # 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. -- 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 )` -- E.g. `mymantis:SetAdvancedMode( true, 90 )`
--
-- Use this option if you want to make use of or allow advanced SEAD tactics. -- Use this option if you want to make use of or allow advanced SEAD tactics.
-- --
-- # 5. Integrate SHORAD
--
-- You can also choose to integrate Mantis with @{Functional.Shorad#SHORAD} for protection against HARMs and AGMs. When SHORAD detects a missile fired at one of MANTIS' SAM sites, it will activate SHORAD systems in
-- the given defense checkradius around that SAM site. Create a SHORAD object first, then integrate with MANTIS like so:
--
-- `local SamSet = SET_GROUP:New():FilterPrefixes("Blue SAM"):FilterCoalitions("blue"):FilterStart()`
-- `myshorad = SHORAD:New("BlueShorad", "Blue SHORAD", SamSet, 22000, 600, "blue")`
-- `-- now set up MANTIS`
-- `mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")`
-- `mymantis:AddShorad(myshorad,720)`
-- `mymantis:Start()`
--
-- and (optionally) remove the link later on with
--
-- `mymantis:RemoveShorad()`
--
-- @field #MANTIS -- @field #MANTIS
MANTIS = { MANTIS = {
ClassName = "MANTIS", ClassName = "MANTIS",
@ -170,6 +189,7 @@ MANTIS = {
Shorad = nil, Shorad = nil,
ShoradLink = false, ShoradLink = false,
ShoradTime = 600, ShoradTime = 600,
ShoradActDistance = 15000,
} }
----------------------------------------------------------------------- -----------------------------------------------------------------------
@ -235,19 +255,20 @@ do
self.verbose = false self.verbose = false
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 --DONE: 250km, User Function to change
self.Shorad = nil self.Shorad = nil
self.ShoradLink = false self.ShoradLink = false
self.ShoradTime = 600 self.ShoradTime = 600
self.ShoradActDistance = 15000
if type(awacs) == "string" then if type(awacs) == "string" then
self.advAwacs = true self.advAwacs = true
else else
self.advAwacs = false self.advAwacs = false
end end
-- @field #string version -- Inherit everything from BASE class.
self.version="0.3.6" local self = BASE:Inherit(self, BASE:New()) -- #MANTIS
env.info(string.format("***** Starting MANTIS Version %s *****", self.version))
-- Set the string id for output to DCS.log file. -- Set the string id for output to DCS.log file.
self.lid=string.format("MANTIS %s | ", self.name) self.lid=string.format("MANTIS %s | ", self.name)
@ -276,8 +297,10 @@ do
if self.HQ_Template_CC then if self.HQ_Template_CC then
self.HQ_CC = GROUP:FindByName(self.HQ_Template_CC) self.HQ_CC = GROUP:FindByName(self.HQ_Template_CC)
end end
-- Inherit everything from BASE class.
local self = BASE:Inherit(self, BASE:New()) -- #MANTIS -- @field #string version
self.version="0.3.7"
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
return self return self
end end
@ -380,6 +403,14 @@ do
end end
end end
--- Function to set AWACS detection range. Defaults to 250.000m (250km) - use **before** starting your Mantis!
-- @param #MANTIS self
-- @param #number range Detection range of the AWACS group
function MANTIS:SetAwacsRange(range)
local range = range or 250000
self.awacsrange = range
end
--- 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 group The #GROUP object to be set as HQ -- @param Wrapper.GROUP#GROUP group The #GROUP object to be set as HQ
@ -569,6 +600,7 @@ do
-- @param #table dectset Table of coordinates of detected items -- @param #table dectset Table of coordinates of detected items
-- @param samcoordinate Core.Point#COORDINATE Coordinate object. -- @param samcoordinate Core.Point#COORDINATE Coordinate object.
-- @return #boolean True if in any zone, else false -- @return #boolean True if in any zone, else false
-- @return #number Distance Target distance in meters or zero when no object is in zone
function MANTIS:CheckObjectInZone(dectset, samcoordinate) function MANTIS:CheckObjectInZone(dectset, samcoordinate)
self:F(self.lid.."CheckObjectInZone Called") self:F(self.lid.."CheckObjectInZone Called")
-- check if non of the coordinate is in the given defense zone -- check if non of the coordinate is in the given defense zone
@ -585,10 +617,10 @@ do
if self.verbose then env.info(self.lid..text) end if self.verbose then env.info(self.lid..text) end
-- end output to cross-check -- end output to cross-check
if targetdistance <= radius then if targetdistance <= radius then
return true return true, targetdistance
end end
end end
return false return false, 0
end end
--- (Internal) Function to start the detection via EWR groups --- (Internal) Function to start the detection via EWR groups
@ -658,7 +690,7 @@ do
-- @param #MANTIS self -- @param #MANTIS self
-- @return #MANTIS self -- @return #MANTIS self
function MANTIS:SetSAMStartState() function MANTIS:SetSAMStartState()
-- TODO: if using dynamic filtering, update SAM_Table and the (active) SEAD groups, pull req #1405/#1406 -- DONE: if using dynamic filtering, update SAM_Table and the (active) SEAD groups, pull req #1405/#1406
self:F(self.lid.."Setting SAM Start States") self:F(self.lid.."Setting SAM Start States")
-- get SAM Group -- get SAM Group
local SAM_SET = self.SAM_Group local SAM_SET = self.SAM_Group
@ -769,13 +801,14 @@ do
local samcoordinate = _data[2] local samcoordinate = _data[2]
local name = _data[1] local name = _data[1]
local samgroup = GROUP:FindByName(name) local samgroup = GROUP:FindByName(name)
if self:CheckObjectInZone(detset, samcoordinate) then --check any target in zone local IsInZone, Distance = self:CheckObjectInZone(detset, samcoordinate)
if IsInZone then --check any target in zone
if samgroup:IsAlive() then if samgroup:IsAlive() then
-- switch off SAM -- switch off SAM
samgroup:OptionAlarmStateRed() samgroup:OptionAlarmStateRed()
-- link in to SHORAD if available -- link in to SHORAD if available
-- TODO Test integration fully -- DONE: Test integration fully
if self.ShoradLink then if self.ShoradLink and Distance < self.ShoradActDistance then -- don't give SHORAD position away too early
local Shorad = self.Shorad local Shorad = self.Shorad
local radius = self.checkradius local radius = self.checkradius
local ontime = self.ShoradTime local ontime = self.ShoradTime

View File

@ -378,7 +378,14 @@ do
-- @param #string TargetGroup Name of the target group used to build the #ZONE -- @param #string TargetGroup Name of the target group used to build the #ZONE
-- @param #number Radius Radius of the #ZONE -- @param #number Radius Radius of the #ZONE
-- @param #number ActiveTimer Number of seconds to stay active -- @param #number ActiveTimer Number of seconds to stay active
-- @usage Use this function to integrate with other systems. -- @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)
-- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
-- mymantis:AddShorad(myshorad,720)
-- mymantis:Start()
function SHORAD:WakeUpShorad(TargetGroup, Radius, ActiveTimer) function SHORAD:WakeUpShorad(TargetGroup, Radius, ActiveTimer)
self:F({TargetGroup, Radius, ActiveTimer}) self:F({TargetGroup, Radius, ActiveTimer})
local targetgroup = GROUP:FindByName(TargetGroup) local targetgroup = GROUP:FindByName(TargetGroup)

View File

@ -966,7 +966,7 @@ function AIRWING:CheckTANKER()
local altitude=patrol.altitude+1000*patrol.noccupied local altitude=patrol.altitude+1000*patrol.noccupied
local mission=AUFTRAG:NewTANKER(patrol.coord, altitude, patrol.speed, patrol.heading, patrol.leg, 0) local mission=AUFTRAG:NewTANKER(patrol.coord, altitude, patrol.speed, patrol.heading, patrol.leg, 1)
mission.patroldata=patrol mission.patroldata=patrol
@ -984,7 +984,7 @@ function AIRWING:CheckTANKER()
local altitude=patrol.altitude+1000*patrol.noccupied local altitude=patrol.altitude+1000*patrol.noccupied
local mission=AUFTRAG:NewTANKER(patrol.coord, altitude, patrol.speed, patrol.heading, patrol.leg, 1) local mission=AUFTRAG:NewTANKER(patrol.coord, altitude, patrol.speed, patrol.heading, patrol.leg, 0)
mission.patroldata=patrol mission.patroldata=patrol

View File

@ -39,6 +39,7 @@
-- * [F-14A/B Tomcat](https://forums.eagle.ru/forumdisplay.php?f=395) (Player & AI) -- * [F-14A/B Tomcat](https://forums.eagle.ru/forumdisplay.php?f=395) (Player & AI)
-- * [A-4E Skyhawk Community Mod](https://forums.eagle.ru/showthread.php?t=224989) (Player & AI) -- * [A-4E Skyhawk Community Mod](https://forums.eagle.ru/showthread.php?t=224989) (Player & AI)
-- * [AV-8B N/A Harrier](https://forums.eagle.ru/forumdisplay.php?f=555) (Player & AI) [**WIP**] -- * [AV-8B N/A Harrier](https://forums.eagle.ru/forumdisplay.php?f=555) (Player & AI) [**WIP**]
-- * [T-45C Goshawk (VNAO)(Player & AI)]
-- * F/A-18C Hornet (AI) -- * F/A-18C Hornet (AI)
-- * F-14A Tomcat (AI) -- * F-14A Tomcat (AI)
-- * E-2D Hawkeye (AI) -- * E-2D Hawkeye (AI)
@ -1271,6 +1272,7 @@ AIRBOSS.AircraftCarrier={
F14B="F-14B", F14B="F-14B",
F14A_AI="F-14A", F14A_AI="F-14A",
FA18C="F/A-18C", FA18C="F/A-18C",
T45C="T-45",
S3B="S-3B", S3B="S-3B",
S3BTANKER="S-3B Tanker", S3BTANKER="S-3B Tanker",
E2D="E-2C", E2D="E-2C",
@ -1705,7 +1707,7 @@ AIRBOSS.MenuF10Root=nil
--- Airboss class version. --- Airboss class version.
-- @field #string version -- @field #string version
AIRBOSS.version="1.1.5" AIRBOSS.version="1.1.6"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -2646,6 +2648,15 @@ function AIRBOSS:SetRecoveryTurnTime(interval)
return self return self
end end
--- Set multiplayer environment wire correction.
-- @param #AIRBOSS self
-- @param #number Dcorr Correction distance in meters. Default 8.7 m.
-- @return #AIRBOSS self
function AIRBOSS:SetMPWireCorrection(Dcorr)
self.mpWireCorrection=Dcorr or 8.7
return self
end
--- Set time interval for updating queues and other stuff. --- Set time interval for updating queues and other stuff.
-- @param #AIRBOSS self -- @param #AIRBOSS self
-- @param #number interval Time interval in seconds. Default 30 sec. -- @param #number interval Time interval in seconds. Default 30 sec.
@ -4169,7 +4180,7 @@ function AIRBOSS:_InitStennis()
-- Carrier Parameters. -- Carrier Parameters.
self.carrierparam.sterndist =-153 self.carrierparam.sterndist =-153
self.carrierparam.deckheight = 19 self.carrierparam.deckheight = 19.06
-- Total size of the carrier (approx as rectangle). -- Total size of the carrier (approx as rectangle).
self.carrierparam.totlength=310 -- Wiki says 332.8 meters overall length. self.carrierparam.totlength=310 -- Wiki says 332.8 meters overall length.
@ -4177,7 +4188,7 @@ function AIRBOSS:_InitStennis()
self.carrierparam.totwidthstarboard=30 self.carrierparam.totwidthstarboard=30
-- Landing runway. -- Landing runway.
self.carrierparam.rwyangle = -9 self.carrierparam.rwyangle = -9.1359
self.carrierparam.rwylength = 225 self.carrierparam.rwylength = 225
self.carrierparam.rwywidth = 20 self.carrierparam.rwywidth = 20
@ -4320,7 +4331,7 @@ function AIRBOSS:_InitNimitz()
-- Carrier Parameters. -- Carrier Parameters.
self.carrierparam.sterndist =-164 self.carrierparam.sterndist =-164
self.carrierparam.deckheight = 20 self.carrierparam.deckheight = 20.1494 --DCS World OpenBeta\CoreMods\tech\USS_Nimitz\Database\USS_CVN_7X.lua
-- Total size of the carrier (approx as rectangle). -- Total size of the carrier (approx as rectangle).
self.carrierparam.totlength=332.8 -- Wiki says 332.8 meters overall length. self.carrierparam.totlength=332.8 -- Wiki says 332.8 meters overall length.
@ -4328,7 +4339,7 @@ function AIRBOSS:_InitNimitz()
self.carrierparam.totwidthstarboard=35 self.carrierparam.totwidthstarboard=35
-- Landing runway. -- Landing runway.
self.carrierparam.rwyangle = -9 self.carrierparam.rwyangle = -9.1359 --DCS World OpenBeta\CoreMods\tech\USS_Nimitz\scripts\USS_Nimitz_RunwaysAndRoutes.lua
self.carrierparam.rwylength = 250 self.carrierparam.rwylength = 250
self.carrierparam.rwywidth = 25 self.carrierparam.rwywidth = 25
@ -5471,6 +5482,7 @@ function AIRBOSS:_GetAircraftAoA(playerData)
-- Get AC type. -- Get AC type.
local hornet=playerData.actype==AIRBOSS.AircraftCarrier.HORNET local hornet=playerData.actype==AIRBOSS.AircraftCarrier.HORNET
local goshawk=playerData.actype==AIRBOSS.AircraftCarrier.T45C
local skyhawk=playerData.actype==AIRBOSS.AircraftCarrier.A4EC local skyhawk=playerData.actype==AIRBOSS.AircraftCarrier.A4EC
local harrier=playerData.actype==AIRBOSS.AircraftCarrier.AV8B local harrier=playerData.actype==AIRBOSS.AircraftCarrier.AV8B
local tomcat=playerData.actype==AIRBOSS.AircraftCarrier.F14A or playerData.actype==AIRBOSS.AircraftCarrier.F14B local tomcat=playerData.actype==AIRBOSS.AircraftCarrier.F14A or playerData.actype==AIRBOSS.AircraftCarrier.F14B
@ -5497,6 +5509,15 @@ function AIRBOSS:_GetAircraftAoA(playerData)
aoa.OnSpeedMin = self:_AoAUnit2Deg(playerData, 14.5) --14.17 --14.5 units aoa.OnSpeedMin = self:_AoAUnit2Deg(playerData, 14.5) --14.17 --14.5 units
aoa.Fast = self:_AoAUnit2Deg(playerData, 14.0) --13.33 --14.0 units aoa.Fast = self:_AoAUnit2Deg(playerData, 14.0) --13.33 --14.0 units
aoa.FAST = self:_AoAUnit2Deg(playerData, 13.0) --11.67 --13.0 units aoa.FAST = self:_AoAUnit2Deg(playerData, 13.0) --11.67 --13.0 units
elseif goshawk then
-- T-45C Goshawk parameters.
aoa.SLOW = 8.00 --19
aoa.Slow = 7.75 --18
aoa.OnSpeedMax = 7.25 --17.5
aoa.OnSpeed = 7.00 --17
aoa.OnSpeedMin = 6.75 --16.5
aoa.Fast = 6.25 --16
aoa.FAST = 6.00 --15
elseif skyhawk then elseif skyhawk then
-- A-4E-C Skyhawk parameters from https://forums.eagle.ru/showpost.php?p=3703467&postcount=390 -- A-4E-C Skyhawk parameters from https://forums.eagle.ru/showpost.php?p=3703467&postcount=390
-- Note that these are arbitrary UNITS and not degrees. We need a conversion formula! -- Note that these are arbitrary UNITS and not degrees. We need a conversion formula!
@ -5681,6 +5702,9 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
elseif skyhawk then elseif skyhawk then
alt=UTILS.FeetToMeters(600) alt=UTILS.FeetToMeters(600)
speed=UTILS.KnotsToMps(250) speed=UTILS.KnotsToMps(250)
elseif goshawk then
alt=UTILS.FeetToMeters(800)
speed=UTILS.KnotsToMps(300)
end end
elseif step==AIRBOSS.PatternStep.BREAKENTRY then elseif step==AIRBOSS.PatternStep.BREAKENTRY then
@ -5691,11 +5715,14 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
elseif skyhawk then elseif skyhawk then
alt=UTILS.FeetToMeters(600) alt=UTILS.FeetToMeters(600)
speed=UTILS.KnotsToMps(250) speed=UTILS.KnotsToMps(250)
elseif goshawk then
alt=UTILS.FeetToMeters(800)
speed=UTILS.KnotsToMps(300)
end end
elseif step==AIRBOSS.PatternStep.EARLYBREAK then elseif step==AIRBOSS.PatternStep.EARLYBREAK then
if hornet or tomcat or harrier then if hornet or tomcat or harrier or goshawk then
alt=UTILS.FeetToMeters(800) alt=UTILS.FeetToMeters(800)
elseif skyhawk then elseif skyhawk then
alt=UTILS.FeetToMeters(600) alt=UTILS.FeetToMeters(600)
@ -5703,7 +5730,7 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
elseif step==AIRBOSS.PatternStep.LATEBREAK then elseif step==AIRBOSS.PatternStep.LATEBREAK then
if hornet or tomcat or harrier then if hornet or tomcat or harrier or goshawk then
alt=UTILS.FeetToMeters(800) alt=UTILS.FeetToMeters(800)
elseif skyhawk then elseif skyhawk then
alt=UTILS.FeetToMeters(600) alt=UTILS.FeetToMeters(600)
@ -5711,7 +5738,7 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
elseif step==AIRBOSS.PatternStep.ABEAM then elseif step==AIRBOSS.PatternStep.ABEAM then
if hornet or tomcat or harrier then if hornet or tomcat or harrier or goshawk then
alt=UTILS.FeetToMeters(600) alt=UTILS.FeetToMeters(600)
elseif skyhawk then elseif skyhawk then
alt=UTILS.FeetToMeters(500) alt=UTILS.FeetToMeters(500)
@ -5726,10 +5753,19 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
dist=UTILS.NMToMeters(1.2) dist=UTILS.NMToMeters(1.2)
end end
if goshawk then
-- 0.9 to 1.1 NM per natops ch.4 page 48
dist=UTILS.NMToMeters(0.9)
else
dist=UTILS.NMToMeters(1.1)
end
elseif step==AIRBOSS.PatternStep.NINETY then elseif step==AIRBOSS.PatternStep.NINETY then
if hornet or tomcat then if hornet or tomcat then
alt=UTILS.FeetToMeters(500) alt=UTILS.FeetToMeters(500)
elseif goshawk then
alt=UTILS.FeetToMeters(450)
elseif skyhawk then elseif skyhawk then
alt=UTILS.FeetToMeters(500) alt=UTILS.FeetToMeters(500)
elseif harrier then elseif harrier then
@ -5740,7 +5776,7 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
elseif step==AIRBOSS.PatternStep.WAKE then elseif step==AIRBOSS.PatternStep.WAKE then
if hornet then if hornet or goshawk then
alt=UTILS.FeetToMeters(370) alt=UTILS.FeetToMeters(370)
elseif tomcat then elseif tomcat then
alt=UTILS.FeetToMeters(430) -- Tomcat should be a bit higher as it intercepts the GS a bit higher. alt=UTILS.FeetToMeters(430) -- Tomcat should be a bit higher as it intercepts the GS a bit higher.
@ -5753,7 +5789,7 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
elseif step==AIRBOSS.PatternStep.FINAL then elseif step==AIRBOSS.PatternStep.FINAL then
if hornet then if hornet or goshawk then
alt=UTILS.FeetToMeters(300) alt=UTILS.FeetToMeters(300)
elseif tomcat then elseif tomcat then
alt=UTILS.FeetToMeters(360) alt=UTILS.FeetToMeters(360)
@ -10370,7 +10406,7 @@ function AIRBOSS:_GetSternCoord()
self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(7, FB+90, true, true) self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(7, FB+90, true, true)
else else
-- Nimitz SC: translate 8 meters starboard wrt Final bearing. -- Nimitz SC: translate 8 meters starboard wrt Final bearing.
self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(8.5, FB+90, true, true) self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(9.5, FB+90, true, true)
end end
-- Set altitude. -- Set altitude.
@ -10401,6 +10437,11 @@ function AIRBOSS:_GetWire(Lcoord, dc)
-- Corrected landing distance wrt to stern. Landing distance needs to be reduced due to delayed landing event for human players. -- Corrected landing distance wrt to stern. Landing distance needs to be reduced due to delayed landing event for human players.
local d=Ldist-dc local d=Ldist-dc
-- Multiplayer wire correction.
if self.mpWireCorrection then
d=d-self.mpWireCorrection
end
-- Shift wires from stern to their correct position. -- Shift wires from stern to their correct position.
local w1=self.carrierparam.wire1 local w1=self.carrierparam.wire1
local w2=self.carrierparam.wire2 local w2=self.carrierparam.wire2
@ -10490,6 +10531,9 @@ function AIRBOSS:_Trapped(playerData)
dcorr=100 dcorr=100
elseif playerData.actype==AIRBOSS.AircraftCarrier.A4EC then elseif playerData.actype==AIRBOSS.AircraftCarrier.A4EC then
-- A-4E gets slowed down much faster the the F/A-18C! -- A-4E gets slowed down much faster the the F/A-18C!
dcorr=56
elseif playerData.actype==AIRBOSS.AircraftCarrier.T45C then
-- T-45 also gets slowed down much faster the the F/A-18C.
dcorr=56 dcorr=56
end end
@ -12001,15 +12045,15 @@ function AIRBOSS:_EvalGrooveTime(playerData)
local grade="" local grade=""
if t<9 then if t<9 then
grade="--" grade="_NESA_"
elseif t<12 then elseif t<15 then
grade="(OK)" grade="NESA"
elseif t<22 then elseif t<19 then
grade="OK" grade="OK Groove"
elseif t<=24 then elseif t<=24 then
grade="(OK)" grade="(LIG)"
else else
grade="--" grade="LIG"
end end
-- The unicorn! -- The unicorn!
@ -12050,7 +12094,7 @@ function AIRBOSS:_LSOgrade(playerData)
-- Groove time 16-18 sec for a unicorn. -- Groove time 16-18 sec for a unicorn.
local Tgroove=playerData.Tgroove local Tgroove=playerData.Tgroove
local TgrooveUnicorn=Tgroove and (Tgroove>=16.0 and Tgroove<=18.0) or false local TgrooveUnicorn=Tgroove and (Tgroove>=15.0 and Tgroove<=18.99) or false
local grade local grade
local points local points
@ -14080,6 +14124,8 @@ function AIRBOSS:_GetACNickname(actype)
local nickname="unknown" local nickname="unknown"
if actype==AIRBOSS.AircraftCarrier.A4EC then if actype==AIRBOSS.AircraftCarrier.A4EC then
nickname="Skyhawk" nickname="Skyhawk"
elseif actype==AIRBOSS.AircraftCarrier.T45C then
nickname="Goshawk"
elseif actype==AIRBOSS.AircraftCarrier.AV8B then elseif actype==AIRBOSS.AircraftCarrier.AV8B then
nickname="Harrier" nickname="Harrier"
elseif actype==AIRBOSS.AircraftCarrier.E2D then elseif actype==AIRBOSS.AircraftCarrier.E2D then

View File

@ -31,6 +31,7 @@
-- @field #boolean clustermarkers If true, create cluster markers on F10 map. -- @field #boolean clustermarkers If true, create cluster markers on F10 map.
-- @field #number clustercounter Running number of clusters. -- @field #number clustercounter Running number of clusters.
-- @field #number dTforget Time interval in seconds before a known contact which is not detected any more is forgotten. -- @field #number dTforget Time interval in seconds before a known contact which is not detected any more is forgotten.
-- @field #number clusterradius Radius im kilometers in which groups/units are considered to belong to a cluster
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
--- Top Secret! --- Top Secret!
@ -46,7 +47,7 @@
-- @field #INTEL -- @field #INTEL
INTEL = { INTEL = {
ClassName = "INTEL", ClassName = "INTEL",
verbose = 2, verbose = 0,
lid = nil, lid = nil,
alias = nil, alias = nil,
filterCategory = {}, filterCategory = {},
@ -56,6 +57,7 @@ INTEL = {
ContactsUnknown = {}, ContactsUnknown = {},
Clusters = {}, Clusters = {},
clustercounter = 1, clustercounter = 1,
clusterradius = 15,
} }
--- Detected item info. --- Detected item info.
@ -74,6 +76,8 @@ INTEL = {
-- @field #boolean isship -- @field #boolean isship
-- @field #boolean ishelo -- @field #boolean ishelo
-- @field #boolean isgrund -- @field #boolean isgrund
-- @field Ops.Auftrag#AUFTRAG mission The current Auftrag attached to this contact
-- @field #string recce The name of the recce unit that detected this contact
--- Cluster info. --- Cluster info.
-- @type INTEL.Cluster -- @type INTEL.Cluster
@ -85,11 +89,12 @@ INTEL = {
-- @field #number threatlevelAve Average of threat levels. -- @field #number threatlevelAve Average of threat levels.
-- @field Core.Point#COORDINATE coordinate Coordinate of the cluster. -- @field Core.Point#COORDINATE coordinate Coordinate of the cluster.
-- @field Wrapper.Marker#MARKER marker F10 marker. -- @field Wrapper.Marker#MARKER marker F10 marker.
-- @field Ops.Auftrag#AUFTRAG mission The current Auftrag attached to this cluster
--- INTEL class version. --- INTEL class version.
-- @field #string version -- @field #string version
INTEL.version="0.1.0" INTEL.version="0.2.0"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list -- ToDo list
@ -175,6 +180,8 @@ function INTEL:New(DetectionSet, Coalition, Alias)
self:AddTransition("*", "NewContact", "*") -- New contact has been detected. self:AddTransition("*", "NewContact", "*") -- New contact has been detected.
self:AddTransition("*", "LostContact", "*") -- Contact could not be detected any more. self:AddTransition("*", "LostContact", "*") -- Contact could not be detected any more.
self:AddTransition("*", "NewCluster", "*") -- New cluster has been detected.
self:AddTransition("*", "LostCluster", "*") -- Cluster could not be detected any more.
-- Defaults -- Defaults
self:SetForgetTime() self:SetForgetTime()
@ -211,9 +218,42 @@ function INTEL:New(DetectionSet, Coalition, Alias)
-- @param #INTEL self -- @param #INTEL self
-- @param #number delay Delay in seconds. -- @param #number delay Delay in seconds.
--- On After "NewContact" event.
-- @function [parent=#INTEL] OnAfterNewContact
-- @param #INTEL self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #INTEL.Contact Contact Detected contact.
--- On After "LostContact" event.
-- @function [parent=#INTEL] OnAfterLostContact
-- @param #INTEL self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #INTEL.Contact Contact Lost contact.
--- On After "NewCluster" event.
-- @function [parent=#INTEL] OnAfterNewCluster
-- @param #INTEL self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #INTEL.Contact Contact Detected contact.
-- @param #INTEL.Cluster Cluster Detected cluster
--- On After "LostCluster" event.
-- @function [parent=#INTEL] OnAfterLostCluster
-- @param #INTEL self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #INTEL.Cluster Cluster Lost cluster
-- @param Ops.Auftrag#AUFTRAG Mission The Auftrag connected with this cluster or nil
return self return self
end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User functions -- User functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -307,7 +347,7 @@ function INTEL:SetFilterCategory(Categories)
for _,category in pairs(self.filterCategory) do for _,category in pairs(self.filterCategory) do
text=text..string.format("%d,", category) text=text..string.format("%d,", category)
end end
self:I(self.lid..text) self:T(self.lid..text)
return self return self
end end
@ -334,7 +374,7 @@ function INTEL:FilterCategoryGroup(GroupCategories)
for _,category in pairs(self.filterCategoryGroup) do for _,category in pairs(self.filterCategoryGroup) do
text=text..string.format("%d,", category) text=text..string.format("%d,", category)
end end
self:I(self.lid..text) self:T(self.lid..text)
return self return self
end end
@ -351,6 +391,49 @@ function INTEL:SetClusterAnalysis(Switch, Markers)
return self return self
end end
--- Set verbosity level for debugging.
-- @param #INTEL self
-- @param #number Verbosity The higher, the noisier, e.g. 0=off, 2=debug
-- @return #INTEL self
function INTEL:SetVerbosity(Verbosity)
self.verbose=Verbosity or 2
return self
end
--- Add a Mission (Auftrag) to a contact for tracking.
-- @param #INTEL self
-- @param #INTEL.Contact Contact The contact
-- @param Ops.Auftrag#AUFTRAG Mission The mission connected with this contact
-- @return #INTEL self
function INTEL:AddMissionToContact(Contact, Mission)
if Mission and Contact then
Contact.mission = Mission
end
return self
end
--- Add a Mission (Auftrag) to a cluster for tracking.
-- @param #INTEL self
-- @param #INTEL.Cluster Cluster The cluster
-- @param Ops.Auftrag#AUFTRAG Mission The mission connected with this cluster
-- @return #INTEL self
function INTEL:AddMissionToCluster(Cluster, Mission)
if Mission and Cluster then
Cluster.mission = Mission
end
return self
end
--- Change radius of the Clusters
-- @param #INTEL self
-- @param #number radius The radius of the clusters
-- @return #INTEL self
function INTEL:SetClusterRadius(radius)
local radius = radius or 15
self.clusterradius = radius
return self
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status -- Start & Status
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -389,10 +472,11 @@ function INTEL:onafterStatus(From, Event, To)
-- Number of total contacts. -- Number of total contacts.
local Ncontacts=#self.Contacts local Ncontacts=#self.Contacts
local Nclusters=#self.Clusters
-- Short info. -- Short info.
if self.verbose>=1 then if self.verbose>=1 then
local text=string.format("Status %s [Agents=%s]: Contacts=%d, New=%d, Lost=%d", fsmstate, self.detectionset:CountAlive(), Ncontacts, #self.ContactsUnknown, #self.ContactsLost) local text=string.format("Status %s [Agents=%s]: Contacts=%d, Clusters=%d, New=%d, Lost=%d", fsmstate, self.detectionset:CountAlive(), Ncontacts, Nclusters, #self.ContactsUnknown, #self.ContactsLost)
self:I(self.lid..text) self:I(self.lid..text)
end end
@ -421,7 +505,8 @@ function INTEL:UpdateIntel()
-- Set of all detected units. -- Set of all detected units.
local DetectedUnits={} local DetectedUnits={}
-- Set of which units was detected by which recce
local RecceDetecting = {}
-- Loop over all units providing intel. -- Loop over all units providing intel.
for _,_group in pairs(self.detectionset.Set or {}) do for _,_group in pairs(self.detectionset.Set or {}) do
local group=_group --Wrapper.Group#GROUP local group=_group --Wrapper.Group#GROUP
@ -432,7 +517,7 @@ function INTEL:UpdateIntel()
local recce=_recce --Wrapper.Unit#UNIT local recce=_recce --Wrapper.Unit#UNIT
-- Get detected units. -- Get detected units.
self:GetDetectedUnits(recce, DetectedUnits) self:GetDetectedUnits(recce, DetectedUnits, RecceDetecting)
end end
@ -489,7 +574,7 @@ function INTEL:UpdateIntel()
end end
end end
if not keepit then if not keepit then
self:I(self.lid..string.format("Removing unit %s category=%d", unitname, unit:GetCategory())) self:T(self.lid..string.format("Removing unit %s category=%d", unitname, unit:GetCategory()))
table.insert(remove, unitname) table.insert(remove, unitname)
end end
end end
@ -503,16 +588,19 @@ function INTEL:UpdateIntel()
-- Create detected groups. -- Create detected groups.
local DetectedGroups={} local DetectedGroups={}
local RecceGroups={}
for unitname,_unit in pairs(DetectedUnits) do for unitname,_unit in pairs(DetectedUnits) do
local unit=_unit --Wrapper.Unit#UNIT local unit=_unit --Wrapper.Unit#UNIT
local group=unit:GetGroup() local group=unit:GetGroup()
if group then if group then
DetectedGroups[group:GetName()]=group local groupname = group:GetName()
DetectedGroups[groupname]=group
RecceGroups[groupname]=RecceDetecting[unitname]
end end
end end
-- Create detected contacts. -- Create detected contacts.
self:CreateDetectedItems(DetectedGroups) self:CreateDetectedItems(DetectedGroups, RecceGroups)
-- Paint a picture of the battlefield. -- Paint a picture of the battlefield.
if self.clusteranalysis then if self.clusteranalysis then
@ -528,8 +616,9 @@ end
--- Create detected items. --- Create detected items.
-- @param #INTEL self -- @param #INTEL self
-- @param #table DetectedGroups Table of detected Groups -- @param #table DetectedGroups Table of detected Groups
function INTEL:CreateDetectedItems(DetectedGroups) -- @param #table RecceDetecting Table of detecting recce names
function INTEL:CreateDetectedItems(DetectedGroups, RecceDetecting)
self:F({RecceDetecting=RecceDetecting})
-- Current time. -- Current time.
local Tnow=timer.getAbsTime() local Tnow=timer.getAbsTime()
@ -569,7 +658,8 @@ function INTEL:CreateDetectedItems(DetectedGroups)
item.position=group:GetCoordinate() item.position=group:GetCoordinate()
item.velocity=group:GetVelocityVec3() item.velocity=group:GetVelocityVec3()
item.speed=group:GetVelocityMPS() item.speed=group:GetVelocityMPS()
item.recce=RecceDetecting[groupname]
self:T(string.format("%s group detect by %s/%s", groupname, RecceDetecting[groupname] or "unknonw", item.recce or "unknown"))
-- Add contact to table. -- Add contact to table.
self:AddContact(item) self:AddContact(item)
@ -602,16 +692,19 @@ end
-- If no detection method is given, the detection will use all the available methods by default. -- If no detection method is given, the detection will use all the available methods by default.
-- @param #INTEL self -- @param #INTEL self
-- @param Wrapper.Unit#UNIT Unit The unit detecting. -- @param Wrapper.Unit#UNIT Unit The unit detecting.
-- @param #table DetectedUnits Table of detected units to be filled
-- @param #table RecceDetecting Table of recce per unit to be filled
-- @param #boolean DetectVisual (Optional) If *false*, do not include visually detected targets. -- @param #boolean DetectVisual (Optional) If *false*, do not include visually detected targets.
-- @param #boolean DetectOptical (Optional) If *false*, do not include optically detected targets. -- @param #boolean DetectOptical (Optional) If *false*, do not include optically detected targets.
-- @param #boolean DetectRadar (Optional) If *false*, do not include targets detected by radar. -- @param #boolean DetectRadar (Optional) If *false*, do not include targets detected by radar.
-- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST. -- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST.
-- @param #boolean DetectRWR (Optional) If *false*, do not include targets detected by RWR. -- @param #boolean DetectRWR (Optional) If *false*, do not include targets detected by RWR.
-- @param #boolean DetectDLINK (Optional) If *false*, do not include targets detected by data link. -- @param #boolean DetectDLINK (Optional) If *false*, do not include targets detected by data link.
function INTEL:GetDetectedUnits(Unit, DetectedUnits, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK) function INTEL:GetDetectedUnits(Unit, DetectedUnits, RecceDetecting, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK)
-- Get detected DCS units. -- Get detected DCS units.
local detectedtargets=Unit:GetDetectedTargets(DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK) local detectedtargets=Unit:GetDetectedTargets(DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK)
local reccename = Unit:GetName()
for DetectionObjectID, Detection in pairs(detectedtargets or {}) do for DetectionObjectID, Detection in pairs(detectedtargets or {}) do
local DetectedObject=Detection.object -- DCS#Object local DetectedObject=Detection.object -- DCS#Object
@ -625,7 +718,8 @@ function INTEL:GetDetectedUnits(Unit, DetectedUnits, DetectVisual, DetectOptical
local unitname=unit:GetName() local unitname=unit:GetName()
DetectedUnits[unitname]=unit DetectedUnits[unitname]=unit
RecceDetecting[unitname]=reccename
self:T(string.format("Unit %s detect by %s", unitname, reccename))
end end
end end
end end
@ -643,7 +737,7 @@ end
-- @param #string To To state. -- @param #string To To state.
-- @param #INTEL.Contact Contact Detected contact. -- @param #INTEL.Contact Contact Detected contact.
function INTEL:onafterNewContact(From, Event, To, Contact) function INTEL:onafterNewContact(From, Event, To, Contact)
self:I(self.lid..string.format("NEW contact %s", Contact.groupname)) self:F(self.lid..string.format("NEW contact %s", Contact.groupname))
table.insert(self.ContactsUnknown, Contact) table.insert(self.ContactsUnknown, Contact)
end end
@ -654,10 +748,37 @@ end
-- @param #string To To state. -- @param #string To To state.
-- @param #INTEL.Contact Contact Detected contact. -- @param #INTEL.Contact Contact Detected contact.
function INTEL:onafterLostContact(From, Event, To, Contact) function INTEL:onafterLostContact(From, Event, To, Contact)
self:I(self.lid..string.format("LOST contact %s", Contact.groupname)) self:F(self.lid..string.format("LOST contact %s", Contact.groupname))
table.insert(self.ContactsLost, Contact) table.insert(self.ContactsLost, Contact)
end end
--- On after "NewCluster" event.
-- @param #INTEL self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #INTEL.Contact Contact Detected contact.
-- @param #INTEL.Cluster Cluster Detected cluster
function INTEL:onafterNewCluster(From, Event, To, Contact, Cluster)
self:F(self.lid..string.format("NEW cluster %d size %d with contact %s", Cluster.index, Cluster.size, Contact.groupname))
end
--- On after "LostCluster" event.
-- @param #INTEL self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #INTEL.Cluster Cluster Lost cluster
-- @param Ops.Auftrag#AUFTRAG Mission The Auftrag connected with this cluster or nil
function INTEL:onafterLostCluster(From, Event, To, Cluster, Mission)
local text = self.lid..string.format("LOST cluster %d", Cluster.index)
if Mission then
local mission=Mission --Ops.Auftrag#AUFTRAG
text=text..string.format(" mission name=%s type=%s target=%s", mission.name, mission.type, mission:GetTargetName() or "unkown")
end
self:T(text)
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Misc Functions -- Misc Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -752,11 +873,27 @@ function INTEL:PaintPicture()
self:RemoveContactFromCluster(contact, cluster) self:RemoveContactFromCluster(contact, cluster)
end end
end end
-- clean up cluster table
local ClusterSet = {}
for _i,_cluster in pairs(self.Clusters) do
if (_cluster.size > 0) and (self:ClusterCountUnits(_cluster) > 0) then
table.insert(ClusterSet,_cluster)
else
local mission = _cluster.mission or nil
local marker = _cluster.marker
if marker then
marker:Remove()
end
self:LostCluster(_cluster, mission)
end
end
self.Clusters = ClusterSet
-- update positions
self:_UpdateClusterPositions()
for _,_contact in pairs(self.Contacts) do for _,_contact in pairs(self.Contacts) do
local contact=_contact --#INTEL.Contact local contact=_contact --#INTEL.Contact
self:T(string.format("Paint Picture: checking for %s",contact.groupname))
-- Check if this contact is in any cluster. -- Check if this contact is in any cluster.
local isincluster=self:CheckContactInClusters(contact) local isincluster=self:CheckContactInClusters(contact)
@ -764,7 +901,7 @@ function INTEL:PaintPicture()
local currentcluster=self:GetClusterOfContact(contact) local currentcluster=self:GetClusterOfContact(contact)
if currentcluster then if currentcluster then
--self:I(string.format("Paint Picture: %s has current cluster",contact.groupname))
--- ---
-- Contact is currently part of a cluster. -- Contact is currently part of a cluster.
--- ---
@ -772,8 +909,8 @@ function INTEL:PaintPicture()
-- Check if the contact is still connected to the cluster. -- Check if the contact is still connected to the cluster.
local isconnected=self:IsContactConnectedToCluster(contact, currentcluster) local isconnected=self:IsContactConnectedToCluster(contact, currentcluster)
if not isconnected then if (not isconnected) and (currentcluster.size > 1) then
--self:I(string.format("Paint Picture: %s has LOST current cluster",contact.groupname))
local cluster=self:IsContactPartOfAnyClusters(contact) local cluster=self:IsContactPartOfAnyClusters(contact)
if cluster then if cluster then
@ -782,6 +919,7 @@ function INTEL:PaintPicture()
local newcluster=self:CreateCluster(contact.position) local newcluster=self:CreateCluster(contact.position)
self:AddContactToCluster(contact, newcluster) self:AddContactToCluster(contact, newcluster)
self:NewCluster(contact, newcluster)
end end
end end
@ -792,7 +930,7 @@ function INTEL:PaintPicture()
--- ---
-- Contact is not in any cluster yet. -- Contact is not in any cluster yet.
--- ---
--self:I(string.format("Paint Picture: %s has NO current cluster",contact.groupname))
local cluster=self:IsContactPartOfAnyClusters(contact) local cluster=self:IsContactPartOfAnyClusters(contact)
if cluster then if cluster then
@ -801,6 +939,7 @@ function INTEL:PaintPicture()
local newcluster=self:CreateCluster(contact.position) local newcluster=self:CreateCluster(contact.position)
self:AddContactToCluster(contact, newcluster) self:AddContactToCluster(contact, newcluster)
self:NewCluster(contact, newcluster)
end end
end end
@ -810,6 +949,7 @@ function INTEL:PaintPicture()
-- Update F10 marker text if cluster has changed. -- Update F10 marker text if cluster has changed.
if self.clustermarkers then
for _,_cluster in pairs(self.Clusters) do for _,_cluster in pairs(self.Clusters) do
local cluster=_cluster --#INTEL.Cluster local cluster=_cluster --#INTEL.Cluster
@ -819,7 +959,7 @@ function INTEL:PaintPicture()
-- Update F10 marker. -- Update F10 marker.
self:UpdateClusterMarker(cluster) self:UpdateClusterMarker(cluster)
end end
end
end end
--- Create a new cluster. --- Create a new cluster.
@ -976,9 +1116,11 @@ function INTEL:IsContactConnectedToCluster(contact, cluster)
if Contact.groupname~=contact.groupname then if Contact.groupname~=contact.groupname then
local dist=Contact.position:Get2DDistance(contact.position) --local dist=Contact.position:Get2DDistance(contact.position)
local dist=Contact.position:DistanceFromPointVec2(contact.position)
if dist<10*1000 then local radius = self.clusterradius or 15
if dist<radius*1000 then
return true return true
end end
@ -1032,7 +1174,6 @@ end
-- @param #INTEL.Cluster cluster The cluster. -- @param #INTEL.Cluster cluster The cluster.
-- @return Core.Point#COORDINATE The coordinate of this cluster. -- @return Core.Point#COORDINATE The coordinate of this cluster.
function INTEL:GetClusterCoordinate(cluster) function INTEL:GetClusterCoordinate(cluster)
-- Init. -- Init.
local x=0 ; local y=0 ; local z=0 ; local n=0 local x=0 ; local y=0 ; local z=0 ; local n=0
@ -1059,11 +1200,13 @@ end
-- @param #INTEL self -- @param #INTEL self
-- @param #INTEL.Cluster cluster The cluster. -- @param #INTEL.Cluster cluster The cluster.
-- @param Core.Point#COORDINATE coordinate (Optional) Coordinate of the new cluster. Default is to calculate the current coordinate. -- @param Core.Point#COORDINATE coordinate (Optional) Coordinate of the new cluster. Default is to calculate the current coordinate.
-- @return #boolean
function INTEL:CheckClusterCoordinateChanged(cluster, coordinate) function INTEL:CheckClusterCoordinateChanged(cluster, coordinate)
coordinate=coordinate or self:GetClusterCoordinate(cluster) coordinate=coordinate or self:GetClusterCoordinate(cluster)
local dist=cluster.coordinate:Get2DDistance(coordinate) --local dist=cluster.coordinate:Get2DDistance(coordinate)
local dist=cluster.coordinate:DistanceFromPointVec2(coordinate)
if dist>1000 then if dist>1000 then
return true return true
@ -1073,6 +1216,27 @@ function INTEL:CheckClusterCoordinateChanged(cluster, coordinate)
end end
--- Update coordinates of the known clusters.
-- @param #INTEL self
function INTEL:_UpdateClusterPositions()
for _,_cluster in pairs (self.Clusters) do
local coord = self:GetClusterCoordinate(_cluster)
_cluster.coordinate = coord
self:T(self.lid..string.format("Cluster size: %s", _cluster.size))
end
end
--- Count number of units in cluster
-- @param #INTEL self
-- @param #INTEL.Cluster Cluster The cluster
-- @return #number unitcount
function INTEL:ClusterCountUnits(Cluster)
local unitcount = 0
for _,_group in pairs (Cluster.Contacts) do -- get Wrapper.GROUP#GROUP _group
unitcount = unitcount + _group.group:CountAliveUnits()
end
return unitcount
end
--- Update cluster F10 marker. --- Update cluster F10 marker.
-- @param #INTEL self -- @param #INTEL self
@ -1081,7 +1245,8 @@ end
function INTEL:UpdateClusterMarker(cluster) function INTEL:UpdateClusterMarker(cluster)
-- Create a marker. -- Create a marker.
local text=string.format("Cluster #%d. Size %d, TLsum=%d", cluster.index, cluster.size, cluster.threatlevelSum) local unitcount = self:ClusterCountUnits(cluster)
local text=string.format("Cluster #%d. Size %d, Units %d, TLsum=%d", cluster.index, cluster.size, unitcount, cluster.threatlevelSum)
if not cluster.marker then if not cluster.marker then
cluster.marker=MARKER:New(cluster.coordinate, text):ToAll() cluster.marker=MARKER:New(cluster.coordinate, text):ToAll()