diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index c4564fb94..4d6565262 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: Feb 2021 +-- Date: Apr 2021 ------------------------------------------------------------------------- --- **MANTIS** class, extends #Core.Base#BASE @@ -51,6 +51,7 @@ -- @field #number adv_state Advanced mode state tracker -- @field #boolean advAwacs Boolean switch to use Awacs as a separate detection stream -- @field #number awacsrange Detection range of an optional Awacs unit +-- @field #boolean UseAIOnOff Decide if we are using AI on/off (true) or AlarmState red/green (default) -- @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 @@ -189,7 +190,8 @@ MANTIS = { Shorad = nil, ShoradLink = false, ShoradTime = 600, - ShoradActDistance = 15000, + ShoradActDistance = 15000, + UseAIOnOff = false, } ----------------------------------------------------------------------- @@ -206,6 +208,7 @@ do --@param #string coaltion Coalition side of your setup, e.g. "blue", "red" or "neutral" --@param #boolean dynamic Use constant (true) filtering or just filter once (false, default) (optional) --@param #string awacs Group name of your Awacs (optional) + --@param #boolean AIOnOff Make MANTIS switch AI on and off instead of changing the alarm state between RED and GREEN (optional) --@return #MANTIS self --@usage Start up your MANTIS with a basic setting -- @@ -227,7 +230,7 @@ do -- `mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")` -- `mybluemantis:Start()` -- - function MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic,awacs) + function MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic,awacs, AIOnOff) -- DONE: Create some user functions for these -- DONE: Make HQ useful @@ -260,6 +263,8 @@ do self.ShoradLink = false self.ShoradTime = 600 self.ShoradActDistance = 15000 + -- TODO: add emissions on/off when available .... in 2 weeks + self.UseAIOnOff = AIOnOff or false if type(awacs) == "string" then self.advAwacs = true @@ -299,7 +304,7 @@ do end -- @field #string version - self.version="0.3.7" + self.version="0.4.0" self:I(string.format("***** Starting MANTIS Version %s *****", self.version)) return self @@ -458,6 +463,13 @@ do end end + --- Set using AI on/off instead of changing alarm state + -- @param #MANTIS self + -- @param #boolean switch Decide if we are changing alarm state or AI state + function MANTIS:SetUsingAIOnOff(switch) + self.UseAIOnOff = switch or false + end + --- [Internal] Function to check if HQ is alive -- @param #MANTIS self -- @return #boolean True if HQ is alive, else false @@ -701,7 +713,12 @@ do --cycle through groups and set alarm state etc for _i,_group in pairs (SAM_Grps) do local group = _group - group:OptionAlarmStateGreen() -- AI off + -- TODO: add emissions on/off + if self.UseAIOnOff then + group:SetAIOff() + else + group:OptionAlarmStateGreen() -- AI off + end group:SetOption(AI.Option.Ground.id.AC_ENGAGEMENT_RANGE_RESTRICTION,engagerange) --default engagement will be 75% of firing range if group:IsGround() then local grpname = group:GetName() @@ -804,7 +821,11 @@ do local IsInZone, Distance = self:CheckObjectInZone(detset, samcoordinate) if IsInZone then --check any target in zone if samgroup:IsAlive() then - -- switch off SAM + -- switch on SAM + if self.UseAIOnOff then + -- TODO: add emissions on/off + samgroup:SetAIOn() + end samgroup:OptionAlarmStateRed() -- link in to SHORAD if available -- DONE: Test integration fully @@ -822,7 +843,12 @@ do else if samgroup:IsAlive() then -- switch off SAM - samgroup:OptionAlarmStateGreen() + if self.UseAIOnOff then + -- TODO: add emissions on/off + samgroup:SetAIOff() + else + samgroup:OptionAlarmStateGreen() + end --samgroup:OptionROEWeaponFree() --samgroup:SetAIOn() local text = string.format("SAM %s switched to alarm state GREEN!", name) @@ -857,6 +883,10 @@ do local name = _data[1] local samgroup = GROUP:FindByName(name) if samgroup:IsAlive() then + if self.UseAIOnOff then + -- TODO: add emissions on/off + samgroup:SetAIOn() + end samgroup:OptionAlarmStateRed() end -- end alive end -- end for loop diff --git a/Moose Development/Moose/Functional/Shorad.lua b/Moose Development/Moose/Functional/Shorad.lua index 7ecf59d18..155a86829 100644 --- a/Moose Development/Moose/Functional/Shorad.lua +++ b/Moose Development/Moose/Functional/Shorad.lua @@ -38,6 +38,7 @@ -- @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 +-- @field #boolean UseAIOnOff Decide if we are using AI on/off (true) or AlarmState red/green (default). -- @extends Core.Base#BASE --- *Good friends are worth defending.* Mr Tushman, Wonder (the Movie) @@ -94,7 +95,8 @@ SHORAD = { DefendHarms = true, DefendMavs = true, DefenseLowProb = 70, - DefenseHighProb = 90, + DefenseHighProb = 90, + UseAIOnOff = false, } ----------------------------------------------------------------------- @@ -174,7 +176,8 @@ do 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") + self.UseAIOnOff = false -- Decide if we are using AI on/off (true) or AlarmState red/green (default) + self:I("*** SHORAD - Started Version 0.1.0") -- Set the string id for output to DCS.log file. self.lid=string.format("SHORAD %s | ", self.name) self:_InitState() @@ -189,7 +192,11 @@ do self:T({set = set}) local aliveset = set:GetAliveSet() --#table for _,_group in pairs (aliveset) do + if self.UseAIOnOff then + _group:SetAIOff() + else _group:OptionAlarmStateGreen() --Wrapper.Group#GROUP + end end -- gather entropy for i=1,10 do @@ -272,6 +279,13 @@ do self.Radius = radius end + --- Set using AI on/off instead of changing alarm state + -- @param #SHORAD self + -- @param #boolean switch Decide if we are changing alarm state or AI state + function SHORAD:SetUsingAIOnOff(switch) + self.UseAIOnOff = switch or false + end + --- Check if a HARM was fired -- @param #SHORAD self -- @param #string WeaponName @@ -396,7 +410,11 @@ do local function SleepShorad(group) local groupname = group:GetName() self.ActiveGroups[groupname] = nil - group:OptionAlarmStateGreen() + if self.UseAIOnOff then + group:SetAIOff() + else + group:OptionAlarmStateGreen() + end local text = string.format("Sleeping SHORAD %s", group:GetName()) self:T(text) local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug) @@ -407,6 +425,9 @@ do local text = string.format("Waking up SHORAD %s", _group:GetName()) self:T(text) local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug) + if self.UseAIOnOff then + _group:SetAIOn() + end _group:OptionAlarmStateRed() local groupname = _group:GetName() if self.ActiveGroups[groupname] == nil then -- no timer yet for this group diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index 2f3870403..706133f4b 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -119,6 +119,7 @@ AIRWING = { pointsTANKER = {}, pointsAWACS = {}, wingcommander = nil, + markpoints = false, } --- Squadron asset. @@ -209,6 +210,7 @@ function AIRWING:New(warehousename, airwingname) self.nflightsTANKERprobe=0 self.nflightsRecoveryTanker=0 self.nflightsRescueHelo=0 + self.markpoints = false ------------------------ --- Pseudo Functions --- @@ -230,6 +232,24 @@ function AIRWING:New(warehousename, airwingname) -- @function [parent=#AIRWING] __Stop -- @param #AIRWING self -- @param #number delay Delay in seconds. + + --- On after "FlightOnMission" event. Triggered when an asset group starts a mission. + -- @function [parent=#AIRWING] OnAfterFlightOnMission + -- @param #AIRWING self + -- @param #string From The From state + -- @param #string Event The Event called + -- @param #string To The To state + -- @param Ops.FlightGroup#FLIGHTGROUP Flightgroup The Flightgroup on mission + -- @param Ops.Auftrag#AUFTRAG Mission The Auftrag of the Flightgroup + + --- On after "AssetReturned" event. Triggered when an asset group returned to its airwing. + -- @function [parent=#AIRWING] OnAfterAssetReturned + -- @param #AIRWING self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.Squadron#SQUADRON Squadron The asset squadron. + -- @param #AIRWING.SquadronAsset Asset The asset that returned. return self end @@ -647,6 +667,19 @@ function AIRWING:SetNumberTankerBoom(Nboom) return self end +--- Set markers on the map for Patrol Points. +-- @param #AIRWING self +-- @param #boolean onoff Set to true to switch markers on. +-- @return #AIRWING self +function AIRWING:ShowPatrolPointMarkers(onoff) + if onoff then + self.markpoints = true + else + self.markpoints = false + end + return self +end + --- Set number of TANKER flights with Probe constantly in the air. -- @param #AIRWING self -- @param #number Nprobe Number of flights. Default 1. @@ -689,12 +722,10 @@ end --- Update marker of the patrol point. -- @param #AIRWING.PatrolData point Patrol point table. function AIRWING.UpdatePatrolPointMarker(point) - - local text=string.format("%s Occupied=%d\nheading=%03d, leg=%d NM, alt=%d ft, speed=%d kts", - point.type, point.noccupied, point.heading, point.leg, point.altitude, point.speed) - - point.marker:UpdateText(text, 1) - + local text=string.format("%s Occupied=%d\nheading=%03d, leg=%d NM, alt=%d ft, speed=%d kts", + point.type, point.noccupied, point.heading, point.leg, point.altitude, point.speed) + + point.marker:UpdateText(text, 1) end @@ -717,10 +748,12 @@ function AIRWING:NewPatrolPoint(Type, Coordinate, Altitude, Speed, Heading, LegL patrolpoint.altitude=Altitude or math.random(10,20)*1000 patrolpoint.speed=Speed or 350 patrolpoint.noccupied=0 - patrolpoint.marker=MARKER:New(Coordinate, "New Patrol Point"):ToAll() - AIRWING.UpdatePatrolPointMarker(patrolpoint) - + if self.markpoints then + patrolpoint.marker=MARKER:New(Coordinate, "New Patrol Point"):ToAll() + AIRWING.UpdatePatrolPointMarker(patrolpoint) + end + return patrolpoint end @@ -928,7 +961,7 @@ function AIRWING:CheckCAP() patrol.noccupied=patrol.noccupied+1 - AIRWING.UpdatePatrolPointMarker(patrol) + if self.markpoints then AIRWING.UpdatePatrolPointMarker(patrol) end self:AddMission(missionCAP) @@ -972,7 +1005,7 @@ function AIRWING:CheckTANKER() patrol.noccupied=patrol.noccupied+1 - AIRWING.UpdatePatrolPointMarker(patrol) + if self.markpoints then AIRWING.UpdatePatrolPointMarker(patrol) end self:AddMission(mission) @@ -990,7 +1023,7 @@ function AIRWING:CheckTANKER() patrol.noccupied=patrol.noccupied+1 - AIRWING.UpdatePatrolPointMarker(patrol) + if self.markpoints then AIRWING.UpdatePatrolPointMarker(patrol) end self:AddMission(mission) @@ -1018,7 +1051,7 @@ function AIRWING:CheckAWACS() patrol.noccupied=patrol.noccupied+1 - AIRWING.UpdatePatrolPointMarker(patrol) + if self.markpoints then AIRWING.UpdatePatrolPointMarker(patrol) end self:AddMission(mission) @@ -1431,7 +1464,9 @@ function AIRWING:onafterMissionCancel(From, Event, To, Mission) -- Info message. self:I(self.lid..string.format("Cancel mission %s", Mission.name)) - if Mission:IsPlanned() or Mission:IsQueued() or Mission:IsRequested() then + local Ngroups = Mission:CountOpsGroups() + + if Mission:IsPlanned() or Mission:IsQueued() or Mission:IsRequested() or Ngroups == 0 then Mission:Done() diff --git a/Moose Development/Moose/Ops/Intelligence.lua b/Moose Development/Moose/Ops/Intelligence.lua index ca95135eb..9c4a3a876 100644 --- a/Moose Development/Moose/Ops/Intelligence.lua +++ b/Moose Development/Moose/Ops/Intelligence.lua @@ -1,11 +1,11 @@ --- **Ops** - Office of Military Intelligence. -- --- ## Main Features: +-- **Main Features:** -- -- * Detect and track contacts consistently -- * Detect and track clusters of contacts consistently -- * Use FSM events to link functionality into your scripts --- * Easy setup +-- * Easy setup -- -- === -- @@ -80,6 +80,7 @@ -- `local m = MESSAGE:New(text,15,"KGB"):ToAll()` -- `end` -- +-- -- @field #INTEL INTEL = { ClassName = "INTEL", @@ -93,7 +94,7 @@ INTEL = { ContactsUnknown = {}, Clusters = {}, clustercounter = 1, - clusterradius = 10, + clusterradius = 15, } --- Detected item info. @@ -130,7 +131,7 @@ INTEL = { --- INTEL class version. -- @field #string version -INTEL.version="0.2.0" +INTEL.version="0.2.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -350,7 +351,7 @@ function INTEL:RemoveRejectZone(RejectZone) return self end ---- Set forget contacts time interval. For unknown contacts only. +--- Set forget contacts time interval. -- Previously known contacts that are not detected any more, are "lost" after this time. -- This avoids fast oscillations between a contact being detected and undetected. -- @param #INTEL self @@ -465,7 +466,7 @@ end -- @param #number radius The radius of the clusters -- @return #INTEL self function INTEL:SetClusterRadius(radius) - local radius = radius or 10 + local radius = radius or 15 self.clusterradius = radius return self end @@ -1082,7 +1083,7 @@ function INTEL:CalcClusterThreatlevelSum(cluster) threatlevel=threatlevel+contact.threatlevel end - cluster.threatlevelSum = threatlevel + cluster.threatlevelSum = threatlevel return threatlevel end @@ -1094,7 +1095,7 @@ function INTEL:CalcClusterThreatlevelAverage(cluster) local threatlevel=self:CalcClusterThreatlevelSum(cluster) threatlevel=threatlevel/cluster.size - cluster.threatlevelAve = threatlevel + cluster.threatlevelAve = threatlevel return threatlevel end @@ -1114,7 +1115,7 @@ function INTEL:CalcClusterThreatlevelMax(cluster) end end - cluster.threatlevelMax = threatlevel + cluster.threatlevelMax = threatlevel return threatlevel end @@ -1155,7 +1156,7 @@ function INTEL:IsContactConnectedToCluster(contact, cluster) --local dist=Contact.position:Get2DDistance(contact.position) local dist=Contact.position:DistanceFromPointVec2(contact.position) - local radius = self.clusterradius or 10 + local radius = self.clusterradius or 15 if dist