MANTIS - Change logic to FSM, added functions

CSAR - advanced options to name injected AI downed pilots
CTLD - added Herc speed check
This commit is contained in:
Applevangelist 2021-07-13 17:50:44 +02:00
parent e33de03522
commit 433d1bbf57
3 changed files with 493 additions and 224 deletions

View File

@ -192,6 +192,16 @@ MANTIS = {
ShoradTime = 600,
ShoradActDistance = 15000,
UseEmOnOff = false,
TimeStamp = 0,
state2flag = false,
}
--- Advanced state enumerator
-- @type MANTIS.AdvancedState
MANTIS.AdvancedState = {
GREEN = 0,
AMBER = 1,
RED = 2,
}
-----------------------------------------------------------------------
@ -263,7 +273,10 @@ do
self.ShoradLink = false
self.ShoradTime = 600
self.ShoradActDistance = 15000
-- TODO: add emissions on/off when available .... in 2 weeks
self.TimeStamp = timer.getAbsTime()
self.relointerval = math.random(1800,3600) -- random between 30 and 60 mins
self.state2flag = false
if EmOnOff then
if EmOnOff == false then
self.UseEmOnOff = false
@ -279,7 +292,7 @@ do
end
-- Inherit everything from BASE class.
local self = BASE:Inherit(self, BASE:New()) -- #MANTIS
local self = BASE:Inherit(self, FSM:New()) -- #MANTIS
-- Set the string id for output to DCS.log file.
self.lid=string.format("MANTIS %s | ", self.name)
@ -310,9 +323,102 @@ do
end
-- @field #string version
self.version="0.4.2"
self.version="0.5.1"
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
--- FSM Functions ---
-- Start State.
self:SetStartState("Stopped")
-- Add FSM transitions.
-- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
self:AddTransition("*", "Status", "*") -- MANTIS status update.
self:AddTransition("*", "Relocating", "*") -- MANTIS HQ and EWR are relocating.
self:AddTransition("*", "GreenState", "*") -- MANTIS A SAM switching to GREEN state.
self:AddTransition("*", "RedState", "*") -- MANTIS A SAM switching to RED state.
self:AddTransition("*", "AdvStateChange", "*") -- MANTIS advanced mode state change.
self:AddTransition("*", "ShoradActivated", "*") -- MANTIS woke up a connected SHORAD.
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
------------------------
--- Pseudo Functions ---
------------------------
--- Triggers the FSM event "Start". Starts the MANTIS. Initializes parameters and starts event handlers.
-- @function [parent=#MANTIS] Start
-- @param #MANTIS self
--- Triggers the FSM event "Start" after a delay. Starts the MANTIS. Initializes parameters and starts event handlers.
-- @function [parent=#MANTIS] __Start
-- @param #MANTIS self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "Stop". Stops the MANTIS and all its event handlers.
-- @param #MANTIS self
--- Triggers the FSM event "Stop" after a delay. Stops the MANTIS and all its event handlers.
-- @function [parent=#MANTIS] __Stop
-- @param #MANTIS self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "Status".
-- @function [parent=#MANTIS] Status
-- @param #MANTIS self
--- Triggers the FSM event "Status" after a delay.
-- @function [parent=#MANTIS] __Status
-- @param #MANTIS self
-- @param #number delay Delay in seconds.
--- On After "Relocating" event. HQ and/or EWR moved.
-- @function [parent=#MANTIS] OnAfterRelocating
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @return #MANTIS self
--- On After "GreenState" event. A SAM group was switched to GREEN alert.
-- @function [parent=#MANTIS] OnAfterGreenState
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @param Wrapper.Group#GROUP Group The GROUP object whose state was changed
-- @return #MANTIS self
--- On After "RedState" event. A SAM group was switched to RED alert.
-- @function [parent=#MANTIS] OnAfterRedState
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @param Wrapper.Group#GROUP Group The GROUP object whose state was changed
-- @return #MANTIS self
--- On After "AdvStateChange" event. Advanced state changed, influencing detection speed.
-- @function [parent=#MANTIS] OnAfterAdvStateChange
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @param #number Oldstate Old state - 0 = green, 1 = amber, 2 = red
-- @param #number Newstate New state - 0 = green, 1 = amber, 2 = red
-- @param #number Interval Calculated detection interval based on state and advanced feature setting
-- @return #MANTIS self
--- On After "ShoradActivated" event. Mantis has activated a SHORAD.
-- @function [parent=#MANTIS] OnAfterShoradActivated
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @param #string Name Name of the GROUP which SHORAD shall protect
-- @param #number Radius Radius around the named group to find SHORAD groups
-- @param #number Ontime Seconds the SHORAD will stay active
return self
end
@ -320,17 +426,19 @@ do
-- MANTIS helper functions
-----------------------------------------------------------------------
--- [internal] Function to get the self.SAM_Table
--- [Internal] Function to get the self.SAM_Table
-- @param #MANTIS self
-- @return #table table
function MANTIS:_GetSAMTable()
self:T(self.lid .. "GetSAMTable")
return self.SAM_Table
end
--- [internal] Function to set the self.SAM_Table
--- [Internal] Function to set the self.SAM_Table
-- @param #MANTIS self
-- @return #MANTIS self
function MANTIS:_SetSAMTable(table)
self:T(self.lid .. "SetSAMTable")
self.SAM_Table = table
return self
end
@ -339,41 +447,50 @@ do
-- @param #MANTIS self
-- @param #number radius Radius upon which detected objects will be grouped
function MANTIS:SetEWRGrouping(radius)
self:T(self.lid .. "SetEWRGrouping")
local radius = radius or 5000
self.grouping = radius
return self
end
--- Function to set the detection radius of the EWR in meters
-- @param #MANTIS self
-- @param #number radius Radius of the EWR detection zone
function MANTIS:SetEWRRange(radius)
self:T(self.lid .. "SetEWRRange")
local radius = radius or 80000
self.acceptrange = radius
return self
end
--- Function to set switch-on/off zone for the SAM sites in meters
-- @param #MANTIS self
-- @param #number radius Radius of the firing zone
function MANTIS:SetSAMRadius(radius)
self:T(self.lid .. "SetSAMRadius")
local radius = radius or 25000
self.checkradius = radius
return self
end
--- Function to set SAM firing engage range, 0-100 percent, e.g. 75
-- @param #MANTIS self
-- @param #number range Percent of the max fire range
function MANTIS:SetSAMRange(range)
self:T(self.lid .. "SetSAMRange")
local range = range or 75
if range < 0 or range > 100 then
range = 75
end
self.engagerange = range
return self
end
--- Function to set a new SAM firing engage range, use this method to adjust range while running MANTIS, e.g. for different setups day and night
-- @param #MANTIS self
-- @param #number range Percent of the max fire range
function MANTIS:SetNewSAMRangeWhileRunning(range)
self:T(self.lid .. "SetNewSAMRangeWhileRunning")
local range = range or 75
if range < 0 or range > 100 then
range = 75
@ -381,20 +498,32 @@ do
self.engagerange = range
self:_RefreshSAMTable()
self.mysead.EngagementRange = range
return self
end
--- Function to set switch-on/off the debug state
-- @param #MANTIS self
-- @param #boolean onoff Set true to switch on
function MANTIS:Debug(onoff)
self:T(self.lid .. "SetDebug")
local onoff = onoff or false
self.debug = onoff
if onoff then
-- Debug trace.
BASE:TraceOn()
BASE:TraceClass("MANTIS")
BASE:TraceLevel(1)
else
BASE:TraceOff()
end
return self
end
--- Function to get the HQ object for further use
-- @param #MANTIS self
-- @return Wrapper.GROUP#GROUP The HQ #GROUP object or *nil* if it doesn't exist
function MANTIS:GetCommandCenter()
self:T(self.lid .. "GetCommandCenter")
if self.HQ_CC then
return self.HQ_CC
else
@ -406,26 +535,31 @@ do
-- @param #MANTIS self
-- @param #string prefix Name of the AWACS group in the mission editor
function MANTIS:SetAwacs(prefix)
self:T(self.lid .. "SetAwacs")
if prefix ~= nil then
if type(prefix) == "string" then
self.AWACS_Prefix = prefix
self.advAwacs = true
end
end
return self
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)
self:T(self.lid .. "SetAwacsRange")
local range = range or 250000
self.awacsrange = range
return self
end
--- Function to set the HQ object for further use
-- @param #MANTIS self
-- @param Wrapper.GROUP#GROUP group The #GROUP object to be set as HQ
function MANTIS:SetCommandCenter(group)
self:T(self.lid .. "SetCommandCenter")
local group = group or nil
if group ~= nil then
if type(group) == "string" then
@ -436,14 +570,17 @@ do
self.HQ_Template_CC = group:GetName()
end
end
return self
end
--- Function to set the detection interval
-- @param #MANTIS self
-- @param #number interval The interval in seconds
function MANTIS:SetDetectInterval(interval)
self:T(self.lid .. "SetDetectInterval")
local interval = interval or 30
self.detectinterval = interval
return self
end
--- Function to set Advanded Mode
@ -453,7 +590,8 @@ do
-- @usage Advanced mode will *decrease* reactivity of MANTIS, if HQ and/or EWR network dies. Set SAMs to RED state if both are dead. Requires usage of an **HQ** object and the **dynamic** option.
-- E.g. `mymantis:SetAdvancedMode(true, 90)`
function MANTIS:SetAdvancedMode(onoff, ratio)
self:F({onoff, ratio})
self:T(self.lid .. "SetAdvancedMode")
self:T({onoff, ratio})
local onoff = onoff or false
local ratio = ratio or 100
if (type(self.HQ_Template_CC) == "string") and onoff and self.dynamic then
@ -461,53 +599,58 @@ do
self.advanced = true
self.adv_state = 0
self.Adv_EWR_Group = SET_GROUP:New():FilterPrefixes(self.EWR_Templates_Prefix):FilterCoalitions(self.Coalition):FilterStart()
env.info(string.format("***** Starting Advanced Mode MANTIS Version %s *****", self.version))
self:I(string.format("***** Starting Advanced Mode MANTIS Version %s *****", self.version))
else
local text = self.lid.." Advanced Mode requires a HQ and dynamic to be set. Revisit your MANTIS:New() statement to add both."
local m= MESSAGE:New(text,10,"MANTIS",true):ToAll()
BASE:E(text)
self:E(text)
end
return self
end
--- Set using Emissions on/off instead of changing alarm state
-- @param #MANTIS self
-- @param #boolean switch Decide if we are changing alarm state or Emission state
function MANTIS:SetUsingEmOnOff(switch)
self:T(self.lid .. "SetUsingEmOnOff")
self.UseEmOnOff = switch or false
return self
end
--- [Internal] Function to check if HQ is alive
-- @param #MANTIS self
-- @return #boolean True if HQ is alive, else false
function MANTIS:_CheckHQState()
self:T(self.lid .. "CheckHQState")
local text = self.lid.." Checking HQ State"
self:T(text)
local m= MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
if self.verbose then env.info(text) end
if self.verbose then self:I(text) end
-- start check
if self.advanced then
local hq = self.HQ_Template_CC
local hqgrp = GROUP:FindByName(hq)
if hqgrp then
if hqgrp:IsAlive() then -- ok we're on, hq exists and as alive
env.info(self.lid.." HQ is alive!")
self:T(self.lid.." HQ is alive!")
return true
else
env.info(self.lid.." HQ is dead!")
self:T(self.lid.." HQ is dead!")
return false
end
end
end
return self
end
--- [Internal] Function to check if EWR is (at least partially) alive
-- @param #MANTIS self
-- @return #boolean True if EWR is alive, else false
function MANTIS:_CheckEWRState()
self:T(self.lid .. "CheckEWRState")
local text = self.lid.." Checking EWR State"
self:F(text)
self:T(text)
local m= MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
if self.verbose then env.info(text) end
if self.verbose then self:I(text) end
-- start check
if self.advanced then
local EWR_Group = self.Adv_EWR_Group
@ -521,24 +664,26 @@ do
end
end
end
env.info(self.lid..string.format(" No of EWR alive is %d", nalive))
self:T(self.lid..string.format(" No of EWR alive is %d", nalive))
if nalive > 0 then
return true
else
return false
end
end
return self
end
--- [Internal] Function to determine state of the advanced mode
-- @param #MANTIS self
-- @return #number Newly calculated interval
-- @return #number Previous state for tracking 0, 1, or 2
function MANTIS:_CheckAdvState()
local text = self.lid.." Checking Advanced State"
self:F(text)
function MANTIS:_CalcAdvState()
self:T(self.lid .. "CalcAdvState")
local text = self.lid.." Calculating Advanced State"
self:T(text)
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
if self.verbose then env.info(text) end
if self.verbose then self:I(text) end
-- start check
local currstate = self.adv_state -- save curr state for comparison later
local EWR_State = self:_CheckEWRState()
@ -557,9 +702,9 @@ do
ratio = ratio * self.adv_state -- e.g 0.8*2 = 1.6
local newinterval = interval + (interval * ratio) -- e.g. 30+(30*1.6) = 78
local text = self.lid..string.format(" Calculated OldState/NewState/Interval: %d / %d / %d", currstate, self.adv_state, newinterval)
self:F(text)
self:T(text)
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
if self.verbose then env.info(text) end
if self.verbose then self:I(text) end
return newinterval, currstate
end
@ -568,7 +713,8 @@ do
-- @param #boolean hq If true, will relocate HQ object
-- @param #boolean ewr If true, will relocate EWR objects
function MANTIS:SetAutoRelocate(hq, ewr)
self:F({hq, ewr})
self:T(self.lid .. "SetAutoRelocate")
self:T({hq, ewr})
local hqrel = hq or false
local ewrel = ewr or false
if hqrel or ewrel then
@ -576,22 +722,24 @@ do
self.autorelocateunits = { HQ = hqrel, EWR = ewrel }
self:T({self.autorelocate, self.autorelocateunits})
end
return self
end
--- [Internal] Function to execute the relocation
-- @param #MANTIS self
function MANTIS:_RelocateGroups()
self:T(self.lid.." Relocating Groups")
self:T(self.lid .. "RelocateGroups")
local text = self.lid.." Relocating Groups"
local m= MESSAGE:New(text,10,"MANTIS",true):ToAllIf(self.debug)
if self.verbose then env.info(text) end
if self.verbose then self:I(text) end
if self.autorelocate then
-- relocate HQ
if self.autorelocateunits.HQ and self.HQ_CC then --only relocate if HQ exists
local HQGroup = self.HQ_CC
if self.autorelocateunits.HQ and self.HQ_CC and HQGroup:IsAlive() then --only relocate if HQ exists
local _hqgrp = self.HQ_CC
self:T(self.lid.." Relocating HQ")
local text = self.lid.." Relocating HQ"
local m= MESSAGE:New(text,10,"MANTIS"):ToAll()
--local m= MESSAGE:New(text,10,"MANTIS"):ToAll()
_hqgrp:RelocateGroundRandomInRadius(20,500,true,true)
end
--relocate EWR
@ -601,26 +749,27 @@ do
local EWR_GRP = SET_GROUP:New():FilterPrefixes(self.EWR_Templates_Prefix):FilterCoalitions(self.Coalition):FilterOnce()
local EWR_Grps = EWR_GRP.Set --table of objects in SET_GROUP
for _,_grp in pairs (EWR_Grps) do
if _grp:IsGround() then
if _grp:IsAlive() and _grp:IsGround() then
self:T(self.lid.." Relocating EWR ".._grp:GetName())
local text = self.lid.." Relocating EWR ".._grp:GetName()
local m= MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
if self.verbose then env.info(text) end
if self.verbose then self:I(text) end
_grp:RelocateGroundRandomInRadius(20,500,true,true)
end
end
end
end
return self
end
--- (Internal) Function to check if any object is in the given SAM zone
--- [Internal] Function to check if any object is in the given SAM zone
-- @param #MANTIS self
-- @param #table dectset Table of coordinates of detected items
-- @param samcoordinate Core.Point#COORDINATE Coordinate object.
-- @param Core.Point#COORDINATE samcoordinate 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")
self:T(self.lid.."CheckObjectInZone")
-- check if non of the coordinate is in the given defense zone
local radius = self.checkradius
local set = dectset
@ -632,7 +781,7 @@ do
local targetdistance = samcoordinate:DistanceFromPointVec2(coord)
local text = string.format("Checking SAM at % s - Distance %d m - Target %s", samstring, targetdistance, dectstring)
local m = MESSAGE:New(text,10,"Check"):ToAllIf(self.debug)
if self.verbose then env.info(self.lid..text) end
if self.verbose then self:I(self.lid..text) end
-- end output to cross-check
if targetdistance <= radius then
return true, targetdistance
@ -641,11 +790,11 @@ do
return false, 0
end
--- (Internal) Function to start the detection via EWR groups
--- [Internal] Function to start the detection via EWR groups
-- @param #MANTIS self
-- @return Functional.Detection #DETECTION_AREAS The running detection set
function MANTIS:StartDetection()
self:F(self.lid.."Starting Detection")
self:T(self.lid.."Starting Detection")
-- start detection
local groupset = self.EWR_Group
@ -653,14 +802,14 @@ do
local acceptrange = self.acceptrange or 80000
local interval = self.detectinterval or 60
--@param Functional.Detection #DETECTION_AREAS _MANTISdetection [internal] The MANTIS detection object
_MANTISdetection = DETECTION_AREAS:New( groupset, grouping ) --[internal] Grouping detected objects to 5000m zones
_MANTISdetection:FilterCategories({ Unit.Category.AIRPLANE, Unit.Category.HELICOPTER })
_MANTISdetection:SetAcceptRange(acceptrange)
_MANTISdetection:SetRefreshTimeInterval(interval)
_MANTISdetection:Start()
--@param Functional.Detection #DETECTION_AREAS _MANTISdetection [Internal] The MANTIS detection object
local MANTISdetection = DETECTION_AREAS:New( groupset, grouping ) --[Internal] Grouping detected objects to 5000m zones
MANTISdetection:FilterCategories({ Unit.Category.AIRPLANE, Unit.Category.HELICOPTER })
MANTISdetection:SetAcceptRange(acceptrange)
MANTISdetection:SetRefreshTimeInterval(interval)
MANTISdetection:Start()
function _MANTISdetection:OnAfterDetectedItem(From,Event,To,DetectedItem)
function MANTISdetection:OnAfterDetectedItem(From,Event,To,DetectedItem)
--BASE:I( { From, Event, To, DetectedItem })
local debug = false
if DetectedItem.IsDetected and debug then
@ -669,14 +818,14 @@ do
local m = MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
end
end
return _MANTISdetection
return MANTISdetection
end
--- (Internal) Function to start the detection via AWACS if defined as separate
--- [Internal] Function to start the detection via AWACS if defined as separate
-- @param #MANTIS self
-- @return Functional.Detection #DETECTION_AREAS The running detection set
function MANTIS:StartAwacsDetection()
self:F(self.lid.."Starting Awacs Detection")
self:T(self.lid.."Starting Awacs Detection")
-- start detection
local group = self.AWACS_Prefix
@ -685,14 +834,14 @@ do
--local acceptrange = self.acceptrange or 80000
local interval = self.detectinterval or 60
--@param Functional.Detection #DETECTION_AREAS _MANTISdetection [internal] The MANTIS detection object
_MANTISAwacs = DETECTION_AREAS:New( groupset, grouping ) --[internal] Grouping detected objects to 5000m zones
_MANTISAwacs:FilterCategories({ Unit.Category.AIRPLANE, Unit.Category.HELICOPTER })
_MANTISAwacs:SetAcceptRange(self.awacsrange) --250km
_MANTISAwacs:SetRefreshTimeInterval(interval)
_MANTISAwacs:Start()
--@param Functional.Detection #DETECTION_AREAS _MANTISdetection [Internal] The MANTIS detection object
local MANTISAwacs = DETECTION_AREAS:New( groupset, grouping ) --[Internal] Grouping detected objects to 5000m zones
MANTISAwacs:FilterCategories({ Unit.Category.AIRPLANE, Unit.Category.HELICOPTER })
MANTISAwacs:SetAcceptRange(self.awacsrange) --250km
MANTISAwacs:SetRefreshTimeInterval(interval)
MANTISAwacs:Start()
function _MANTISAwacs:OnAfterDetectedItem(From,Event,To,DetectedItem)
function MANTISAwacs:OnAfterDetectedItem(From,Event,To,DetectedItem)
--BASE:I( { From, Event, To, DetectedItem })
local debug = false
if DetectedItem.IsDetected and debug then
@ -701,15 +850,15 @@ do
local m = MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
end
end
return _MANTISAwacs
return MANTISAwacs
end
--- (Internal) Function to set the SAM start state
--- [Internal] Function to set the SAM start state
-- @param #MANTIS self
-- @return #MANTIS self
function MANTIS:SetSAMStartState()
-- 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:T(self.lid.."Setting SAM Start States")
-- get SAM Group
local SAM_SET = self.SAM_Group
local SAM_Grps = SAM_SET.Set --table of objects
@ -742,11 +891,11 @@ do
return self
end
--- (Internal) Function to update SAM table and SEAD state
--- [Internal] Function to update SAM table and SEAD state
-- @param #MANTIS self
-- @return #MANTIS self
function MANTIS:_RefreshSAMTable()
self:F(self.lid.."Setting SAM Start States")
self:T(self.lid.."RefreshSAMTable")
-- Requires SEAD 0.2.2 or better
-- get SAM Group
local SAM_SET = self.SAM_Group
@ -779,6 +928,7 @@ do
-- @param Functional.Shorad#SHORAD Shorad The #SHORAD object
-- @param #number Shoradtime Number of seconds #SHORAD stays active post wake-up
function MANTIS:AddShorad(Shorad,Shoradtime)
self:T(self.lid.."AddShorad")
local Shorad = Shorad or nil
local ShoradTime = Shoradtime or 600
local ShoradLink = true
@ -787,33 +937,30 @@ do
self.Shorad = Shorad --#SHORAD
self.ShoradTime = Shoradtime -- #number
end
return self
end
--- Function to unlink #MANTIS from a #SHORAD installation
-- @param #MANTIS self
function MANTIS:RemoveShorad()
self:T(self.lid.."RemoveShorad")
self.ShoradLink = false
return self
end
-----------------------------------------------------------------------
-- MANTIS main functions
-----------------------------------------------------------------------
--- Function to set the SAM start state
--- [Internal] Check detection function
-- @param #MANTIS self
-- @param Functional.Detection#DETECTION_AREAS detection Detection object
-- @return #MANTIS self
function MANTIS:Start()
self:F(self.lid.."Starting MANTIS")
self:SetSAMStartState()
self.Detection = self:StartDetection()
if self.advAwacs then
self.AWACS_Detection = self:StartAwacsDetection()
end
-- detection function
local function check(detection)
function MANTIS:_Check(detection)
self:T(self.lid .. "Check")
--get detected set
local detset = detection:GetDetectedItemCoordinates()
self:F("Check:", {detset})
self:T("Check:", {detset})
-- randomly update SAM Table
local rand = math.random(1,100)
if rand > 65 then -- 1/3 of cases
@ -835,6 +982,7 @@ do
samgroup:EnableEmission(true)
end
samgroup:OptionAlarmStateRed()
self:__RedState(1,samgroup)
-- link in to SHORAD if available
-- DONE: Test integration fully
if self.ShoradLink and Distance < self.ShoradActDistance then -- don't give SHORAD position away too early
@ -842,11 +990,12 @@ do
local radius = self.checkradius
local ontime = self.ShoradTime
Shorad:WakeUpShorad(name, radius, ontime)
self:__ShoradActivated(1,name, radius, ontime)
end
-- debug output
local text = string.format("SAM %s switched to alarm state RED!", name)
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
if self.verbose then env.info(self.lid..text) end
if self.verbose then self:I(self.lid..text) end
end --end alive
else
if samgroup:IsAlive() then
@ -854,39 +1003,45 @@ do
if self.UseEmOnOff then
-- TODO: add emissions on/off
samgroup:EnableEmission(false)
self:__GreenState(1,samgroup)
--samgroup:SetAIOff()
else
samgroup:OptionAlarmStateGreen()
self:__GreenState(1,samgroup)
end
--samgroup:OptionROEWeaponFree()
--samgroup:SetAIOn()
local text = string.format("SAM %s switched to alarm state GREEN!", name)
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
if self.verbose then env.info(self.lid..text) end
if self.verbose then self:I(self.lid..text) end
end --end alive
end --end check
end --for for loop
end --end function
-- relocation relay function
local function relocate()
self:_RelocateGroups()
return self
end
-- check advanced state
local function checkadvstate()
local interval, oldstate = self:_CheckAdvState()
--- [Internal] Relocation relay function
-- @param #MANTIS self
-- @return #MANTIS self
function MANTIS:_Relocate()
self:T(self.lid .. "Relocate")
self:_RelocateGroups()
return self
end
--- [Internal] Check advanced state
-- @param #MANTIS self
-- @return #MANTIS self
function MANTIS:_CheckAdvState()
self:T(self.lid .. "CheckAdvSate")
local interval, oldstate = self:_CalcAdvState()
local newstate = self.adv_state
if newstate ~= oldstate then
-- deal with new state
self:__AdvStateChange(1,oldstate,newstate,interval)
if newstate == 2 then
-- switch alarm state RED
if self.MantisTimer.isrunning then
self.MantisTimer:Stop()
self.MantisTimer.isrunning = false
end -- stop Awacs timer
if self.MantisATimer.isrunning then
self.MantisATimer:Stop()
self.MantisATimer.isrunning = false
end -- stop timer
self.state2flag = true
local samset = self:_GetSAMTable() -- table of i.1=names, i.2=coordinates
for _,_data in pairs (samset) do
local name = _data[1]
@ -902,69 +1057,159 @@ do
end -- end for loop
elseif newstate <= 1 then
-- change MantisTimer to slow down or speed up
if self.MantisTimer.isrunning then
self.MantisTimer:Stop()
self.MantisTimer.isrunning = false
end
if self.MantisATimer.isrunning then
self.MantisATimer:Stop()
self.MantisATimer.isrunning = false
end
self.MantisTimer = TIMER:New(check,self.Detection)
self.MantisTimer:Start(5,interval,nil)
self.MantisTimer.isrunning = true
if self.advAwacs then
self.MantisATimer = TIMER:New(check,self.AWACS_Detection)
self.MantisATimer:Start(15,interval,nil)
self.MantisATimer.isrunning = true
end
self.detectinterval = interval
self.state2flag = false
end
end -- end newstate vs oldstate
return self
end
-- timers to run the system
local interval = self.detectinterval
self.MantisTimer = TIMER:New(check,self.Detection)
self.MantisTimer:Start(5,interval,nil)
self.MantisTimer.isrunning = true
-- Awacs timer
--- [Internal] Function to set start state
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @return #MANTIS self
function MANTIS:onafterStart(From, Event, To)
self:T({From, Event, To})
self:T(self.lid.."Starting MANTIS")
self:SetSAMStartState()
self.Detection = self:StartDetection()
if self.advAwacs then
self.MantisATimer = TIMER:New(check,self.AWACS_Detection)
self.MantisATimer:Start(15,interval,nil)
self.MantisATimer.isrunning = true
self.AWACS_Detection = self:StartAwacsDetection()
end
-- timer to relocate HQ and EWR
self:__Status(self.detectinterval)
return self
end
--- [Internal] Before status function for MANTIS
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @return #MANTIS self
function MANTIS:onbeforeStatus(From, Event, To)
self:T({From, Event, To})
-- check detection
if not self.state2flag then
self:_Check(self.Detection)
end
-- check Awacs
if self.advAwacs and not self.state2flag then
self:_Check(self.AWACS_Detection)
end
-- relocate HQ and EWR
if self.autorelocate then
local relointerval = math.random(1800,3600) -- random between 30 and 60 mins
self.MantisReloTimer = TIMER:New(relocate)
self.MantisReloTimer:Start(relointerval,relointerval,nil)
local relointerval = self.relointerval
local thistime = timer.getAbsTime()
local timepassed = thistime - self.TimeStamp
local halfintv = math.floor(timepassed / relointerval)
--self:T({timepassed=timepassed, halfintv=halfintv})
if halfintv >= 1 then
self.TimeStamp = timer.getAbsTime()
self:_Relocate()
self:__Relocating(1)
end
end
-- timer for advanced state check
if self.advanced then
self.MantisAdvTimer = TIMER:New(checkadvstate)
self.MantisAdvTimer:Start(30,interval*5,nil)
self:_CheckAdvState()
end
return self
end
--- Function to stop MANTIS
--- [Internal] Status function for MANTIS
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @return #MANTIS self
function MANTIS:Stop()
if self.MantisTimer.isrunning then
self.MantisTimer:Stop()
end
if self.MantisATimer.isrunning then
self.MantisATimer:Stop()
end
if self.autorelocate then
self.MantisReloTimer:Stop()
end
if self.advanced then
self.MantisAdvTimer:Stop()
end
function MANTIS:onafterStatus(From,Event,To)
self:T({From, Event, To})
local interval = self.detectinterval * -1
self:__Status(interval)
return self
end
--- [Internal] Function to stop MANTIS
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @return #MANTIS self
function MANTIS:onafterStop(From, Event, To)
self:T({From, Event, To})
return self
end
--- [Internal] Function triggered by Event Relocating
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @return #MANTIS self
function MANTIS:onafterRelocating(From, Event, To)
self:T({From, Event, To})
return self
end
--- [Internal] Function triggered by Event GreenState
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @param Wrapper.Group#GROUP Group The GROUP object whose state was changed
-- @return #MANTIS self
function MANTIS:onafterGreenState(From, Event, To, Group)
self:T({From, Event, To, Group})
return self
end
--- [Internal] Function triggered by Event RedState
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @param Wrapper.Group#GROUP Group The GROUP object whose state was changed
-- @return #MANTIS self
function MANTIS:onafterRedState(From, Event, To, Group)
self:T({From, Event, To, Group})
return self
end
--- [Internal] Function triggered by Event AdvStateChange
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @param #number Oldstate Old state - 0 = green, 1 = amber, 2 = red
-- @param #number Newstate New state - 0 = green, 1 = amber, 2 = red
-- @param #number Interval Calculated detection interval based on state and advanced feature setting
-- @return #MANTIS self
function MANTIS:onafterAdvStateChange(From, Event, To, Oldstate, Newstate, Interval)
self:T({From, Event, To, Oldstate, Newstate, Interval})
return self
end
--- [Internal] Function triggered by Event ShoradActivated
-- @param #MANTIS self
-- @param #string From The From State
-- @param #string Event The Event
-- @param #string To The To State
-- @param #string Name Name of the GROUP which SHORAD shall protect
-- @param #number Radius Radius around the named group to find SHORAD groups
-- @param #number Ontime Seconds the SHORAD will stay active
function MANTIS:onafterShoradActivated(From, Event, To, Name, Radius, Ontime)
self:T({From, Event, To, Name, Radius, Ontime})
return self
end
end
-----------------------------------------------------------------------
-- MANTIS end

View File

@ -662,7 +662,9 @@ end
-- @param #string _description (optional) Description.
-- @param #boolean _randomPoint (optional) Random yes or no.
-- @param #boolean _nomessage (optional) If true, don\'t send a message to SAR.
function CSAR:_SpawnCsarAtZone( _zone, _coalition, _description, _randomPoint, _nomessage)
-- @param #string unitname (optional) Name of the lost unit.
-- @param #string typename (optional) Type of plane.
function CSAR:_SpawnCsarAtZone( _zone, _coalition, _description, _randomPoint, _nomessage, unitname, typename)
self:T(self.lid .. " _SpawnCsarAtZone")
local freq = self:_GenerateADFFrequency()
local _triggerZone = ZONE:New(_zone) -- trigger to use as reference position
@ -671,7 +673,9 @@ function CSAR:_SpawnCsarAtZone( _zone, _coalition, _description, _randomPoint, _
return
end
local _description = _description or "Unknown"
local _description = _description or "PoW"
local unitname = unitname or "Old Rusty"
local typename = typename or "Phantom II"
local pos = {}
if _randomPoint then
@ -690,7 +694,7 @@ function CSAR:_SpawnCsarAtZone( _zone, _coalition, _description, _randomPoint, _
_country = country.id.UN_PEACEKEEPERS
end
self:_AddCsar(_coalition, _country, pos, "PoW", _description, nil, freq, _nomessage, _description)
self:_AddCsar(_coalition, _country, pos, typename, unitname, _description, freq, _nomessage, _description)
return self
end
@ -702,12 +706,14 @@ end
-- @param #string Description (optional) Description.
-- @param #boolean RandomPoint (optional) Random yes or no.
-- @param #boolean Nomessage (optional) If true, don\'t send a message to SAR.
-- @param #string unitname (optional) Name of the lost unit.
-- @param #string typename (optional) Type of plane.
-- @usage If missions designers want to spawn downed pilots into the field, e.g. at mission begin, to give the helicopter guys works, they can do this like so:
--
-- -- Create downed "Pilot Wagner" in #ZONE "CSAR_Start_1" at a random point for the blue coalition
-- my_csar:SpawnCSARAtZone( "CSAR_Start_1", coalition.side.BLUE, "Pilot Wagner", true )
function CSAR:SpawnCSARAtZone(Zone, Coalition, Description, RandomPoint, Nomessage)
self:_SpawnCsarAtZone(Zone, Coalition, Description, RandomPoint, Nomessage)
-- my_csar:SpawnCSARAtZone( "CSAR_Start_1", coalition.side.BLUE, "Wagner", true, false, "Charly-1-1", "F5E" )
function CSAR:SpawnCSARAtZone(Zone, Coalition, Description, RandomPoint, Nomessage, Unitname, Typename)
self:_SpawnCsarAtZone(Zone, Coalition, Description, RandomPoint, Nomessage, Unitname, Typename)
return self
end
@ -1199,7 +1205,7 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
end
if _time <= 0 or _distance < self.loadDistance then
if self.pilotmustopendoors and not self:_IsLoadingDoorOpen(_heliName) then
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in, bugger!", self.messageTime, true)
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true)
return true
else
self.landedStatus[_lookupKeyHeli] = nil
@ -1211,7 +1217,7 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
else
if (_distance < self.loadDistance) then
if self.pilotmustopendoors and not self:_IsLoadingDoorOpen(_heliName) then
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in, honk!", self.messageTime, true)
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true)
return true
else
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
@ -1252,7 +1258,7 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
self:_DisplayMessageToSAR(_heliUnit, "Hovering above " .. _pilotName .. ". \n\nHold hover for " .. _time .. " seconds to winch them up. \n\nIf the countdown stops you\'re too far away!", self.messageTime, true)
else
if self.pilotmustopendoors and not self:_IsLoadingDoorOpen(_heliName) then
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in, noob!", self.messageTime, true)
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true)
return true
else
self.hoverStatus[_lookupKeyHeli] = nil

View File

@ -410,6 +410,7 @@ do
-- my_ctld.enableHercules = true
-- my_ctld.HercMinAngels = 155 -- for troop/cargo drop via chute in meters, ca 470 ft
-- my_ctld.HercMaxAngels = 2000 -- for troop/cargo drop via chute in meters, ca 6000 ft
-- my_ctld.HercMaxSpeed = 77 -- 77mps or 270 kph or 150 kn
--
-- Also, the following options need to be set to `true`:
--
@ -478,7 +479,7 @@ CTLD = {
-- @field #table vhfbeacon Beacon info as #CTLD.ZoneBeacon
--- Zone Type Info.
-- @type CTLD.
-- @type CTLD.CargoZoneType
CTLD.CargoZoneType = {
LOAD = "load",
DROP = "drop",
@ -651,6 +652,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
self.enableHercules = false
self.HercMinAngels = 165 -- for troop/cargo drop via chute
self.HercMaxAngels = 2000 -- for troop/cargo drop via chute
self.HercMaxSpeed = 77 -- 280 kph or 150kn eq 77 mps
-- message suppression
self.suppressmessages = false
@ -2283,10 +2285,12 @@ end
local aheight = uheight - gheight -- height above ground
local maxh = self.HercMinAngels-- 1500m
local minh = self.HercMaxAngels -- 5000m
local mspeed = 2 -- 2 m/s
-- TODO:Add speed test for Herc, should not be above 280kph/150kn
--self:Tstring.format("%s Unit parameters: at %dm AGL with %dmps",self.lid,aheight,uspeed))
if (aheight <= maxh) and (aheight >= minh) then
local maxspeed = self.HercMaxSpeed -- 77 mps
-- TODO: TEST - Speed test for Herc, should not be above 280kph/150kn
local kmspeed = uspeed * 3.6
local knspeed = kmspeed / 1.86
self:T(string.format("%s Unit parameters: at %dm AGL with %dmps | %dkph | %dkn",self.lid,aheight,uspeed,kmspeed,knspeed))
if (aheight <= maxh) and (aheight >= minh) and (uspeed <= maxspeed) then
-- yep within parameters
outcome = true
end
@ -2302,7 +2306,14 @@ end
local inhover = self:IsCorrectHover(Unit)
local htxt = "true"
if not inhover then htxt = "false" end
local text = string.format("Hover parameters (autoload/drop):\n - Min height %dm \n - Max height %dm \n - Max speed 2mps \n - In parameter: %s", self.minimumHoverHeight, self.maximumHoverHeight, htxt)
local text = ""
if _SETTINGS:IsMetric() then
text = string.format("Hover parameters (autoload/drop):\n - Min height %dm \n - Max height %dm \n - Max speed 2mps \n - In parameter: %s", self.minimumHoverHeight, self.maximumHoverHeight, htxt)
else
local minheight = UTILS.MetersToFeet(self.minimumHoverHeight)
local maxheight = UTILS.MetersToFeet(self.maximumHoverHeight)
text = string.format("Hover parameters (autoload/drop):\n - Min height %dm \n - Max height %dm \n - Max speed 6fts \n - In parameter: %s", minheight, maxheight, htxt)
end
self:_SendMessage(text, 10, false, Group)
--local m = MESSAGE:New(text,10,"CTLD",false):ToGroup(Group)
return self
@ -2316,9 +2327,16 @@ end
local inhover = self:IsCorrectFlightParameters(Unit)
local htxt = "true"
if not inhover then htxt = "false" end
local text = ""
if _SETTINGS:IsImperial() then
local minheight = UTILS.MetersToFeet(self.HercMinAngels)
local maxheight = UTILS.MetersToFeet(self.HercMaxAngels)
local text = string.format("Flight parameters (airdrop):\n - Min height %dft \n - Max height %dft \n - In parameter: %s", minheight, maxheight, htxt)
text = string.format("Flight parameters (airdrop):\n - Min height %dft \n - Max height %dft \n - In parameter: %s", minheight, maxheight, htxt)
else
local minheight = self.HercMinAngels
local maxheight = self.HercMaxAngels
text = string.format("Flight parameters (airdrop):\n - Min height %dm \n - Max height %dm \n - In parameter: %s", minheight, maxheight, htxt)
end
self:_SendMessage(text, 10, false, Group)
--local m = MESSAGE:New(text,15,"CTLD",false):ToGroup(Group)
return self