diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index a9bae01c3..79f664a12 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -33,7 +33,7 @@ -- -- ## 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. -- 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. @@ -67,18 +67,6 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) self:AddTransition( "Unloaded", "Pickup", "*" ) 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( "Unboarding", "Pickup", "Unloaded" ) self:AddTransition( "Unloaded", "Unboard", "Unloaded" ) @@ -107,13 +95,31 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) -- @param #string Event -- @param #string To -- @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 -- @function [parent=#AI_CARGO_HELICOPTER] Pickup -- @param #AI_CARGO_HELICOPTER self -- @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 -- @function [parent=#AI_CARGO_HELICOPTER] __Pickup @@ -129,7 +135,7 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) -- @param #string Event -- @param #string To -- @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 --- Deploy Handler OnAfter for AI_CARGO_HELICOPTER @@ -139,21 +145,42 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) -- @param #string Event -- @param #string To -- @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 -- @function [parent=#AI_CARGO_HELICOPTER] Deploy -- @param #AI_CARGO_HELICOPTER self -- @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 -- @function [parent=#AI_CARGO_HELICOPTER] __Deploy -- @param #number Delay Delay in seconds. -- @param #AI_CARGO_HELICOPTER self -- @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. -- The helicopter reference is used in the semaphore AI_CARGO_QUEUE. @@ -235,7 +262,7 @@ end -- @param Event -- @param To function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To ) - + self:F({From, Event, To}) Helicopter:F( { Name = Helicopter:GetName() } ) if Helicopter and Helicopter:IsAlive() then @@ -276,7 +303,7 @@ end -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordinate, Speed, DeployZone ) - + self:F({From, Event, To, Coordinate, Speed, DeployZone}) local HelicopterInZone = false if Helicopter and Helicopter:IsAlive() == true then @@ -359,7 +386,8 @@ end -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordinate ) - + self:F({From, Event, To, Coordinate}) + if Helicopter and Helicopter:IsAlive() then local Route = {} @@ -394,7 +422,7 @@ end -- @param #boolean Deployed Cargo is deployed. -- @return #boolean True if all cargo has been unloaded. 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 ) @@ -416,7 +444,7 @@ end -- @param Event -- @param To -- @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 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 ) @@ -485,10 +513,10 @@ end -- @param Event -- @param To -- @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. 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 self.RouteDeploy = true @@ -550,11 +578,12 @@ end -- @param Event -- @param To -- @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 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 ) - + self:F({From, Event, To, Coordinate, Speed, Height}) + if Helicopter and Helicopter:IsAlive() ~= nil then self.RouteHome = true @@ -563,7 +592,8 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat --- Calculate the target route point. - Coordinate.y = Height + --Coordinate.y = Height + Height = Height or 50 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. local CoordinateTo = Coordinate 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) @@ -589,12 +619,11 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() ) Route[#Route].task = Helicopter:TaskCombo( Tasks ) - + Route[#Route+1] = WaypointTo -- Now route the helicopter Helicopter:Route(Route, 0) - end end diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 864b56bd1..1835eb3c2 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -361,9 +361,9 @@ do -- COORDINATE -- Adjust height if altitude==nil then - _coord.y=altitude - else _coord.y=self:GetLandHeight() + else + _coord.y=altitude end return _coord diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index bc043506b..c4564fb94 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -20,7 +20,7 @@ -- @module Functional.Mantis -- @image Functional.Mantis.jpg --- Date: Jan 2021 +-- Date: Feb 2021 ------------------------------------------------------------------------- --- **MANTIS** class, extends #Core.Base#BASE @@ -31,7 +31,7 @@ -- @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 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 Wrapper.Group#GROUP HQ_CC The #GROUP object of the HQ -- @field #table SAM_Table Table of SAM sites @@ -54,6 +54,7 @@ -- @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 +-- @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 @@ -127,7 +128,7 @@ -- * 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)` -- * 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)` -- * 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)` @@ -135,8 +136,26 @@ -- # 4. Advanced Mode -- -- Advanced mode will *decrease* reactivity of MANTIS, if HQ and/or EWR network dies. Awacs is counted as one EWR unit. It will set SAMs to RED state if both are dead. Requires usage of an **HQ** object and the **dynamic** option. --- E.g. `mymantis:SetAdvancedMode( true, 90 )` +-- +-- E.g. `mymantis:SetAdvancedMode( true, 90 )` +-- -- 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 MANTIS = { @@ -169,7 +188,8 @@ MANTIS = { awacsrange = 250000, Shorad = nil, ShoradLink = false, - ShoradTime = 600, + ShoradTime = 600, + ShoradActDistance = 15000, } ----------------------------------------------------------------------- @@ -235,19 +255,20 @@ do self.verbose = false self.Adv_EWR_Group = 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.ShoradLink = false - self.ShoradTime = 600 + self.ShoradTime = 600 + self.ShoradActDistance = 15000 + if type(awacs) == "string" then self.advAwacs = true else self.advAwacs = false end - -- @field #string version - self.version="0.3.6" - env.info(string.format("***** Starting MANTIS Version %s *****", self.version)) + -- Inherit everything from BASE class. + local self = BASE:Inherit(self, BASE:New()) -- #MANTIS -- Set the string id for output to DCS.log file. self.lid=string.format("MANTIS %s | ", self.name) @@ -276,8 +297,10 @@ do if self.HQ_Template_CC then self.HQ_CC = GROUP:FindByName(self.HQ_Template_CC) end - -- Inherit everything from BASE class. - local self = BASE:Inherit(self, BASE:New()) -- #MANTIS + + -- @field #string version + self.version="0.3.7" + self:I(string.format("***** Starting MANTIS Version %s *****", self.version)) return self end @@ -379,6 +402,14 @@ do 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 -- @param #MANTIS self @@ -569,6 +600,7 @@ do -- @param #table dectset Table of coordinates of detected items -- @param samcoordinate Core.Point#COORDINATE Coordinate object. -- @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) self:F(self.lid.."CheckObjectInZone Called") -- 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 -- end output to cross-check if targetdistance <= radius then - return true + return true, targetdistance end end - return false + return false, 0 end --- (Internal) Function to start the detection via EWR groups @@ -658,7 +690,7 @@ do -- @param #MANTIS self -- @return #MANTIS self 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") -- get SAM Group local SAM_SET = self.SAM_Group @@ -769,13 +801,14 @@ do local samcoordinate = _data[2] local name = _data[1] 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 -- switch off SAM samgroup:OptionAlarmStateRed() -- link in to SHORAD if available - -- TODO Test integration fully - if self.ShoradLink then + -- DONE: Test integration fully + if self.ShoradLink and Distance < self.ShoradActDistance then -- don't give SHORAD position away too early local Shorad = self.Shorad local radius = self.checkradius local ontime = self.ShoradTime diff --git a/Moose Development/Moose/Functional/Shorad.lua b/Moose Development/Moose/Functional/Shorad.lua index 7ed638f43..7ecf59d18 100644 --- a/Moose Development/Moose/Functional/Shorad.lua +++ b/Moose Development/Moose/Functional/Shorad.lua @@ -378,7 +378,14 @@ do -- @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. + -- @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) self:F({TargetGroup, Radius, ActiveTimer}) local targetgroup = GROUP:FindByName(TargetGroup)