mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Improve the consistency of the module intros to the most commonly used version (single dash). Add missing module information (abbreviated where none existed previously). Fix broken documentation links Make module names correspond to filenames (and fix links). Fix typos.
1475 lines
57 KiB
Lua
1475 lines
57 KiB
Lua
--- **Functional** - Management of target **Designation**. Lase, smoke and illuminate targets.
|
|
--
|
|
-- ===
|
|
--
|
|
-- ## Features:
|
|
--
|
|
-- * Faciliate the communication of detected targets to players.
|
|
-- * Designate targets using lasers, through a menu system.
|
|
-- * Designate targets using smoking, through a menu system.
|
|
-- * Designate targets using illumination, through a menu system.
|
|
-- * Auto lase targets.
|
|
-- * Refresh detection upon specified time intervals.
|
|
-- * Prioritization on threat levels.
|
|
-- * Reporting system of threats.
|
|
--
|
|
-- ===
|
|
--
|
|
-- ## Missions:
|
|
--
|
|
-- [DES - Designation](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/DES%20-%20Designation)
|
|
--
|
|
-- ===
|
|
--
|
|
-- Targets detected by recce will be communicated to a group of attacking players.
|
|
-- A menu system is made available that allows to:
|
|
--
|
|
-- * **Lased** for a period of time.
|
|
-- * **Smoked**. Artillery or airplanes with Illuminatino ordonance need to be present. (WIP, but early demo ready.)
|
|
-- * **Illuminated** through an illumination bomb. Artillery or airplanes with Illuminatino ordonance need to be present. (WIP, but early demo ready.
|
|
--
|
|
-- The following terminology is being used throughout this document:
|
|
--
|
|
-- * The **DesignateObject** is the object of the DESIGNATE class, which is this class explained in the document.
|
|
-- * The **DetectionObject** is the object of a DETECTION_ class (DETECTION_TYPES, DETECTION_AREAS, DETECTION_UNITS), which is executing the detection and grouping of Targets into _DetectionItems_.
|
|
-- * **TargetGroups** is the list of detected target groupings by the _DetectionObject_. Each _TargetGroup_ contains a _TargetSet_.
|
|
-- * **TargetGroup** is one element of the __TargetGroups__ list, and contains a _TargetSet_.
|
|
-- * The **TargetSet** is a SET_UNITS collection of _Targets_, that have been detected by the _DetectionObject_.
|
|
-- * A **Target** is a detected UNIT object by the _DetectionObject_.
|
|
-- * A **Threat Level** is a number from 0 to 10 that is calculated based on the threat of the Target in an Air to Ground battle scenario.
|
|
-- * The **RecceSet** is a SET_GROUP collection that contains the **RecceGroups**.
|
|
-- * A **RecceGroup** is a GROUP object containing the **Recces**.
|
|
-- * A **Recce** is a UNIT object executing the reconnaissance as part the _DetectionObject_. A Recce can be of any UNIT type.
|
|
-- * An **AttackGroup** is a GROUP object that contain _Players_.
|
|
-- * A **Player** is an active CLIENT object containing a human player.
|
|
-- * A **Designate Menu** is the menu that is dynamically created during the designation process for each _AttackGroup_.
|
|
--
|
|
-- # Player Manual
|
|
--
|
|
-- 
|
|
--
|
|
-- A typical mission setup would require Recce (a @{Set} of Recce) to be detecting potential targets.
|
|
-- The DetectionObject will group the detected targets based on the detection method being used.
|
|
-- Possible detection methods could be by Area, by Type or by Unit.
|
|
-- Each grouping will result in a **TargetGroup**, for terminology and clarity we will use this term throughout the document.
|
|
--
|
|
-- **Recce** require to have Line of Sight (LOS) towards the targets.
|
|
-- The **Recce** will report any detected targets to the Players (on the picture Observers).
|
|
-- When targets are detected, a menu will be made available that allows those **TargetGroups** to be designated.
|
|
-- Designation can be done by Lasing, Smoking and Illumination.
|
|
-- Smoking is useful during the day, while illumination is recommended to be used during the night.
|
|
-- Smoking can designate specific targets, but not very precise, while lasing is very accurate and allows to
|
|
-- players to attack the targets using laser guided bombs or rockets.
|
|
-- Illumination will lighten up the Target Area.
|
|
--
|
|
-- **Recce** can be ground based or airborne. Airborne **Recce** (AFAC) can be really useful to designate a large amount of targets
|
|
-- in a wide open area, as airborne **Recce** has a large LOS.
|
|
-- However, ground based **Recce** are very useful to smoke or illuminate targets, as they can be much closer
|
|
-- to the Target Area.
|
|
--
|
|
-- It is recommended to make the **Recce** invisible and immortal using the Mission Editor in DCS World.
|
|
-- This will ensure that the detection process won't be interrupted and that targets can be designated.
|
|
-- However, you don't have to, so to simulate a more real-word situation or simulation, **Recce can also be destroyed**!
|
|
--
|
|
-- ## 1. Player View (Observer)
|
|
--
|
|
-- 
|
|
--
|
|
-- The RecceSet is continuously detecting for potential Targets,
|
|
-- executing its task as part of the DetectionObject.
|
|
-- Once Targets have been detected, the DesignateObject will trigger the **Detect Event**.
|
|
--
|
|
-- In order to prevent an overflow in the DesignateObject of detected targets,
|
|
-- there is a maximum amount of TargetGroups
|
|
-- that can be put in **scope** of the DesignateObject.
|
|
-- We call this the **MaximumDesignations** term.
|
|
--
|
|
-- ## 2. Designate Menu
|
|
--
|
|
-- 
|
|
--
|
|
-- For each detected TargetGroup, there is:
|
|
--
|
|
-- * A **Designate Menu** are created and continuously refreshed, containing the **DesignationID** and the **Designation Status**.
|
|
-- * The RecceGroups are reporting to each AttackGroup, sending **Messages** containing the Threat Level and the TargetSet composition.
|
|
--
|
|
-- A Player can then select an action from the **Designate Menu**.
|
|
-- The Designation Status is shown between the ( ).
|
|
--
|
|
-- It indicates for each TargetGroup the current active designation action applied:
|
|
--
|
|
-- * An "I" for Illumnation designation.
|
|
-- * An "S" for Smoking designation.
|
|
-- * An "L" for Lasing designation.
|
|
--
|
|
-- Note that multiple designation methods can be active at the same time!
|
|
-- Note the **Auto Lase** option. When switched on, the available **Recce** will lase
|
|
-- Targets when detected.
|
|
--
|
|
-- Targets are designated per **Threat Level**.
|
|
-- The most threatening targets from an Air to Ground perspective, are designated first!
|
|
-- This is for all designation methods.
|
|
--
|
|
-- 
|
|
--
|
|
-- Each Designate Menu has a sub menu structure, which allows specific actions to be triggered:
|
|
--
|
|
-- * Lase Targets using a specific laser code.
|
|
-- * Smoke Targets using a specific smoke color.
|
|
-- * Illuminate areas.
|
|
--
|
|
-- ## 3. Lasing Targets
|
|
--
|
|
-- 
|
|
--
|
|
-- Lasing targets is done as expected. Each available Recce can lase only ONE target through!
|
|
--
|
|
-- 
|
|
--
|
|
-- Lasing can be done for specific laser codes. The Su-25T requires laser code 1113, while the A-10A requires laser code 1680.
|
|
-- For those, specific menu options can be made available for players to lase with these codes.
|
|
-- Auto Lase (as explained above), will ensure continuous lasing of available targets.
|
|
-- The status report shows which targets are being designated.
|
|
--
|
|
-- The following logic is executed when a TargetGroup is selected to be *lased* from the Designation Menu:
|
|
--
|
|
-- * The RecceSet is searched for any Recce that is within *designation distance* from a Target in the TargetGroup that is currently not being designated.
|
|
-- * If there is a Recce found that is currently no designating a target, and is within designation distance from the Target, then that Target will be designated.
|
|
-- * During designation, any Recce that does not have Line of Sight (LOS) and is not within disignation distance from the Target, will stop designating the Target, and a report is given.
|
|
-- * When a Recce is designating a Target, and that Target is destroyed, then the Recce will stop designating the Target, and will report the event.
|
|
-- * When a Recce is designating a Target, and that Recce is destroyed, then the Recce will be removed from the RecceSet and designation will stop without reporting.
|
|
-- * When all RecceGroups are destroyed from the RecceSet, then the DesignationObject will stop functioning, and nothing will be reported.
|
|
--
|
|
-- In this way, DESIGNATE assists players to designate ground targets for a coordinated attack!
|
|
--
|
|
-- ## 4. Illuminating Targets
|
|
--
|
|
-- 
|
|
--
|
|
-- Illumination bombs are fired between 500 and 700 meters altitude and will burn about 2 minutes, while slowly decending.
|
|
-- Each available recce within range will fire an illumination bomb.
|
|
-- Illumination bombs can be fired in while lasing targets.
|
|
-- When illumination bombs are fired, it will take about 2 minutes until a sequent bomb run can be requested using the menus.
|
|
--
|
|
-- ## 5. Smoking Targets
|
|
--
|
|
-- 
|
|
--
|
|
-- Smoke will fire for 5 minutes.
|
|
-- Each available recce within range will smoke a target.
|
|
-- Smoking can be requested while lasing targets.
|
|
-- Smoke will appear "around" the targets, because of accuracy limitations.
|
|
--
|
|
--
|
|
-- Have FUN!
|
|
--
|
|
-- ===
|
|
--
|
|
-- ### Contributions:
|
|
--
|
|
-- * [**Ciribob**](https://forums.eagle.ru/member.php?u=112175): Showing the way how to lase targets + how laser codes work!!! Explained the autolase script.
|
|
-- * [**EasyEB**](https://forums.eagle.ru/member.php?u=112055): Ideas and Beta Testing
|
|
-- * [**Wingthor**](https://forums.eagle.ru/member.php?u=123698): Beta Testing
|
|
--
|
|
-- ### Authors:
|
|
--
|
|
-- * **FlightControl**: Design & Programming
|
|
--
|
|
-- ===
|
|
--
|
|
-- @module Functional.Designate
|
|
-- @image Designation.JPG
|
|
|
|
do -- DESIGNATE
|
|
|
|
--- @type DESIGNATE
|
|
-- @extends Core.Fsm#FSM_PROCESS
|
|
|
|
--- Manage the designation of detected targets.
|
|
--
|
|
--
|
|
-- # 1. DESIGNATE constructor
|
|
--
|
|
-- * @{#DESIGNATE.New}(): Creates a new DESIGNATE object.
|
|
--
|
|
-- # 2. DESIGNATE is a FSM
|
|
--
|
|
-- Designate is a finite state machine, which allows for controlled transitions of states.
|
|
--
|
|
-- ## 2.1 DESIGNATE States
|
|
--
|
|
-- * **Designating** ( Group ): The designation process.
|
|
--
|
|
-- ## 2.2 DESIGNATE Events
|
|
--
|
|
-- * **@{#DESIGNATE.Detect}**: Detect targets.
|
|
-- * **@{#DESIGNATE.LaseOn}**: Lase the targets with the specified Index.
|
|
-- * **@{#DESIGNATE.LaseOff}**: Stop lasing the targets with the specified Index.
|
|
-- * **@{#DESIGNATE.Smoke}**: Smoke the targets with the specified Index.
|
|
-- * **@{#DESIGNATE.Status}**: Report designation status.
|
|
--
|
|
-- # 3. Maximum Designations
|
|
--
|
|
-- In order to prevent an overflow of designations due to many Detected Targets, there is a
|
|
-- Maximum Designations scope that is set in the DesignationObject.
|
|
--
|
|
-- The method @{#DESIGNATE.SetMaximumDesignations}() will put a limit on the amount of designations (target groups) put in scope of the DesignationObject.
|
|
-- Using the menu system, the player can "forget" a designation, so that gradually a new designation can be put in scope when detected.
|
|
--
|
|
-- # 4. Laser codes
|
|
--
|
|
-- ## 4.1. Set possible laser codes
|
|
--
|
|
-- An array of laser codes can be provided, that will be used by the DESIGNATE when lasing.
|
|
-- The laser code is communicated by the Recce when it is lasing a larget.
|
|
-- Note that the default laser code is 1113.
|
|
-- Working known laser codes are: 1113,1462,1483,1537,1362,1214,1131,1182,1644,1614,1515,1411,1621,1138,1542,1678,1573,1314,1643,1257,1467,1375,1341,1275,1237
|
|
--
|
|
-- Use the method @{#DESIGNATE.SetLaserCodes}() to set the possible laser codes to be selected from.
|
|
-- One laser code can be given or an sequence of laser codes through an table...
|
|
--
|
|
-- Designate:SetLaserCodes( 1214 )
|
|
--
|
|
-- The above sets one laser code with the value 1214.
|
|
--
|
|
-- Designate:SetLaserCodes( { 1214, 1131, 1614, 1138 } )
|
|
--
|
|
-- The above sets a collection of possible laser codes that can be assigned. **Note the { } notation!**
|
|
--
|
|
-- ## 4.2. Auto generate laser codes
|
|
--
|
|
-- Use the method @{#DESIGNATE.GenerateLaserCodes}() to generate all possible laser codes. Logic implemented and advised by Ciribob!
|
|
--
|
|
-- ## 4.3. Add specific lase codes to the lase menu
|
|
--
|
|
-- Certain plane types can only drop laser guided ordonnance when targets are lased with specific laser codes.
|
|
-- The SU-25T needs targets to be lased using laser code 1113.
|
|
-- The A-10A needs targets to be lased using laser code 1680.
|
|
--
|
|
-- The method @{#DESIGNATE.AddMenuLaserCode}() to allow a player to lase a target using a specific laser code.
|
|
-- Remove such a lase menu option using @{#DESIGNATE.RemoveMenuLaserCode}().
|
|
--
|
|
-- # 5. Autolase to automatically lase detected targets.
|
|
--
|
|
-- DetectionItems can be auto lased once detected by Recces. As such, there is almost no action required from the Players using the Designate Menu.
|
|
-- The **auto lase** function can be activated through the Designation Menu.
|
|
-- Use the method @{#DESIGNATE.SetAutoLase}() to activate or deactivate the auto lase function programmatically.
|
|
-- Note that autolase will automatically activate lasing for ALL DetectedItems. Individual items can be switched-off if required using the Designation Menu.
|
|
--
|
|
-- Designate:SetAutoLase( true )
|
|
--
|
|
-- Activate the auto lasing.
|
|
--
|
|
-- # 6. Target prioritization on threat level
|
|
--
|
|
-- Targets can be detected of different types in one DetectionItem. Depending on the type of the Target, a different threat level applies in an Air to Ground combat context.
|
|
-- SAMs are of a higher threat than normal tanks. So, if the Target type was recognized, the Recces will select those targets that form the biggest threat first,
|
|
-- and will continue this until the remaining vehicles with the lowest threat have been reached.
|
|
--
|
|
-- This threat level prioritization can be activated using the method @{#DESIGNATE.SetThreatLevelPrioritization}().
|
|
-- If not activated, Targets will be selected in a random order, but most like those first which are the closest to the Recce marking the Target.
|
|
--
|
|
-- Designate:SetThreatLevelPrioritization( true )
|
|
--
|
|
-- The example will activate the threat level prioritization for this the Designate object. Threats will be marked based on the threat level of the Target.
|
|
--
|
|
-- # 7. Designate Menu Location for a Mission
|
|
--
|
|
-- You can make DESIGNATE work for a @{Tasking.Mission#MISSION} object. In this way, the designate menu will not appear in the root of the radio menu, but in the menu of the Mission.
|
|
-- Use the method @{#DESIGNATE.SetMission}() to set the @{Mission} object for the designate function.
|
|
--
|
|
-- # 8. Status Report
|
|
--
|
|
-- A status report is available that displays the current Targets detected, grouped per DetectionItem, and a list of which Targets are currently being marked.
|
|
--
|
|
-- * The status report can be shown by selecting "Status" -> "Report Status" from the Designation menu .
|
|
-- * The status report can be automatically flashed by selecting "Status" -> "Flash Status On".
|
|
-- * The automatic flashing of the status report can be deactivated by selecting "Status" -> "Flash Status Off".
|
|
-- * The flashing of the status menu is disabled by default.
|
|
-- * The method @{#DESIGNATE.SetFlashStatusMenu}() can be used to enable or disable to flashing of the status menu.
|
|
--
|
|
-- Designate:SetFlashStatusMenu( true )
|
|
--
|
|
-- The example will activate the flashing of the status menu for this Designate object.
|
|
--
|
|
-- @field #DESIGNATE
|
|
DESIGNATE = {
|
|
ClassName = "DESIGNATE",
|
|
}
|
|
|
|
--- DESIGNATE Constructor. This class is an abstract class and should not be instantiated.
|
|
-- @param #DESIGNATE self
|
|
-- @param Tasking.CommandCenter#COMMANDCENTER CC
|
|
-- @param Functional.Detection#DETECTION_BASE Detection
|
|
-- @param Core.Set#SET_GROUP AttackSet The Attack collection of GROUP objects to designate and report for.
|
|
-- @param Tasking.Mission#MISSION Mission (Optional) The Mission where the menu needs to be attached.
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:New( CC, Detection, AttackSet, Mission )
|
|
|
|
local self = BASE:Inherit( self, FSM:New() ) -- #DESIGNATE
|
|
self:F( { Detection } )
|
|
|
|
self:SetStartState( "Designating" )
|
|
|
|
self:AddTransition( "*", "Detect", "*" )
|
|
--- Detect Handler OnBefore for DESIGNATE
|
|
-- @function [parent=#DESIGNATE] OnBeforeDetect
|
|
-- @param #DESIGNATE self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
-- @return #boolean
|
|
|
|
--- Detect Handler OnAfter for DESIGNATE
|
|
-- @function [parent=#DESIGNATE] OnAfterDetect
|
|
-- @param #DESIGNATE self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
|
|
--- Detect Trigger for DESIGNATE
|
|
-- @function [parent=#DESIGNATE] Detect
|
|
-- @param #DESIGNATE self
|
|
|
|
--- Detect Asynchronous Trigger for DESIGNATE
|
|
-- @function [parent=#DESIGNATE] __Detect
|
|
-- @param #DESIGNATE self
|
|
-- @param #number Delay
|
|
|
|
self:AddTransition( "*", "LaseOn", "Lasing" )
|
|
--- LaseOn Handler OnBefore for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] OnBeforeLaseOn
|
|
-- @param #DESIGNATE self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
-- @return #boolean
|
|
|
|
--- LaseOn Handler OnAfter for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] OnAfterLaseOn
|
|
-- @param #DESIGNATE self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
|
|
--- LaseOn Trigger for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] LaseOn
|
|
-- @param #DESIGNATE self
|
|
|
|
--- LaseOn Asynchronous Trigger for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] __LaseOn
|
|
-- @param #DESIGNATE self
|
|
-- @param #number Delay
|
|
|
|
self:AddTransition( "Lasing", "Lasing", "Lasing" )
|
|
|
|
self:AddTransition( "*", "LaseOff", "Designate" )
|
|
--- LaseOff Handler OnBefore for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] OnBeforeLaseOff
|
|
-- @param #DESIGNATE self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
-- @return #boolean
|
|
|
|
--- LaseOff Handler OnAfter for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] OnAfterLaseOff
|
|
-- @param #DESIGNATE self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
|
|
--- LaseOff Trigger for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] LaseOff
|
|
-- @param #DESIGNATE self
|
|
|
|
--- LaseOff Asynchronous Trigger for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] __LaseOff
|
|
-- @param #DESIGNATE self
|
|
-- @param #number Delay
|
|
|
|
self:AddTransition( "*", "Smoke", "*" )
|
|
--- Smoke Handler OnBefore for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] OnBeforeSmoke
|
|
-- @param #DESIGNATE self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
-- @return #boolean
|
|
|
|
--- Smoke Handler OnAfter for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] OnAfterSmoke
|
|
-- @param #DESIGNATE self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
|
|
--- Smoke Trigger for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] Smoke
|
|
-- @param #DESIGNATE self
|
|
|
|
--- Smoke Asynchronous Trigger for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] __Smoke
|
|
-- @param #DESIGNATE self
|
|
-- @param #number Delay
|
|
|
|
self:AddTransition( "*", "Illuminate", "*" )
|
|
--- Illuminate Handler OnBefore for DESIGNATE
|
|
-- @function [parent=#DESIGNATE] OnBeforeIlluminate
|
|
-- @param #DESIGNATE self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
-- @return #boolean
|
|
|
|
--- Illuminate Handler OnAfter for DESIGNATE
|
|
-- @function [parent=#DESIGNATE] OnAfterIlluminate
|
|
-- @param #DESIGNATE self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
|
|
--- Illuminate Trigger for DESIGNATE
|
|
-- @function [parent=#DESIGNATE] Illuminate
|
|
-- @param #DESIGNATE self
|
|
|
|
--- Illuminate Asynchronous Trigger for DESIGNATE
|
|
-- @function [parent=#DESIGNATE] __Illuminate
|
|
-- @param #DESIGNATE self
|
|
-- @param #number Delay
|
|
|
|
self:AddTransition( "*", "DoneSmoking", "*" )
|
|
self:AddTransition( "*", "DoneIlluminating", "*" )
|
|
|
|
self:AddTransition( "*", "Status", "*" )
|
|
--- Status Handler OnBefore for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] OnBeforeStatus
|
|
-- @param #DESIGNATE self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
-- @return #boolean
|
|
|
|
--- Status Handler OnAfter for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] OnAfterStatus
|
|
-- @param #DESIGNATE self
|
|
-- @param #string From
|
|
-- @param #string Event
|
|
-- @param #string To
|
|
|
|
--- Status Trigger for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] Status
|
|
-- @param #DESIGNATE self
|
|
|
|
--- Status Asynchronous Trigger for DESIGNATE
|
|
-- @function [parent=#DESIGNATE ] __Status
|
|
-- @param #DESIGNATE self
|
|
-- @param #number Delay
|
|
|
|
self.CC = CC
|
|
self.Detection = Detection
|
|
self.AttackSet = AttackSet
|
|
self.RecceSet = Detection:GetDetectionSet()
|
|
self.Recces = {}
|
|
self.Designating = {}
|
|
self:SetDesignateName()
|
|
|
|
self:SetLaseDuration() -- Default is 120 seconds.
|
|
|
|
self:SetFlashStatusMenu( false )
|
|
self:SetFlashDetectionMessages( true )
|
|
self:SetMission( Mission )
|
|
|
|
self:SetLaserCodes( { 1688, 1130, 4785, 6547, 1465, 4578 } ) -- set self.LaserCodes
|
|
self:SetAutoLase( false, false ) -- set self.Autolase and don't send message.
|
|
|
|
self:SetThreatLevelPrioritization( false ) -- self.ThreatLevelPrioritization, default is threat level priorization off
|
|
self:SetMaximumDesignations( 5 ) -- Sets the maximum designations. The default is 5 designations.
|
|
self:SetMaximumDistanceDesignations( 8000 ) -- Sets the maximum distance on which designations can be accepted. The default is 8000 meters.
|
|
self:SetMaximumMarkings( 2 ) -- Per target group, a maximum of 2 markings will be made by default.
|
|
|
|
self:SetDesignateMenu()
|
|
|
|
self.LaserCodesUsed = {}
|
|
|
|
self.MenuLaserCodes = {} -- This map contains the laser codes that will be shown in the designate menu to lase with specific laser codes.
|
|
|
|
self.Detection:__Start( 2 )
|
|
|
|
self:__Detect( -15 )
|
|
|
|
self.MarkScheduler = SCHEDULER:New( self )
|
|
|
|
return self
|
|
end
|
|
|
|
--- Set the flashing of the status menu for all AttackGroups.
|
|
-- @param #DESIGNATE self
|
|
-- @param #boolean FlashMenu true: the status menu will be flashed every detection run; false: no flashing of the menu.
|
|
-- @return #DESIGNATE
|
|
-- @usage
|
|
--
|
|
-- -- Enable the designate status message flashing...
|
|
-- Designate:SetFlashStatusMenu( true )
|
|
--
|
|
-- -- Disable the designate statusmessage flashing...
|
|
-- Designate:SetFlashStatusMenu()
|
|
--
|
|
-- -- Disable the designate status message flashing...
|
|
-- Designate:SetFlashStatusMenu( false )
|
|
function DESIGNATE:SetFlashStatusMenu( FlashMenu ) --R2.1
|
|
|
|
self.FlashStatusMenu = {}
|
|
|
|
self.AttackSet:ForEachGroupAlive(
|
|
|
|
--- @param Wrapper.Group#GROUP AttackGroup
|
|
function( AttackGroup )
|
|
self.FlashStatusMenu[AttackGroup] = FlashMenu
|
|
end
|
|
)
|
|
|
|
return self
|
|
end
|
|
|
|
--- Set the flashing of the new detection messages.
|
|
-- @param #DESIGNATE self
|
|
-- @param #boolean FlashDetectionMessage true: The detection message will be flashed every time a new detection was done; false: no messages will be displayed.
|
|
-- @return #DESIGNATE
|
|
-- @usage
|
|
--
|
|
-- -- Enable the message flashing...
|
|
-- Designate:SetFlashDetectionMessages( true )
|
|
--
|
|
-- -- Disable the message flashing...
|
|
-- Designate:SetFlashDetectionMessages()
|
|
--
|
|
-- -- Disable the message flashing...
|
|
-- Designate:SetFlashDetectionMessages( false )
|
|
function DESIGNATE:SetFlashDetectionMessages( FlashDetectionMessage )
|
|
|
|
self.FlashDetectionMessage = {}
|
|
|
|
self.AttackSet:ForEachGroupAlive(
|
|
|
|
--- @param Wrapper.Group#GROUP AttackGroup
|
|
function( AttackGroup )
|
|
self.FlashDetectionMessage[AttackGroup] = FlashDetectionMessage
|
|
end
|
|
)
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
--- Set the maximum amount of designations (target groups). This will put a limit on the amount of designations in scope.
|
|
-- Using the menu system, the player can "forget" a designation, so that gradually a new designation can be put in scope when detected.
|
|
-- @param #DESIGNATE self
|
|
-- @param #number MaximumDesignations
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:SetMaximumDesignations( MaximumDesignations )
|
|
self.MaximumDesignations = MaximumDesignations
|
|
return self
|
|
end
|
|
|
|
|
|
--- Set the maximum ground designation distance.
|
|
-- @param #DESIGNATE self
|
|
-- @param #number MaximumDistanceGroundDesignation Maximum ground designation distance in meters.
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:SetMaximumDistanceGroundDesignation( MaximumDistanceGroundDesignation )
|
|
self.MaximumDistanceGroundDesignation = MaximumDistanceGroundDesignation
|
|
return self
|
|
end
|
|
|
|
|
|
--- Set the maximum air designation distance.
|
|
-- @param #DESIGNATE self
|
|
-- @param #number MaximumDistanceAirDesignation Maximum air designation distance in meters.
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:SetMaximumDistanceAirDesignation( MaximumDistanceAirDesignation )
|
|
self.MaximumDistanceAirDesignation = MaximumDistanceAirDesignation
|
|
return self
|
|
end
|
|
|
|
|
|
--- Set the overall maximum distance when designations can be accepted.
|
|
-- @param #DESIGNATE self
|
|
-- @param #number MaximumDistanceDesignations Maximum distance in meters to accept designations.
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:SetMaximumDistanceDesignations( MaximumDistanceDesignations )
|
|
self.MaximumDistanceDesignations = MaximumDistanceDesignations
|
|
return self
|
|
end
|
|
|
|
|
|
--- Set the maximum amount of markings FACs will do, per designated target group. This will limit the number of parallelly marked units of a target group.
|
|
-- @param #DESIGNATE self
|
|
-- @param #number MaximumMarkings Maximum markings FACs will do, per designated target group.
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:SetMaximumMarkings( MaximumMarkings )
|
|
self.MaximumMarkings = MaximumMarkings
|
|
return self
|
|
end
|
|
|
|
|
|
--- Set an array of possible laser codes.
|
|
-- Each new lase will select a code from this table.
|
|
-- @param #DESIGNATE self
|
|
-- @param #list<#number> LaserCodes
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:SetLaserCodes( LaserCodes ) --R2.1
|
|
|
|
self.LaserCodes = ( type( LaserCodes ) == "table" ) and LaserCodes or { LaserCodes }
|
|
self:F( { LaserCodes = self.LaserCodes } )
|
|
|
|
self.LaserCodesUsed = {}
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
--- Add a specific lase code to the designate lase menu to lase targets with a specific laser code.
|
|
-- The MenuText will appear in the lase menu.
|
|
-- @param #DESIGNATE self
|
|
-- @param #number LaserCode The specific laser code to be added to the lase menu.
|
|
-- @param #string MenuText The text to be shown to the player. If you specify a %d in the MenuText, the %d will be replaced with the LaserCode specified.
|
|
-- @return #DESIGNATE
|
|
-- @usage
|
|
-- RecceDesignation:AddMenuLaserCode( 1113, "Lase with %d for Su-25T" )
|
|
-- RecceDesignation:AddMenuLaserCode( 1680, "Lase with %d for A-10A" )
|
|
--
|
|
function DESIGNATE:AddMenuLaserCode( LaserCode, MenuText )
|
|
|
|
self.MenuLaserCodes[LaserCode] = MenuText
|
|
self:SetDesignateMenu()
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
--- Removes a specific lase code from the designate lase menu.
|
|
-- @param #DESIGNATE self
|
|
-- @param #number LaserCode The specific laser code that was set to be added to the lase menu.
|
|
-- @return #DESIGNATE
|
|
-- @usage
|
|
-- RecceDesignation:RemoveMenuLaserCode( 1113 )
|
|
--
|
|
function DESIGNATE:RemoveMenuLaserCode( LaserCode )
|
|
|
|
self.MenuLaserCodes[LaserCode] = nil
|
|
self:SetDesignateMenu()
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
|
|
|
|
--- Set the name of the designation. The name will appear in the menu.
|
|
-- This method can be used to control different designations for different plane types.
|
|
-- @param #DESIGNATE self
|
|
-- @param #string DesignateName
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:SetDesignateName( DesignateName )
|
|
|
|
self.DesignateName = "Designation" .. ( DesignateName and ( " for " .. DesignateName ) or "" )
|
|
|
|
return self
|
|
end
|
|
|
|
--- Set the lase duration for designations.
|
|
-- @param #DESIGNATE self
|
|
-- @param #number LaseDuration The time in seconds a lase will continue to hold on target. The default is 120 seconds.
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:SetLaseDuration( LaseDuration )
|
|
self.LaseDuration = LaseDuration or 120
|
|
return self
|
|
end
|
|
|
|
--- Generate an array of possible laser codes.
|
|
-- Each new lase will select a code from this table.
|
|
-- The entered value can range from 1111 - 1788,
|
|
-- -- but the first digit of the series must be a 1 or 2
|
|
-- -- and the last three digits must be between 1 and 8.
|
|
-- The range used to be bugged so its not 1 - 8 but 0 - 7.
|
|
-- function below will use the range 1-7 just in case
|
|
-- @param #DESIGNATE self
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:GenerateLaserCodes() --R2.1
|
|
|
|
self.LaserCodes = {}
|
|
|
|
local function containsDigit(_number, _numberToFind)
|
|
|
|
local _thisNumber = _number
|
|
local _thisDigit = 0
|
|
|
|
while _thisNumber ~= 0 do
|
|
_thisDigit = _thisNumber % 10
|
|
_thisNumber = math.floor(_thisNumber / 10)
|
|
if _thisDigit == _numberToFind then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
-- generate list of laser codes
|
|
local _code = 1111
|
|
local _count = 1
|
|
while _code < 1777 and _count < 30 do
|
|
while true do
|
|
_code = _code + 1
|
|
if not containsDigit(_code, 8)
|
|
and not containsDigit(_code, 9)
|
|
and not containsDigit(_code, 0) then
|
|
self:T(_code)
|
|
table.insert( self.LaserCodes, _code )
|
|
break
|
|
end
|
|
end
|
|
_count = _count + 1
|
|
end
|
|
|
|
self.LaserCodesUsed = {}
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
|
|
--- Set auto lase.
|
|
-- Auto lase will start lasing targets immediately when these are in range.
|
|
-- @param #DESIGNATE self
|
|
-- @param #boolean AutoLase (optional) true sets autolase on, false off. Default is off.
|
|
-- @param #boolean Message (optional) true is send message, false or nil won't send a message. Default is no message sent.
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:SetAutoLase( AutoLase, Message )
|
|
|
|
self.AutoLase = AutoLase or false
|
|
|
|
if Message then
|
|
local AutoLaseOnOff = ( self.AutoLase == true ) and "On" or "Off"
|
|
local CC = self.CC:GetPositionable()
|
|
if CC then
|
|
CC:MessageToSetGroup( self.DesignateName .. ": Auto Lase " .. AutoLaseOnOff .. ".", 15, self.AttackSet )
|
|
end
|
|
end
|
|
|
|
self:CoordinateLase()
|
|
self:SetDesignateMenu()
|
|
|
|
return self
|
|
end
|
|
|
|
--- Set priorization of Targets based on the **Threat Level of the Target** in an Air to Ground context.
|
|
-- @param #DESIGNATE self
|
|
-- @param #boolean Prioritize
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:SetThreatLevelPrioritization( Prioritize ) --R2.1
|
|
|
|
self.ThreatLevelPrioritization = Prioritize
|
|
|
|
return self
|
|
end
|
|
|
|
--- Set the MISSION object for which designate will function.
|
|
-- When a MISSION object is assigned, the menu for the designation will be located at the Mission Menu.
|
|
-- @param #DESIGNATE self
|
|
-- @param Tasking.Mission#MISSION Mission The MISSION object.
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:SetMission( Mission ) --R2.2
|
|
|
|
self.Mission = Mission
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
---
|
|
-- @param #DESIGNATE self
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:onafterDetect()
|
|
|
|
self:__Detect( -math.random( 60 ) )
|
|
|
|
self:DesignationScope()
|
|
self:CoordinateLase()
|
|
self:SendStatus()
|
|
self:SetDesignateMenu()
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
--- Adapt the designation scope according the detected items.
|
|
-- @param #DESIGNATE self
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:DesignationScope()
|
|
|
|
local DetectedItems = self.Detection:GetDetectedItemsByIndex()
|
|
|
|
local DetectedItemCount = 0
|
|
|
|
for DesignateIndex, Designating in pairs( self.Designating ) do
|
|
local DetectedItem = self.Detection:GetDetectedItemByIndex( DesignateIndex )
|
|
if DetectedItem then
|
|
-- Check LOS...
|
|
local IsDetected = self.Detection:IsDetectedItemDetected( DetectedItem )
|
|
self:F({IsDetected = IsDetected })
|
|
if IsDetected == false then
|
|
self:F("Removing")
|
|
-- This Detection is obsolete, remove from the designate scope
|
|
self.Designating[DesignateIndex] = nil
|
|
self.AttackSet:ForEachGroupAlive(
|
|
--- @param Wrapper.Group#GROUP AttackGroup
|
|
function( AttackGroup )
|
|
if AttackGroup:IsAlive() == true then
|
|
local DetectionText = self.Detection:DetectedItemReportSummary( DetectedItem, AttackGroup ):Text( ", " )
|
|
self.CC:GetPositionable():MessageToGroup( "Targets out of LOS\n" .. DetectionText, 10, AttackGroup, self.DesignateName )
|
|
end
|
|
end
|
|
)
|
|
else
|
|
DetectedItemCount = DetectedItemCount + 1
|
|
end
|
|
else
|
|
-- This Detection is obsolete, remove from the designate scope
|
|
self.Designating[DesignateIndex] = nil
|
|
end
|
|
end
|
|
|
|
if DetectedItemCount < 5 then
|
|
for DesignateIndex, DetectedItem in pairs( DetectedItems ) do
|
|
local IsDetected = self.Detection:IsDetectedItemDetected( DetectedItem )
|
|
if IsDetected == true then
|
|
self:F( { DistanceRecce = DetectedItem.DistanceRecce } )
|
|
if DetectedItem.DistanceRecce <= self.MaximumDistanceDesignations then
|
|
if self.Designating[DesignateIndex] == nil then
|
|
-- ok, we added one item to the designate scope.
|
|
self.AttackSet:ForEachGroupAlive(
|
|
function( AttackGroup )
|
|
if self.FlashDetectionMessage[AttackGroup] == true then
|
|
local DetectionText = self.Detection:DetectedItemReportSummary( DetectedItem, AttackGroup ):Text( ", " )
|
|
self.CC:GetPositionable():MessageToGroup( "Targets detected at \n" .. DetectionText, 10, AttackGroup, self.DesignateName )
|
|
end
|
|
end
|
|
)
|
|
self.Designating[DesignateIndex] = ""
|
|
|
|
-- When we found an item for designation, we stop the loop.
|
|
-- So each iteration over the detected items, a new detected item will be selected to be designated.
|
|
-- Until all detected items were found or until there are about 5 designations allocated.
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Coordinates the Auto Lase.
|
|
-- @param #DESIGNATE self
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:CoordinateLase()
|
|
|
|
local DetectedItems = self.Detection:GetDetectedItemsByIndex()
|
|
|
|
for DesignateIndex, Designating in pairs( self.Designating ) do
|
|
local DetectedItem = DetectedItems[DesignateIndex]
|
|
if DetectedItem then
|
|
if self.AutoLase then
|
|
self:LaseOn( DesignateIndex, self.LaseDuration )
|
|
end
|
|
end
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
--- Sends the status to the Attack Groups.
|
|
-- @param #DESIGNATE self
|
|
-- @param Wrapper.Group#GROUP AttackGroup
|
|
-- @param #number Duration The time in seconds the report should be visible.
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:SendStatus( MenuAttackGroup )
|
|
|
|
self.AttackSet:ForEachGroupAlive(
|
|
|
|
--- @param Wrapper.Group#GROUP GroupReport
|
|
function( AttackGroup )
|
|
|
|
if self.FlashStatusMenu[AttackGroup] or ( MenuAttackGroup and ( AttackGroup:GetName() == MenuAttackGroup:GetName() ) ) then
|
|
|
|
local DetectedReport = REPORT:New( "Targets ready for Designation:" )
|
|
local DetectedItems = self.Detection:GetDetectedItemsByIndex()
|
|
|
|
for DesignateIndex, Designating in pairs( self.Designating ) do
|
|
local DetectedItem = DetectedItems[DesignateIndex]
|
|
if DetectedItem then
|
|
local Report = self.Detection:DetectedItemReportSummary( DetectedItem, AttackGroup, nil, true ):Text( ", " )
|
|
DetectedReport:Add( string.rep( "-", 40 ) )
|
|
DetectedReport:Add( " - " .. Report )
|
|
if string.find( Designating, "L" ) then
|
|
DetectedReport:Add( " - " .. "Lasing Targets" )
|
|
end
|
|
if string.find( Designating, "S" ) then
|
|
DetectedReport:Add( " - " .. "Smoking Targets" )
|
|
end
|
|
if string.find( Designating, "I" ) then
|
|
DetectedReport:Add( " - " .. "Illuminating Area" )
|
|
end
|
|
end
|
|
end
|
|
|
|
local CC = self.CC:GetPositionable()
|
|
|
|
CC:MessageTypeToGroup( DetectedReport:Text( "\n" ), MESSAGE.Type.Information, AttackGroup, self.DesignateName )
|
|
|
|
local DesignationReport = REPORT:New( "Marking Targets:" )
|
|
|
|
self.RecceSet:ForEachGroupAlive(
|
|
function( RecceGroup )
|
|
local RecceUnits = RecceGroup:GetUnits()
|
|
for UnitID, RecceData in pairs( RecceUnits ) do
|
|
local Recce = RecceData -- Wrapper.Unit#UNIT
|
|
if Recce:IsLasing() then
|
|
DesignationReport:Add( " - " .. Recce:GetMessageText( "Marking " .. Recce:GetSpot().Target:GetTypeName() .. " with laser " .. Recce:GetSpot().LaserCode .. "." ) )
|
|
end
|
|
end
|
|
end
|
|
)
|
|
|
|
CC:MessageTypeToGroup( DesignationReport:Text(), MESSAGE.Type.Information, AttackGroup, self.DesignateName )
|
|
end
|
|
end
|
|
)
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
--- Sets the Designate Menu for one attack groups.
|
|
-- @param #DESIGNATE self
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:SetMenu( AttackGroup )
|
|
|
|
self.MenuDesignate = self.MenuDesignate or {}
|
|
|
|
local MissionMenu = nil
|
|
|
|
if self.Mission then
|
|
--MissionMenu = self.Mission:GetRootMenu( AttackGroup )
|
|
MissionMenu = self.Mission:GetMenu( AttackGroup )
|
|
end
|
|
|
|
local MenuTime = timer.getTime()
|
|
|
|
self.MenuDesignate[AttackGroup] = MENU_GROUP_DELAYED:New( AttackGroup, self.DesignateName, MissionMenu ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
local MenuDesignate = self.MenuDesignate[AttackGroup] -- Core.Menu#MENU_GROUP_DELAYED
|
|
|
|
-- Set Menu option for auto lase
|
|
|
|
if self.AutoLase then
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Auto Lase Off", MenuDesignate, self.MenuAutoLase, self, false ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
else
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Auto Lase On", MenuDesignate, self.MenuAutoLase, self, true ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
end
|
|
|
|
local StatusMenu = MENU_GROUP_DELAYED:New( AttackGroup, "Status", MenuDesignate ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Report Status", StatusMenu, self.MenuStatus, self, AttackGroup ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
|
|
if self.FlashStatusMenu[AttackGroup] then
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Flash Status Report Off", StatusMenu, self.MenuFlashStatus, self, AttackGroup, false ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
else
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Flash Status Report On", StatusMenu, self.MenuFlashStatus, self, AttackGroup, true ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
end
|
|
|
|
local DesignateCount = 0
|
|
|
|
for DesignateIndex, Designating in pairs( self.Designating ) do
|
|
|
|
local DetectedItem = self.Detection:GetDetectedItemByIndex( DesignateIndex )
|
|
|
|
if DetectedItem then
|
|
|
|
local Coord = self.Detection:GetDetectedItemCoordinate( DetectedItem )
|
|
local ID = self.Detection:GetDetectedItemID( DetectedItem )
|
|
local MenuText = ID --.. ", " .. Coord:ToStringA2G( AttackGroup )
|
|
|
|
-- Use injected MenuName from TaskA2GDispatcher if using same Detection Object
|
|
if DetectedItem.DesignateMenuName then
|
|
MenuText = string.format( "(%3s) %s", Designating, DetectedItem.DesignateMenuName )
|
|
else
|
|
MenuText = string.format( "(%3s) %s", Designating, MenuText )
|
|
end
|
|
|
|
local DetectedMenu = MENU_GROUP_DELAYED:New( AttackGroup, MenuText, MenuDesignate ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
|
|
-- Build the Lasing menu.
|
|
if string.find( Designating, "L", 1, true ) == nil then
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Search other target", DetectedMenu, self.MenuForget, self, DesignateIndex ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
for LaserCode, MenuText in pairs( self.MenuLaserCodes ) do
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, string.format( MenuText, LaserCode ), DetectedMenu, self.MenuLaseCode, self, DesignateIndex, self.LaseDuration, LaserCode ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
end
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Lase with random laser code(s)", DetectedMenu, self.MenuLaseOn, self, DesignateIndex, self.LaseDuration ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
else
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Stop lasing", DetectedMenu, self.MenuLaseOff, self, DesignateIndex ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
end
|
|
|
|
-- Build the Smoking menu.
|
|
if string.find( Designating, "S", 1, true ) == nil then
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Smoke red", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Red ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Smoke blue", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Blue ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Smoke green", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Green ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Smoke white", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.White ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Smoke orange", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Orange ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
end
|
|
|
|
-- Build the Illuminate menu.
|
|
if string.find( Designating, "I", 1, true ) == nil then
|
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Illuminate", DetectedMenu, self.MenuIlluminate, self, DesignateIndex ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
end
|
|
end
|
|
|
|
DesignateCount = DesignateCount + 1
|
|
if DesignateCount > 10 then
|
|
break
|
|
end
|
|
end
|
|
MenuDesignate:Remove( MenuTime, self.DesignateName )
|
|
MenuDesignate:Set()
|
|
end
|
|
|
|
|
|
--- Sets the Designate Menu for all the attack groups.
|
|
-- @param #DESIGNATE self
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:SetDesignateMenu()
|
|
|
|
self.AttackSet:Flush( self )
|
|
|
|
local Delay = 1
|
|
|
|
self.AttackSet:ForEachGroupAlive(
|
|
|
|
--- @param Wrapper.Group#GROUP GroupReport
|
|
function( AttackGroup )
|
|
|
|
self:ScheduleOnce( Delay, self.SetMenu, self, AttackGroup )
|
|
Delay = Delay + 1
|
|
end
|
|
|
|
)
|
|
|
|
return self
|
|
end
|
|
|
|
---
|
|
-- @param #DESIGNATE self
|
|
function DESIGNATE:MenuStatus( AttackGroup )
|
|
|
|
self:F("Status")
|
|
|
|
self:SendStatus( AttackGroup )
|
|
end
|
|
|
|
---
|
|
-- @param #DESIGNATE self
|
|
function DESIGNATE:MenuFlashStatus( AttackGroup, Flash )
|
|
|
|
self:F("Flash Status")
|
|
|
|
self.FlashStatusMenu[AttackGroup] = Flash
|
|
self:SetDesignateMenu()
|
|
end
|
|
|
|
|
|
---
|
|
-- @param #DESIGNATE self
|
|
function DESIGNATE:MenuForget( Index )
|
|
|
|
self:F("Forget")
|
|
|
|
self.Designating[Index] = ""
|
|
self:SetDesignateMenu()
|
|
end
|
|
|
|
---
|
|
-- @param #DESIGNATE self
|
|
function DESIGNATE:MenuAutoLase( AutoLase )
|
|
|
|
self:F("AutoLase")
|
|
|
|
self:SetAutoLase( AutoLase, true )
|
|
end
|
|
|
|
---
|
|
-- @param #DESIGNATE self
|
|
function DESIGNATE:MenuSmoke( Index, Color )
|
|
|
|
self:F("Designate through Smoke")
|
|
|
|
if string.find( self.Designating[Index], "S" ) == nil then
|
|
self.Designating[Index] = self.Designating[Index] .. "S"
|
|
end
|
|
self:Smoke( Index, Color )
|
|
self:SetDesignateMenu()
|
|
end
|
|
|
|
---
|
|
-- @param #DESIGNATE self
|
|
function DESIGNATE:MenuIlluminate( Index )
|
|
|
|
self:F("Designate through Illumination")
|
|
|
|
if string.find( self.Designating[Index], "I", 1, true ) == nil then
|
|
self.Designating[Index] = self.Designating[Index] .. "I"
|
|
end
|
|
|
|
self:__Illuminate( 1, Index )
|
|
self:SetDesignateMenu()
|
|
end
|
|
|
|
---
|
|
-- @param #DESIGNATE self
|
|
function DESIGNATE:MenuLaseOn( Index, Duration )
|
|
|
|
self:F("Designate through Lase")
|
|
|
|
self:__LaseOn( 1, Index, Duration )
|
|
self:SetDesignateMenu()
|
|
end
|
|
|
|
|
|
---
|
|
-- @param #DESIGNATE self
|
|
function DESIGNATE:MenuLaseCode( Index, Duration, LaserCode )
|
|
|
|
self:F( "Designate through Lase using " .. LaserCode )
|
|
|
|
self:__LaseOn( 1, Index, Duration, LaserCode )
|
|
self:SetDesignateMenu()
|
|
end
|
|
|
|
|
|
---
|
|
-- @param #DESIGNATE self
|
|
function DESIGNATE:MenuLaseOff( Index, Duration )
|
|
|
|
self:F("Lasing off")
|
|
|
|
self.Designating[Index] = string.gsub( self.Designating[Index], "L", "" )
|
|
self:__LaseOff( 1, Index )
|
|
self:SetDesignateMenu()
|
|
end
|
|
|
|
---
|
|
-- @param #DESIGNATE self
|
|
function DESIGNATE:onafterLaseOn( From, Event, To, Index, Duration, LaserCode )
|
|
|
|
if string.find( self.Designating[Index], "L", 1, true ) == nil then
|
|
self.Designating[Index] = self.Designating[Index] .. "L"
|
|
self.LaseStart = timer.getTime()
|
|
self.LaseDuration = Duration
|
|
self:Lasing( Index, Duration, LaserCode )
|
|
end
|
|
end
|
|
|
|
|
|
---
|
|
-- @param #DESIGNATE self
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:onafterLasing( From, Event, To, Index, Duration, LaserCodeRequested )
|
|
|
|
|
|
local DetectedItem = self.Detection:GetDetectedItemByIndex( Index )
|
|
local TargetSetUnit = self.Detection:GetDetectedItemSet( DetectedItem )
|
|
|
|
local MarkingCount = 0
|
|
local MarkedTypes = {}
|
|
--local ReportTypes = REPORT:New()
|
|
--local ReportLaserCodes = REPORT:New()
|
|
|
|
TargetSetUnit:Flush( self )
|
|
|
|
--self:F( { Recces = self.Recces } )
|
|
for TargetUnit, RecceData in pairs( self.Recces ) do
|
|
local Recce = RecceData -- Wrapper.Unit#UNIT
|
|
self:F( { TargetUnit = TargetUnit, Recce = Recce:GetName() } )
|
|
if not Recce:IsLasing() then
|
|
local LaserCode = Recce:GetLaserCode() -- (Not deleted when stopping with lasing).
|
|
self:F( { ClearingLaserCode = LaserCode } )
|
|
self.LaserCodesUsed[LaserCode] = nil
|
|
self.Recces[TargetUnit] = nil
|
|
end
|
|
end
|
|
|
|
-- If a specific lasercode is requested, we disable one active lase!
|
|
if LaserCodeRequested then
|
|
for TargetUnit, RecceData in pairs( self.Recces ) do -- We break after the first has been processed.
|
|
local Recce = RecceData -- Wrapper.Unit#UNIT
|
|
self:F( { TargetUnit = TargetUnit, Recce = Recce:GetName() } )
|
|
if Recce:IsLasing() then
|
|
-- When a Recce is lasing, we switch the lasing off, and clear the references to the lasing in the DESIGNATE class.
|
|
Recce:LaseOff() -- Switch off the lasing.
|
|
local LaserCode = Recce:GetLaserCode() -- (Not deleted when stopping with lasing).
|
|
self:F( { ClearingLaserCode = LaserCode } )
|
|
self.LaserCodesUsed[LaserCode] = nil
|
|
self.Recces[TargetUnit] = nil
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
if self.AutoLase or ( not self.AutoLase and ( self.LaseStart + Duration >= timer.getTime() ) ) then
|
|
|
|
TargetSetUnit:ForEachUnitPerThreatLevel( 10, 0,
|
|
--- @param Wrapper.Unit#UNIT SmokeUnit
|
|
function( TargetUnit )
|
|
|
|
self:F( { TargetUnit = TargetUnit:GetName() } )
|
|
|
|
if MarkingCount < self.MaximumMarkings then
|
|
|
|
if TargetUnit:IsAlive() then
|
|
|
|
local Recce = self.Recces[TargetUnit]
|
|
|
|
if not Recce then
|
|
|
|
self:F( "Lasing..." )
|
|
--self.RecceSet:Flush( self)
|
|
|
|
for RecceGroupID, RecceGroup in pairs( self.RecceSet:GetSet() ) do
|
|
for UnitID, UnitData in pairs( RecceGroup:GetUnits() or {} ) do
|
|
|
|
local RecceUnit = UnitData -- Wrapper.Unit#UNIT
|
|
local RecceUnitDesc = RecceUnit:GetDesc()
|
|
--self:F( { RecceUnit = RecceUnit:GetName(), RecceDescription = RecceUnitDesc } )
|
|
|
|
if RecceUnit:IsLasing() == false then
|
|
--self:F( { IsDetected = RecceUnit:IsDetected( TargetUnit ), IsLOS = RecceUnit:IsLOS( TargetUnit ) } )
|
|
|
|
if RecceUnit:IsDetected( TargetUnit ) and RecceUnit:IsLOS( TargetUnit ) then
|
|
|
|
local LaserCodeIndex = math.random( 1, #self.LaserCodes )
|
|
local LaserCode = self.LaserCodes[LaserCodeIndex]
|
|
--self:F( { LaserCode = LaserCode, LaserCodeUsed = self.LaserCodesUsed[LaserCode] } )
|
|
|
|
if LaserCodeRequested and LaserCodeRequested ~= LaserCode then
|
|
LaserCode = LaserCodeRequested
|
|
LaserCodeRequested = nil
|
|
end
|
|
|
|
if not self.LaserCodesUsed[LaserCode] then
|
|
|
|
self.LaserCodesUsed[LaserCode] = LaserCodeIndex
|
|
local Spot = RecceUnit:LaseUnit( TargetUnit, LaserCode, Duration )
|
|
local AttackSet = self.AttackSet
|
|
local DesignateName = self.DesignateName
|
|
|
|
function Spot:OnAfterDestroyed( From, Event, To )
|
|
self.Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() .. " destroyed. " .. TargetSetUnit:Count() .. " targets left.",
|
|
5, AttackSet, self.DesignateName )
|
|
end
|
|
|
|
self.Recces[TargetUnit] = RecceUnit
|
|
-- OK. We have assigned for the Recce a TargetUnit. We can exit the function.
|
|
MarkingCount = MarkingCount + 1
|
|
local TargetUnitType = TargetUnit:GetTypeName()
|
|
RecceUnit:MessageToSetGroup( "Marking " .. TargetUnit:GetTypeName() .. " with laser " .. RecceUnit:GetSpot().LaserCode .. " for " .. Duration .. "s.",
|
|
10, self.AttackSet, DesignateName )
|
|
if not MarkedTypes[TargetUnitType] then
|
|
MarkedTypes[TargetUnitType] = true
|
|
--ReportTypes:Add(TargetUnitType)
|
|
end
|
|
--ReportLaserCodes:Add(RecceUnit.LaserCode)
|
|
return
|
|
end
|
|
else
|
|
--RecceUnit:MessageToSetGroup( "Can't mark " .. TargetUnit:GetTypeName(), 5, self.AttackSet )
|
|
end
|
|
else
|
|
-- The Recce is lasing, but the Target is not detected or within LOS. So stop lasing and send a report.
|
|
|
|
if not RecceUnit:IsDetected( TargetUnit ) or not RecceUnit:IsLOS( TargetUnit ) then
|
|
|
|
local Recce = self.Recces[TargetUnit] -- Wrapper.Unit#UNIT
|
|
|
|
if Recce then
|
|
Recce:LaseOff()
|
|
Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() "out of LOS. Cancelling lase!", 10, self.AttackSet, self.DesignateName )
|
|
end
|
|
else
|
|
--MarkingCount = MarkingCount + 1
|
|
local TargetUnitType = TargetUnit:GetTypeName()
|
|
if not MarkedTypes[TargetUnitType] then
|
|
MarkedTypes[TargetUnitType] = true
|
|
--ReportTypes:Add(TargetUnitType)
|
|
end
|
|
--ReportLaserCodes:Add(RecceUnit.LaserCode)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
else
|
|
MarkingCount = MarkingCount + 1
|
|
local TargetUnitType = TargetUnit:GetTypeName()
|
|
if not MarkedTypes[TargetUnitType] then
|
|
MarkedTypes[TargetUnitType] = true
|
|
--ReportTypes:Add(TargetUnitType)
|
|
end
|
|
--ReportLaserCodes:Add(Recce.LaserCode)
|
|
Recce:MessageToSetGroup( self.DesignateName .. ": Marking " .. TargetUnit:GetTypeName() .. " with laser " .. Recce.LaserCode .. ".", 10, self.AttackSet )
|
|
end
|
|
end
|
|
end
|
|
end
|
|
)
|
|
|
|
--local MarkedTypesText = ReportTypes:Text(', ')
|
|
--local MarkedLaserCodesText = ReportLaserCodes:Text(', ')
|
|
--self.CC:GetPositionable():MessageToSetGroup( "Marking " .. MarkingCount .. " x " .. MarkedTypesText .. ", code " .. MarkedLaserCodesText .. ".", 5, self.AttackSet, self.DesignateName )
|
|
|
|
self:__Lasing( -self.LaseDuration, Index, Duration, LaserCodeRequested )
|
|
|
|
self:SetDesignateMenu()
|
|
|
|
else
|
|
self:LaseOff( Index )
|
|
end
|
|
|
|
end
|
|
|
|
---
|
|
-- @param #DESIGNATE self
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:onafterLaseOff( From, Event, To, Index )
|
|
|
|
local CC = self.CC:GetPositionable()
|
|
|
|
if CC then
|
|
CC:MessageToSetGroup( "Stopped lasing.", 5, self.AttackSet, self.DesignateName )
|
|
end
|
|
|
|
local DetectedItem = self.Detection:GetDetectedItemByIndex( Index )
|
|
local TargetSetUnit = self.Detection:GetDetectedItemSet( DetectedItem )
|
|
|
|
local Recces = self.Recces
|
|
|
|
for TargetID, RecceData in pairs( Recces ) do
|
|
local Recce = RecceData -- Wrapper.Unit#UNIT
|
|
Recce:MessageToSetGroup( "Stopped lasing " .. Recce:GetSpot().Target:GetTypeName() .. ".", 5, self.AttackSet, self.DesignateName )
|
|
Recce:LaseOff()
|
|
end
|
|
|
|
Recces = nil
|
|
self.Recces = {}
|
|
self.LaserCodesUsed = {}
|
|
|
|
self.Designating[Index] = string.gsub( self.Designating[Index], "L", "" )
|
|
self:SetDesignateMenu()
|
|
end
|
|
|
|
|
|
---
|
|
-- @param #DESIGNATE self
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:onafterSmoke( From, Event, To, Index, Color )
|
|
|
|
local DetectedItem = self.Detection:GetDetectedItemByIndex( Index )
|
|
local TargetSetUnit = self.Detection:GetDetectedItemSet( DetectedItem )
|
|
local TargetSetUnitCount = TargetSetUnit:Count()
|
|
|
|
local MarkedCount = 0
|
|
|
|
TargetSetUnit:ForEachUnitPerThreatLevel( 10, 0,
|
|
--- @param Wrapper.Unit#UNIT SmokeUnit
|
|
function( SmokeUnit )
|
|
|
|
if MarkedCount < self.MaximumMarkings then
|
|
|
|
MarkedCount = MarkedCount + 1
|
|
|
|
self:F( "Smoking ..." )
|
|
|
|
local RecceGroup = self.RecceSet:FindNearestGroupFromPointVec2(SmokeUnit:GetPointVec2())
|
|
local RecceUnit = RecceGroup:GetUnit( 1 ) -- Wrapper.Unit#UNIT
|
|
|
|
if RecceUnit then
|
|
|
|
RecceUnit:MessageToSetGroup( "Smoking " .. SmokeUnit:GetTypeName() .. ".", 5, self.AttackSet, self.DesignateName )
|
|
|
|
if SmokeUnit:IsAlive() then
|
|
SmokeUnit:Smoke( Color, 50, 2 )
|
|
end
|
|
|
|
self.MarkScheduler:Schedule( self,
|
|
function()
|
|
self:DoneSmoking( Index )
|
|
end, {}, math.random( 180, 240 )
|
|
)
|
|
end
|
|
end
|
|
end
|
|
)
|
|
|
|
|
|
end
|
|
|
|
--- Illuminating
|
|
-- @param #DESIGNATE self
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:onafterIlluminate( From, Event, To, Index )
|
|
|
|
local DetectedItem = self.Detection:GetDetectedItemByIndex( Index )
|
|
local TargetSetUnit = self.Detection:GetDetectedItemSet( DetectedItem )
|
|
local TargetUnit = TargetSetUnit:GetFirst()
|
|
|
|
if TargetUnit then
|
|
local RecceGroup = self.RecceSet:FindNearestGroupFromPointVec2(TargetUnit:GetPointVec2())
|
|
local RecceUnit = RecceGroup:GetUnit( 1 )
|
|
if RecceUnit then
|
|
RecceUnit:MessageToSetGroup( "Illuminating " .. TargetUnit:GetTypeName() .. ".", 5, self.AttackSet, self.DesignateName )
|
|
if TargetUnit:IsAlive() then
|
|
-- Fire 2 illumination bombs at random locations.
|
|
TargetUnit:GetPointVec3():AddY(math.random( 350, 500) ):AddX(math.random(-50,50) ):AddZ(math.random(-50,50) ):IlluminationBomb()
|
|
TargetUnit:GetPointVec3():AddY(math.random( 350, 500) ):AddX(math.random(-50,50) ):AddZ(math.random(-50,50) ):IlluminationBomb()
|
|
end
|
|
self.MarkScheduler:Schedule( self,
|
|
function()
|
|
self:DoneIlluminating( Index )
|
|
end, {}, math.random( 60, 90 )
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
--- DoneSmoking
|
|
-- @param #DESIGNATE self
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:onafterDoneSmoking( From, Event, To, Index )
|
|
|
|
self.Designating[Index] = string.gsub( self.Designating[Index], "S", "" )
|
|
self:SetDesignateMenu()
|
|
end
|
|
|
|
--- DoneIlluminating
|
|
-- @param #DESIGNATE self
|
|
-- @return #DESIGNATE
|
|
function DESIGNATE:onafterDoneIlluminating( From, Event, To, Index )
|
|
|
|
self.Designating[Index] = string.gsub( self.Designating[Index], "I", "" )
|
|
self:SetDesignateMenu()
|
|
end
|
|
|
|
end
|
|
|
|
|