mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Working version of the DETECTION classes
This commit is contained in:
5
Moose Development/Dcs/DCStrigger.lua
Normal file
5
Moose Development/Dcs/DCStrigger.lua
Normal file
@@ -0,0 +1,5 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- @module DCStrigger
|
||||
|
||||
|
||||
trigger = {} --#timer
|
||||
@@ -157,6 +157,7 @@ function AIRBASEPOLICE_BASE:_AirbaseMonitor()
|
||||
self:SetState( self, "Taxi", true )
|
||||
end
|
||||
|
||||
-- TODO: GetVelocityKMH function usage
|
||||
local VelocityVec3 = Client:GetVelocity()
|
||||
local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec
|
||||
local Velocity = Velocity * 3.6 -- now it is in km/h.
|
||||
|
||||
@@ -55,8 +55,9 @@
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- ### Author: FlightControl
|
||||
--
|
||||
-- @module Base
|
||||
-- @author FlightControl
|
||||
|
||||
|
||||
|
||||
@@ -131,8 +132,7 @@ function BASE:Inherit( Child, Parent )
|
||||
setmetatable( Child, Parent )
|
||||
Child.__index = Child
|
||||
end
|
||||
--Child.ClassName = Child.ClassName .. '.' .. Child.ClassID
|
||||
self:T( 'Inherited from ' .. Parent.ClassName )
|
||||
--self:T( 'Inherited from ' .. Parent.ClassName )
|
||||
return Child
|
||||
end
|
||||
|
||||
@@ -140,7 +140,7 @@ end
|
||||
-- @param #BASE self
|
||||
-- @param #BASE Child is the Child class from which the Parent class needs to be retrieved.
|
||||
-- @return #BASE
|
||||
function BASE:Inherited( Child )
|
||||
function BASE:GetParent( Child )
|
||||
local Parent = getmetatable( Child )
|
||||
-- env.info('Inherited class of ' .. Child.ClassName .. ' is ' .. Parent.ClassName )
|
||||
return Parent
|
||||
@@ -338,11 +338,9 @@ function BASE:SetState( Object, StateName, State )
|
||||
|
||||
local ClassNameAndID = Object:GetClassNameAndID()
|
||||
|
||||
if not self.States[ClassNameAndID] then
|
||||
self.States[ClassNameAndID] = {}
|
||||
end
|
||||
self.States[ClassNameAndID] = self.States[ClassNameAndID] or {}
|
||||
self.States[ClassNameAndID][StateName] = State
|
||||
self:F2( { ClassNameAndID, StateName, State } )
|
||||
self:T2( { ClassNameAndID, StateName, State } )
|
||||
|
||||
return self.States[ClassNameAndID][StateName]
|
||||
end
|
||||
@@ -353,7 +351,7 @@ function BASE:GetState( Object, StateName )
|
||||
|
||||
if self.States[ClassNameAndID] then
|
||||
local State = self.States[ClassNameAndID][StateName]
|
||||
self:F2( { ClassNameAndID, StateName, State } )
|
||||
self:T2( { ClassNameAndID, StateName, State } )
|
||||
return State
|
||||
end
|
||||
|
||||
@@ -378,7 +376,7 @@ end
|
||||
-- When Moose is loaded statically, (as one file), tracing is switched off by default.
|
||||
-- So tracing must be switched on manually in your mission if you are using Moose statically.
|
||||
-- When moose is loading dynamically (for moose class development), tracing is switched on by default.
|
||||
-- @param BASE self
|
||||
-- @param #BASE self
|
||||
-- @param #boolean TraceOnOff Switch the tracing on or off.
|
||||
-- @usage
|
||||
-- -- Switch the tracing On
|
||||
@@ -390,6 +388,19 @@ function BASE:TraceOnOff( TraceOnOff )
|
||||
_TraceOnOff = TraceOnOff
|
||||
end
|
||||
|
||||
|
||||
--- Enquires if tracing is on (for the class).
|
||||
-- @param #BASE self
|
||||
-- @return #boolean
|
||||
function BASE:IsTrace()
|
||||
|
||||
if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--- Set trace level
|
||||
-- @param #BASE self
|
||||
-- @param #number Level
|
||||
|
||||
@@ -120,7 +120,6 @@ function DATABASE:AddUnit( DCSUnitName )
|
||||
|
||||
if not self.UNITS[DCSUnitName] then
|
||||
local UnitRegister = UNIT:Register( DCSUnitName )
|
||||
self:E( UnitRegister.UnitName )
|
||||
self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName )
|
||||
end
|
||||
|
||||
|
||||
@@ -34,16 +34,16 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 2) @{Detection#DETECTION_UNITGROUPS} class, extends @{Detection#DETECTION_BASE}
|
||||
-- 2) @{Detection#DETECTION_AREAS} class, extends @{Detection#DETECTION_BASE}
|
||||
-- ===============================================================================
|
||||
-- The @{Detection#DETECTION_UNITGROUPS} class will detect units within the battle zone for a list of @{Group}s detecting targets following (a) detection method(s),
|
||||
-- The @{Detection#DETECTION_AREAS} class will detect units within the battle zone for a list of @{Group}s detecting targets following (a) detection method(s),
|
||||
-- and will build a list (table) of @{Set#SET_UNIT}s containing the @{Unit#UNIT}s detected.
|
||||
-- The class is group the detected units within zones given a DetectedZoneRange parameter.
|
||||
-- A set with multiple detected zones will be created as there are groups of units detected.
|
||||
--
|
||||
-- 2.1) Retrieve the Detected Unit sets and Detected Zones
|
||||
-- -------------------------------------------------------
|
||||
-- The DetectedUnitSets methods are implemented in @{Detection#DECTECTION_BASE} and the DetectedZones methods is implemented in @{Detection#DETECTION_UNITGROUPS}.
|
||||
-- The DetectedUnitSets methods are implemented in @{Detection#DECTECTION_BASE} and the DetectedZones methods is implemented in @{Detection#DETECTION_AREAS}.
|
||||
--
|
||||
-- Retrieve the DetectedUnitSets with the method @{Detection#DETECTION_BASE.GetDetectedSets}(). A table will be return of @{Set#SET_UNIT}s.
|
||||
-- To understand the amount of sets created, use the method @{Detection#DETECTION_BASE.GetDetectedSetCount}().
|
||||
@@ -55,33 +55,36 @@
|
||||
--
|
||||
-- 1.4) Flare or Smoke detected units
|
||||
-- ----------------------------------
|
||||
-- Use the methods @{Detection#DETECTION_UNITGROUPS.FlareDetectedUnits}() or @{Detection#DETECTION_UNITGROUPS.SmokeDetectedUnits}() to flare or smoke the detected units when a new detection has taken place.
|
||||
-- Use the methods @{Detection#DETECTION_AREAS.FlareDetectedUnits}() or @{Detection#DETECTION_AREAS.SmokeDetectedUnits}() to flare or smoke the detected units when a new detection has taken place.
|
||||
--
|
||||
-- 1.5) Flare or Smoke detected zones
|
||||
-- ----------------------------------
|
||||
-- Use the methods @{Detection#DETECTION_UNITGROUPS.FlareDetectedZones}() or @{Detection#DETECTION_UNITGROUPS.SmokeDetectedZones}() to flare or smoke the detected zones when a new detection has taken place.
|
||||
-- Use the methods @{Detection#DETECTION_AREAS.FlareDetectedZones}() or @{Detection#DETECTION_AREAS.SmokeDetectedZones}() to flare or smoke the detected zones when a new detection has taken place.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Contributions: Mechanic - Concept & Testing
|
||||
-- ### Authors: FlightControl : Design & Programming
|
||||
--
|
||||
-- @module Detection
|
||||
-- @author Mechanic : Concept & Testing
|
||||
-- @author FlightControl : Design & Programming
|
||||
|
||||
|
||||
|
||||
--- DETECTION_BASE class
|
||||
-- @type DETECTION_BASE
|
||||
-- @field Group#GROUP DetectionGroups The GROUP in the Forward Air Controller role.
|
||||
-- @field Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
|
||||
-- @field DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected.
|
||||
-- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects.
|
||||
-- @field #table DetectedObjectsIdentified Map of the DetectedObjects identified.
|
||||
-- @field #number DetectionRun
|
||||
-- @extends Base#BASE
|
||||
DETECTION_BASE = {
|
||||
ClassName = "DETECTION_BASE",
|
||||
DetectionGroups = nil,
|
||||
DetectionSetGroup = nil,
|
||||
DetectionRange = nil,
|
||||
DetectedObjects = {},
|
||||
DetectionRun = 0,
|
||||
DetectedObjectsIdentified = {},
|
||||
}
|
||||
|
||||
--- @type DETECTION_BASE.DetectedObjects
|
||||
@@ -96,15 +99,15 @@ DETECTION_BASE = {
|
||||
|
||||
--- DETECTION constructor.
|
||||
-- @param #DETECTION_BASE self
|
||||
-- @param Group#GROUP DetectionGroups The GROUP in the Forward Air Controller role.
|
||||
-- @param Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
|
||||
-- @param DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected.
|
||||
-- @return #DETECTION_BASE self
|
||||
function DETECTION_BASE:New( DetectionGroups, DetectionRange )
|
||||
function DETECTION_BASE:New( DetectionSetGroup, DetectionRange )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
|
||||
self.DetectionGroups = DetectionGroups
|
||||
self.DetectionSetGroup = DetectionSetGroup
|
||||
self.DetectionRange = DetectionRange
|
||||
|
||||
self:InitDetectVisual( false )
|
||||
@@ -176,16 +179,62 @@ function DETECTION_BASE:InitDetectDLINK( DetectDLINK )
|
||||
self.DetectDLINK = DetectDLINK
|
||||
end
|
||||
|
||||
--- Determines if a detected object has already been identified during detection processing.
|
||||
-- @param #DETECTION_BASE self
|
||||
-- @param #DETECTION_BASE.DetectedObject DetectedObject
|
||||
-- @return #boolean true if already identified.
|
||||
function DETECTION_BASE:IsDetectedObjectIdentified( DetectedObject )
|
||||
self:F3( DetectedObject.Name )
|
||||
|
||||
local DetectedObjectName = DetectedObject.Name
|
||||
local DetectedObjectIdentified = self.DetectedObjectsIdentified[DetectedObjectName] == true
|
||||
self:T3( DetectedObjectIdentified )
|
||||
return DetectedObjectIdentified
|
||||
end
|
||||
|
||||
--- Identifies a detected object during detection processing.
|
||||
-- @param #DETECTION_BASE self
|
||||
-- @param #DETECTION_BASE.DetectedObject DetectedObject
|
||||
function DETECTION_BASE:IdentifyDetectedObject( DetectedObject )
|
||||
self:F( DetectedObject.Name )
|
||||
|
||||
local DetectedObjectName = DetectedObject.Name
|
||||
self.DetectedObjectsIdentified[DetectedObjectName] = true
|
||||
end
|
||||
|
||||
--- UnIdentify a detected object during detection processing.
|
||||
-- @param #DETECTION_BASE self
|
||||
-- @param #DETECTION_BASE.DetectedObject DetectedObject
|
||||
function DETECTION_BASE:UnIdentifyDetectedObject( DetectedObject )
|
||||
|
||||
local DetectedObjectName = DetectedObject.Name
|
||||
self.DetectedObjectsIdentified[DetectedObjectName] = false
|
||||
end
|
||||
|
||||
--- UnIdentify all detected objects during detection processing.
|
||||
-- @param #DETECTION_BASE self
|
||||
function DETECTION_BASE:UnIdentifyAllDetectedObjects()
|
||||
|
||||
self.DetectedObjectsIdentified = {} -- Table will be garbage collected.
|
||||
end
|
||||
|
||||
--- Gets a detected object with a given name.
|
||||
-- @param #DETECTION_BASE self
|
||||
-- @param #string ObjectName
|
||||
-- @return #DETECTION_BASE.DetectedObject
|
||||
function DETECTION_BASE:GetDetectedObject( ObjectName )
|
||||
self:F( ObjectName )
|
||||
self:F3( ObjectName )
|
||||
|
||||
if ObjectName then
|
||||
local DetectedObject = self.DetectedObjects[ObjectName]
|
||||
return DetectedObject
|
||||
|
||||
-- Only return detected objects that are alive!
|
||||
local DetectedUnit = UNIT:FindByName( ObjectName )
|
||||
if DetectedUnit and DetectedUnit:IsAlive() then
|
||||
if self:IsDetectedObjectIdentified( DetectedObject ) == false then
|
||||
return DetectedObject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
@@ -226,10 +275,10 @@ end
|
||||
--- Get the detection Groups.
|
||||
-- @param #DETECTION_BASE self
|
||||
-- @return Group#GROUP
|
||||
function DETECTION_BASE:GetDetectionGroups()
|
||||
function DETECTION_BASE:GetDetectionSetGroup()
|
||||
|
||||
local DetectionGroups = self.DetectionGroups
|
||||
return DetectionGroups
|
||||
local DetectionSetGroup = self.DetectionSetGroup
|
||||
return DetectionSetGroup
|
||||
end
|
||||
|
||||
--- Make a DetectionSet table. This function will be overridden in the derived clsses.
|
||||
@@ -242,6 +291,7 @@ function DETECTION_BASE:CreateDetectionSets()
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Schedule the DETECTION construction.
|
||||
-- @param #DETECTION_BASE self
|
||||
-- @param #number DelayTime The delay in seconds to wait the reporting.
|
||||
@@ -263,167 +313,179 @@ end
|
||||
function DETECTION_BASE:_DetectionScheduler( SchedulerName )
|
||||
self:F2( { SchedulerName } )
|
||||
|
||||
self.DetectedObjects = {}
|
||||
self.DetectionRun = self.DetectionRun + 1
|
||||
|
||||
if self.DetectionGroups:IsAlive() then
|
||||
local DetectionGroupsName = self.DetectionGroups:GetName()
|
||||
|
||||
local DetectionDetectedTargets = self.DetectionGroups:GetDetectedTargets(
|
||||
self.DetectVisual,
|
||||
self.DetectOptical,
|
||||
self.DetectRadar,
|
||||
self.DetectIRST,
|
||||
self.DetectRWR,
|
||||
self.DetectDLINK
|
||||
)
|
||||
|
||||
for DetectionDetectedTargetID, DetectionDetectedTarget in pairs( DetectionDetectedTargets ) do
|
||||
local DetectionObject = DetectionDetectedTarget.object -- DCSObject#Object
|
||||
self:T2( DetectionObject )
|
||||
self:UnIdentifyAllDetectedObjects() -- Resets the DetectedObjectsIdentified table
|
||||
|
||||
for DetectionGroupID, DetectionGroupData in pairs( self.DetectionSetGroup:GetSet() ) do
|
||||
local DetectionGroup = DetectionGroupData -- Group#GROUP
|
||||
|
||||
if DetectionGroup:IsAlive() then
|
||||
|
||||
local DetectionGroupName = DetectionGroup:GetName()
|
||||
|
||||
if DetectionObject and DetectionObject:isExist() and DetectionObject.id_ < 50000000 then
|
||||
|
||||
local DetectionDetectedObjectName = DetectionObject:getName()
|
||||
|
||||
local DetectionDetectedObjectPositionVec3 = DetectionObject:getPoint()
|
||||
local DetectionGroupsPositionVec3 = self.DetectionGroups:GetPointVec3()
|
||||
|
||||
local Distance = ( ( DetectionDetectedObjectPositionVec3.x - DetectionGroupsPositionVec3.x )^2 +
|
||||
( DetectionDetectedObjectPositionVec3.y - DetectionGroupsPositionVec3.y )^2 +
|
||||
( DetectionDetectedObjectPositionVec3.z - DetectionGroupsPositionVec3.z )^2
|
||||
) ^ 0.5 / 1000
|
||||
|
||||
self:T2( { DetectionGroupsName, DetectionDetectedObjectName, Distance } )
|
||||
|
||||
if Distance <= self.DetectionRange then
|
||||
|
||||
if not self.DetectedObjects[DetectionDetectedObjectName] then
|
||||
self.DetectedObjects[DetectionDetectedObjectName] = {}
|
||||
end
|
||||
self.DetectedObjects[DetectionDetectedObjectName].Name = DetectionDetectedObjectName
|
||||
self.DetectedObjects[DetectionDetectedObjectName].Visible = DetectionDetectedTarget.visible
|
||||
self.DetectedObjects[DetectionDetectedObjectName].Type = DetectionDetectedTarget.type
|
||||
self.DetectedObjects[DetectionDetectedObjectName].Distance = DetectionDetectedTarget.distance
|
||||
self.DetectedObjects[DetectionDetectedObjectName].Identified = false -- This flag is used to control identification.
|
||||
else
|
||||
-- if beyond the DetectionRange then nullify...
|
||||
if self.DetectedObjects[DetectionDetectedObjectName] then
|
||||
self.DetectedObjects[DetectionDetectedObjectName] = nil
|
||||
local DetectionDetectedTargets = DetectionGroup:GetDetectedTargets(
|
||||
self.DetectVisual,
|
||||
self.DetectOptical,
|
||||
self.DetectRadar,
|
||||
self.DetectIRST,
|
||||
self.DetectRWR,
|
||||
self.DetectDLINK
|
||||
)
|
||||
|
||||
for DetectionDetectedTargetID, DetectionDetectedTarget in pairs( DetectionDetectedTargets ) do
|
||||
local DetectionObject = DetectionDetectedTarget.object -- DCSObject#Object
|
||||
self:T2( DetectionObject )
|
||||
|
||||
if DetectionObject and DetectionObject:isExist() and DetectionObject.id_ < 50000000 then
|
||||
|
||||
local DetectionDetectedObjectName = DetectionObject:getName()
|
||||
|
||||
local DetectionDetectedObjectPositionVec3 = DetectionObject:getPoint()
|
||||
local DetectionGroupPositionVec3 = DetectionGroup:GetPointVec3()
|
||||
|
||||
local Distance = ( ( DetectionDetectedObjectPositionVec3.x - DetectionGroupPositionVec3.x )^2 +
|
||||
( DetectionDetectedObjectPositionVec3.y - DetectionGroupPositionVec3.y )^2 +
|
||||
( DetectionDetectedObjectPositionVec3.z - DetectionGroupPositionVec3.z )^2
|
||||
) ^ 0.5 / 1000
|
||||
|
||||
self:T2( { DetectionGroupName, DetectionDetectedObjectName, Distance } )
|
||||
|
||||
if Distance <= self.DetectionRange then
|
||||
|
||||
if not self.DetectedObjects[DetectionDetectedObjectName] then
|
||||
self.DetectedObjects[DetectionDetectedObjectName] = {}
|
||||
end
|
||||
self.DetectedObjects[DetectionDetectedObjectName].Name = DetectionDetectedObjectName
|
||||
self.DetectedObjects[DetectionDetectedObjectName].Visible = DetectionDetectedTarget.visible
|
||||
self.DetectedObjects[DetectionDetectedObjectName].Type = DetectionDetectedTarget.type
|
||||
self.DetectedObjects[DetectionDetectedObjectName].Distance = DetectionDetectedTarget.distance
|
||||
else
|
||||
-- if beyond the DetectionRange then nullify...
|
||||
if self.DetectedObjects[DetectionDetectedObjectName] then
|
||||
self.DetectedObjects[DetectionDetectedObjectName] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:T2( self.DetectedObjects )
|
||||
|
||||
-- okay, now we have a list of detected object names ...
|
||||
-- Sort the table based on distance ...
|
||||
table.sort( self.DetectedObjects, function( a, b ) return a.Distance < b.Distance end )
|
||||
end
|
||||
|
||||
self:T2( self.DetectedObjects )
|
||||
|
||||
-- okay, now we have a list of detected object names ...
|
||||
-- Sort the table based on distance ...
|
||||
self:T( { "Sorting DetectedObjects table:", self.DetectedObjects } )
|
||||
table.sort( self.DetectedObjects, function( a, b ) return a.Distance < b.Distance end )
|
||||
self:T( { "Sorted Targets Table:", self.DetectedObjects } )
|
||||
|
||||
-- Now group the DetectedObjects table into SET_BASEs, evaluating the DetectionZoneRange.
|
||||
|
||||
if self.DetectedObjects then
|
||||
self:CreateDetectionSets()
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
if self.DetectedObjects then
|
||||
self:CreateDetectionSets()
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- DETECTION_UNITGROUPS class
|
||||
-- @type DETECTION_UNITGROUPS
|
||||
--- DETECTION_AREAS class
|
||||
-- @type DETECTION_AREAS
|
||||
-- @field DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
|
||||
-- @field #DETECTION_UNITGROUPS.DetectedAreas DetectedAreas A list of areas containing the set of @{Unit}s, @{Zone}s, the center @{Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
|
||||
-- @field #DETECTION_AREAS.DetectedAreas DetectedAreas A list of areas containing the set of @{Unit}s, @{Zone}s, the center @{Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
|
||||
-- @extends Detection#DETECTION_BASE
|
||||
DETECTION_UNITGROUPS = {
|
||||
ClassName = "DETECTION_UNITGROUPS",
|
||||
DETECTION_AREAS = {
|
||||
ClassName = "DETECTION_AREAS",
|
||||
DetectedAreas = { n = 0 },
|
||||
DetectionZoneRange = nil,
|
||||
}
|
||||
|
||||
--- @type DETECTION_UNITGROUPS.DetectedAreas
|
||||
-- @list <#DETECTION_UNITGROUPS.DetectedArea>
|
||||
--- @type DETECTION_AREAS.DetectedAreas
|
||||
-- @list <#DETECTION_AREAS.DetectedArea>
|
||||
|
||||
--- @type DETECTION_UNITGROUPS.DetectedArea
|
||||
--- @type DETECTION_AREAS.DetectedArea
|
||||
-- @field Set#SET_UNIT Set -- The Set of Units in the detected area.
|
||||
-- @field Zone#ZONE_UNIT Zone -- The Zone of the detected area.
|
||||
-- @field #boolean Changed Documents if the detected area has changes.
|
||||
-- @field #table Changes A list of the changes reported on the detected area. (It is up to the user of the detected area to consume those changes).
|
||||
-- @field #number AreaID -- The identifier of the detected area.
|
||||
-- @field #boolean FriendliesNearBy Indicates if there are friendlies within the detected area.
|
||||
|
||||
|
||||
--- DETECTION_UNITGROUPS constructor.
|
||||
-- @param Detection#DETECTION_UNITGROUPS self
|
||||
-- @param Group#GROUP DetectionGroups The GROUP in the Forward Air Controller role.
|
||||
--- DETECTION_AREAS constructor.
|
||||
-- @param Detection#DETECTION_AREAS self
|
||||
-- @param Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
|
||||
-- @param DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected.
|
||||
-- @param DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
|
||||
-- @return Detection#DETECTION_UNITGROUPS self
|
||||
function DETECTION_UNITGROUPS:New( DetectionGroups, DetectionRange, DetectionZoneRange )
|
||||
-- @return Detection#DETECTION_AREAS self
|
||||
function DETECTION_AREAS:New( DetectionSetGroup, DetectionRange, DetectionZoneRange )
|
||||
|
||||
-- Inherits from DETECTION_BASE
|
||||
local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionGroups, DetectionRange ) )
|
||||
local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionSetGroup, DetectionRange ) )
|
||||
|
||||
self.DetectionZoneRange = DetectionZoneRange
|
||||
|
||||
self:Schedule( 10, 30 )
|
||||
self._SmokeDetectedUnits = false
|
||||
self._FlareDetectedUnits = false
|
||||
self._SmokeDetectedZones = false
|
||||
self._FlareDetectedZones = false
|
||||
|
||||
self:Schedule( 0, 15 )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a detected @{#DETECTION_UNITGROUPS.DetectedArea}.
|
||||
--- Add a detected @{#DETECTION_AREAS.DetectedArea}.
|
||||
-- @param Set#SET_UNIT Set -- The Set of Units in the detected area.
|
||||
-- @param Zone#ZONE_UNIT Zone -- The Zone of the detected area.
|
||||
-- @return #DETECTION_UNITGROUPS.DetectedArea DetectedArea
|
||||
function DETECTION_UNITGROUPS:AddDetectedArea( Set, Zone )
|
||||
-- @return #DETECTION_AREAS.DetectedArea DetectedArea
|
||||
function DETECTION_AREAS:AddDetectedArea( Set, Zone )
|
||||
local DetectedAreas = self:GetDetectedAreas()
|
||||
DetectedAreas.n = self:GetDetectedAreaCount() + 1
|
||||
DetectedAreas[DetectedAreas.n] = {}
|
||||
local DetectedArea = DetectedAreas[DetectedAreas.n]
|
||||
DetectedArea.Set = Set
|
||||
DetectedArea.Zone = Zone
|
||||
DetectedArea.AreaID = #DetectedAreas
|
||||
DetectedArea.Removed = false
|
||||
DetectedArea.AreaID = DetectedAreas.n
|
||||
|
||||
return DetectedArea
|
||||
end
|
||||
|
||||
--- Remove a detected @{#DETECTION_UNITGROUPS.DetectedArea} with a given Index.
|
||||
-- @param #DETECTION_UNITGROUPS self
|
||||
--- Remove a detected @{#DETECTION_AREAS.DetectedArea} with a given Index.
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @param #number Index The Index of the detection are to be removed.
|
||||
-- @return #nil
|
||||
function DETECTION_UNITGROUPS:RemoveDetectedArea( Index )
|
||||
function DETECTION_AREAS:RemoveDetectedArea( Index )
|
||||
local DetectedAreas = self:GetDetectedAreas()
|
||||
local DetectedAreaCount = self:GetDetectedAreaCount()
|
||||
DetectedAreas[Index] = nil
|
||||
DetectedAreas.n = DetectedAreas.n - 1
|
||||
local DetectedArea = DetectedAreas[Index]
|
||||
local DetectedAreaSet = DetectedArea.Set
|
||||
DetectedArea[Index] = nil
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Get the detected @{#DETECTION_UNITGROUPS.DetectedAreas}.
|
||||
-- @param #DETECTION_UNITGROUPS self
|
||||
-- @return #DETECTION_UNITGROUPS.DetectedAreas DetectedAreas
|
||||
function DETECTION_UNITGROUPS:GetDetectedAreas()
|
||||
--- Get the detected @{#DETECTION_AREAS.DetectedAreas}.
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @return #DETECTION_AREAS.DetectedAreas DetectedAreas
|
||||
function DETECTION_AREAS:GetDetectedAreas()
|
||||
|
||||
local DetectedAreas = self.DetectedAreas
|
||||
return DetectedAreas
|
||||
end
|
||||
|
||||
--- Get the amount of @{#DETECTION_UNITGROUPS.DetectedAreas}.
|
||||
-- @param #DETECTION_UNITGROUPS self
|
||||
--- Get the amount of @{#DETECTION_AREAS.DetectedAreas}.
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @return #number DetectedAreaCount
|
||||
function DETECTION_UNITGROUPS:GetDetectedAreaCount()
|
||||
function DETECTION_AREAS:GetDetectedAreaCount()
|
||||
|
||||
local DetectedAreaCount = self.DetectedAreas.n
|
||||
return DetectedAreaCount
|
||||
end
|
||||
|
||||
--- Get the @{Set#SET_UNIT} of a detecttion area using a given numeric index.
|
||||
-- @param #DETECTION_UNITGROUPS self
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @param #number Index
|
||||
-- @return Set#SET_UNIT DetectedSet
|
||||
function DETECTION_UNITGROUPS:GetDetectedSet( Index )
|
||||
function DETECTION_AREAS:GetDetectedSet( Index )
|
||||
|
||||
local DetectedSetUnit = self.DetectedAreas[Index].Set
|
||||
if DetectedSetUnit then
|
||||
@@ -434,10 +496,10 @@ function DETECTION_UNITGROUPS:GetDetectedSet( Index )
|
||||
end
|
||||
|
||||
--- Get the @{Zone#ZONE_UNIT} of a detection area using a given numeric index.
|
||||
-- @param #DETECTION_UNITGROUPS self
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @param #number Index
|
||||
-- @return Zone#ZONE_UNIT DetectedZone
|
||||
function DETECTION_UNITGROUPS:GetDetectedZone( Index )
|
||||
function DETECTION_AREAS:GetDetectedZone( Index )
|
||||
|
||||
local DetectedZone = self.DetectedAreas[Index].Zone
|
||||
if DetectedZone then
|
||||
@@ -447,11 +509,107 @@ function DETECTION_UNITGROUPS:GetDetectedZone( Index )
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Background worker function to determine if there are friendlies nearby ...
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @param Unit#UNIT ReportUnit
|
||||
function DETECTION_AREAS:ReportFriendliesNearBy( ReportGroupData )
|
||||
self:F2()
|
||||
|
||||
local DetectedArea = ReportGroupData.DetectedArea -- Detection#DETECTION_AREAS.DetectedArea
|
||||
local DetectedSet = ReportGroupData.DetectedArea.Set
|
||||
local DetectedZone = ReportGroupData.DetectedArea.Zone
|
||||
local DetectedZoneUnit = DetectedZone.ZoneUNIT
|
||||
|
||||
DetectedArea.FriendliesNearBy = false
|
||||
|
||||
local SphereSearch = {
|
||||
id = world.VolumeType.SPHERE,
|
||||
params = {
|
||||
point = DetectedZoneUnit:GetPointVec3(),
|
||||
radius = 6000,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
--- @param DCSUnit#Unit FoundDCSUnit
|
||||
-- @param Group#GROUP ReportGroup
|
||||
-- @param Set#SET_GROUP ReportSetGroup
|
||||
local FindNearByFriendlies = function( FoundDCSUnit, ReportGroupData )
|
||||
|
||||
local DetectedArea = ReportGroupData.DetectedArea -- Detection#DETECTION_AREAS.DetectedArea
|
||||
local DetectedSet = ReportGroupData.DetectedArea.Set
|
||||
local DetectedZone = ReportGroupData.DetectedArea.Zone
|
||||
local DetectedZoneUnit = DetectedZone.ZoneUNIT -- Unit#UNIT
|
||||
local ReportSetGroup = ReportGroupData.ReportSetGroup
|
||||
|
||||
local EnemyCoalition = DetectedZoneUnit:GetCoalition()
|
||||
|
||||
local FoundUnitCoalition = FoundDCSUnit:getCoalition()
|
||||
local FoundUnitName = FoundDCSUnit:getName()
|
||||
local FoundUnitGroupName = FoundDCSUnit:getGroup():getName()
|
||||
local EnemyUnitName = DetectedZoneUnit:GetName()
|
||||
local FoundUnitInReportSetGroup = ReportSetGroup:FindGroup( FoundUnitGroupName ) ~= nil
|
||||
|
||||
self:T3( { "Friendlies search:", FoundUnitName, FoundUnitCoalition, EnemyUnitName, EnemyCoalition, FoundUnitInReportSetGroup } )
|
||||
|
||||
if FoundUnitCoalition ~= EnemyCoalition and FoundUnitInReportSetGroup == false then
|
||||
DetectedArea.FriendliesNearBy = true
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
world.searchObjects( Object.Category.UNIT, SphereSearch, FindNearByFriendlies, ReportGroupData )
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Returns if there are friendlies nearby the FAC units ...
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @return #boolean trhe if there are friendlies nearby
|
||||
function DETECTION_AREAS:IsFriendliesNearBy( DetectedArea )
|
||||
|
||||
self:T3( DetectedArea.FriendliesNearBy )
|
||||
return DetectedArea.FriendliesNearBy or false
|
||||
end
|
||||
|
||||
--- Calculate the maxium A2G threat level of the DetectedArea.
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @param #DETECTION_AREAS.DetectedArea DetectedArea
|
||||
function DETECTION_AREAS:CalculateThreatLevelA2G( DetectedArea )
|
||||
|
||||
local MaxThreatLevelA2G = 0
|
||||
for UnitName, UnitData in pairs( DetectedArea.Set:GetSet() ) do
|
||||
local ThreatUnit = UnitData -- Unit#UNIT
|
||||
local ThreatLevelA2G = ThreatUnit:GetThreatLevel()
|
||||
if ThreatLevelA2G > MaxThreatLevelA2G then
|
||||
MaxThreatLevelA2G = ThreatLevelA2G
|
||||
end
|
||||
end
|
||||
|
||||
self:T3( MaxThreatLevelA2G )
|
||||
DetectedArea.MaxThreatLevelA2G = MaxThreatLevelA2G
|
||||
|
||||
end
|
||||
|
||||
--- Returns the A2G threat level of the units in the DetectedArea
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @param #DETECTION_AREAS.DetectedArea DetectedArea
|
||||
-- @return #number a scale from 0 to 10.
|
||||
function DETECTION_AREAS:GetTreatLevelA2G( DetectedArea )
|
||||
|
||||
self:T3( DetectedArea.MaxThreatLevelA2G )
|
||||
return DetectedArea.MaxThreatLevelA2G
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Smoke the detected units
|
||||
-- @param #DETECTION_UNITGROUPS self
|
||||
-- @return #DETECTION_UNITGROUPS self
|
||||
function DETECTION_UNITGROUPS:SmokeDetectedUnits()
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @return #DETECTION_AREAS self
|
||||
function DETECTION_AREAS:SmokeDetectedUnits()
|
||||
self:F2()
|
||||
|
||||
self._SmokeDetectedUnits = true
|
||||
@@ -459,9 +617,9 @@ function DETECTION_UNITGROUPS:SmokeDetectedUnits()
|
||||
end
|
||||
|
||||
--- Flare the detected units
|
||||
-- @param #DETECTION_UNITGROUPS self
|
||||
-- @return #DETECTION_UNITGROUPS self
|
||||
function DETECTION_UNITGROUPS:FlareDetectedUnits()
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @return #DETECTION_AREAS self
|
||||
function DETECTION_AREAS:FlareDetectedUnits()
|
||||
self:F2()
|
||||
|
||||
self._FlareDetectedUnits = true
|
||||
@@ -469,9 +627,9 @@ function DETECTION_UNITGROUPS:FlareDetectedUnits()
|
||||
end
|
||||
|
||||
--- Smoke the detected zones
|
||||
-- @param #DETECTION_UNITGROUPS self
|
||||
-- @return #DETECTION_UNITGROUPS self
|
||||
function DETECTION_UNITGROUPS:SmokeDetectedZones()
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @return #DETECTION_AREAS self
|
||||
function DETECTION_AREAS:SmokeDetectedZones()
|
||||
self:F2()
|
||||
|
||||
self._SmokeDetectedZones = true
|
||||
@@ -479,59 +637,181 @@ function DETECTION_UNITGROUPS:SmokeDetectedZones()
|
||||
end
|
||||
|
||||
--- Flare the detected zones
|
||||
-- @param #DETECTION_UNITGROUPS self
|
||||
-- @return #DETECTION_UNITGROUPS self
|
||||
function DETECTION_UNITGROUPS:FlareDetectedZones()
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @return #DETECTION_AREAS self
|
||||
function DETECTION_AREAS:FlareDetectedZones()
|
||||
self:F2()
|
||||
|
||||
self._FlareDetectedZones = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a change to the detected zone.
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @param #DETECTION_AREAS.DetectedArea DetectedArea
|
||||
-- @param #string ChangeCode
|
||||
-- @return #DETECTION_AREAS self
|
||||
function DETECTION_AREAS:AddChangeArea( DetectedArea, ChangeCode, AreaUnitType )
|
||||
|
||||
DetectedArea.Changed = true
|
||||
local AreaID = DetectedArea.AreaID
|
||||
|
||||
DetectedArea.Changes = DetectedArea.Changes or {}
|
||||
DetectedArea.Changes[ChangeCode] = DetectedArea.Changes[ChangeCode] or {}
|
||||
DetectedArea.Changes[ChangeCode].AreaID = AreaID
|
||||
DetectedArea.Changes[ChangeCode].AreaUnitType = AreaUnitType
|
||||
|
||||
self:T( { "Change on Detection Area:", DetectedArea.AreaID, ChangeCode, AreaUnitType } )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Add a change to the detected zone.
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @param #DETECTION_AREAS.DetectedArea DetectedArea
|
||||
-- @param #string ChangeCode
|
||||
-- @param #string ChangeUnitType
|
||||
-- @return #DETECTION_AREAS self
|
||||
function DETECTION_AREAS:AddChangeUnit( DetectedArea, ChangeCode, ChangeUnitType )
|
||||
|
||||
DetectedArea.Changed = true
|
||||
local AreaID = DetectedArea.AreaID
|
||||
|
||||
DetectedArea.Changes = DetectedArea.Changes or {}
|
||||
DetectedArea.Changes[ChangeCode] = DetectedArea.Changes[ChangeCode] or {}
|
||||
DetectedArea.Changes[ChangeCode][ChangeUnitType] = DetectedArea.Changes[ChangeCode][ChangeUnitType] or 0
|
||||
DetectedArea.Changes[ChangeCode][ChangeUnitType] = DetectedArea.Changes[ChangeCode][ChangeUnitType] + 1
|
||||
DetectedArea.Changes[ChangeCode].AreaID = AreaID
|
||||
|
||||
self:T( { "Change on Detection Area:", DetectedArea.AreaID, ChangeCode, ChangeUnitType } )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Make text documenting the changes of the detected zone.
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @param #DETECTION_AREAS.DetectedArea DetectedArea
|
||||
-- @return #string The Changes text
|
||||
function DETECTION_AREAS:GetChangeText( DetectedArea )
|
||||
self:F( DetectedArea )
|
||||
|
||||
local MT = {}
|
||||
|
||||
for ChangeCode, ChangeData in pairs( DetectedArea.Changes ) do
|
||||
|
||||
if ChangeCode == "AA" then
|
||||
MT[#MT+1] = "Detected new area " .. ChangeData.AreaID .. ". The center target is a " .. ChangeData.AreaUnitType .. "."
|
||||
end
|
||||
|
||||
if ChangeCode == "RAU" then
|
||||
MT[#MT+1] = "Changed area " .. ChangeData.AreaID .. ". Removed the center target " .. ChangeData.AreaUnitType "."
|
||||
end
|
||||
|
||||
if ChangeCode == "AAU" then
|
||||
MT[#MT+1] = "Changed area " .. ChangeData.AreaID .. ". The new center target is a " .. ChangeData.AreaUnitType "."
|
||||
end
|
||||
|
||||
if ChangeCode == "RA" then
|
||||
MT[#MT+1] = "Removed old area " .. ChangeData.AreaID .. ". No more targets in this area."
|
||||
end
|
||||
|
||||
if ChangeCode == "AU" then
|
||||
local MTUT = {}
|
||||
for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do
|
||||
if ChangeUnitType ~= "AreaID" then
|
||||
MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType
|
||||
end
|
||||
end
|
||||
MT[#MT+1] = "Detected for area " .. ChangeData.AreaID .. " new target(s) " .. table.concat( MTUT, ", " ) .. "."
|
||||
end
|
||||
|
||||
if ChangeCode == "RU" then
|
||||
local MTUT = {}
|
||||
for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do
|
||||
if ChangeUnitType ~= "AreaID" then
|
||||
MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType
|
||||
end
|
||||
end
|
||||
MT[#MT+1] = "Removed for area " .. ChangeData.AreaID .. " invisible or destroyed target(s) " .. table.concat( MTUT, ", " ) .. "."
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return table.concat( MT, "\n" )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Accepts changes from the detected zone.
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @param #DETECTION_AREAS.DetectedArea DetectedArea
|
||||
-- @return #DETECTION_AREAS self
|
||||
function DETECTION_AREAS:AcceptChanges( DetectedArea )
|
||||
|
||||
DetectedArea.Changed = false
|
||||
DetectedArea.Changes = {}
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Make a DetectionSet table. This function will be overridden in the derived clsses.
|
||||
-- @param #DETECTION_UNITGROUPS self
|
||||
-- @return #DETECTION_UNITGROUPS self
|
||||
function DETECTION_UNITGROUPS:CreateDetectionSets()
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @return #DETECTION_AREAS self
|
||||
function DETECTION_AREAS:CreateDetectionSets()
|
||||
self:F2()
|
||||
|
||||
-- First go through all detected sets, and check if there are new detected units, match all existing detected units and identify undetected units.
|
||||
-- Regroup when needed, split groups when needed.
|
||||
for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do
|
||||
|
||||
local DetectedArea = DetectedAreaData -- #DETECTION_UNITGROUPS.DetectedArea
|
||||
local DetectedArea = DetectedAreaData -- #DETECTION_AREAS.DetectedArea
|
||||
if DetectedArea then
|
||||
|
||||
local DetectedSet = DetectedArea.Set
|
||||
local DetectedZone = DetectedArea.Zone
|
||||
DetectedSet:Flush()
|
||||
|
||||
-- first test if the center unit is detected in the detection area.
|
||||
|
||||
local AreaExists = false -- This flag will determine of the detected area is still existing.
|
||||
|
||||
local DetectedObject = self:GetDetectedObject( DetectedArea.Zone.ZoneUNIT.UnitName )
|
||||
self:T( DetectedObject )
|
||||
if DetectedObject then
|
||||
DetectedObject.Identified = true
|
||||
-- First test if the center unit is detected in the detection area.
|
||||
self:T3( DetectedArea.Zone.ZoneUNIT.UnitName )
|
||||
local DetectedZoneObject = self:GetDetectedObject( DetectedArea.Zone.ZoneUNIT.UnitName )
|
||||
self:T3( { "Detecting Zone Object", DetectedArea.AreaID, DetectedArea.Zone, DetectedZoneObject } )
|
||||
|
||||
if DetectedZoneObject then
|
||||
|
||||
--self:IdentifyDetectedObject( DetectedZoneObject )
|
||||
AreaExists = true
|
||||
self:T( { DetectedArea = DetectedArea.AreaID, "Detected Center Unit " .. DetectedArea.Zone.ZoneUNIT.UnitName } )
|
||||
|
||||
|
||||
|
||||
else
|
||||
-- The center object of the detected area has not been detected. Find an other unit of the set to become the center of the area.
|
||||
-- First remove the center unit from the set.
|
||||
DetectedSet:RemoveUnitsByName( DetectedArea.Zone.ZoneUNIT.UnitName )
|
||||
self:T( { DetectedArea = DetectedArea.AreaID, "Removed Center Unit " .. DetectedArea.Zone.ZoneUNIT.UnitName } )
|
||||
|
||||
self:AddChangeArea( DetectedArea, 'RAU', DetectedArea.Zone.ZoneUNIT:GetTypeName() )
|
||||
|
||||
-- Then search for a new center area unit within the set. Note that the new area unit candidate must be within the area range.
|
||||
for DetectedUnitName, DetectedUnitData in pairs( DetectedSet:GetSet() ) do
|
||||
|
||||
local DetectedUnit = DetectedUnitData -- Unit#UNIT
|
||||
local DetectedObject = self:GetDetectedObject( DetectedUnit.UnitName )
|
||||
local DetectedObject = self:GetDetectedObject( DetectedUnit.UnitName )
|
||||
|
||||
-- The DetectedObject can be nil when the DetectedUnit is not alive anymore or it is not in the DetectedObjects map.
|
||||
-- If the DetectedUnit was already identified, DetectedObject will be nil.
|
||||
if DetectedObject then
|
||||
if DetectedObject.Identified == false and DetectedUnit:IsAlive() then
|
||||
DetectedObject.Identified = true
|
||||
AreaExists = true
|
||||
-- Assign the Unit as the new center unit of the detected area.
|
||||
DetectedArea.Zone = ZONE_UNIT:New( DetectedUnit:GetName(), DetectedUnit, self.DetectionZoneRange )
|
||||
self:T( { DetectedArea = DetectedArea.AreaID, "New Center Unit " .. DetectedArea.Zone.ZoneUNIT.UnitName } )
|
||||
break
|
||||
end
|
||||
self:IdentifyDetectedObject( DetectedObject )
|
||||
AreaExists = true
|
||||
|
||||
-- Assign the Unit as the new center unit of the detected area.
|
||||
DetectedArea.Zone = ZONE_UNIT:New( DetectedUnit:GetName(), DetectedUnit, self.DetectionZoneRange )
|
||||
|
||||
self:AddChangeArea( DetectedArea, "AAU", DetectedArea.Zone.ZoneUNIT:GetTypeName() )
|
||||
|
||||
-- We don't need to add the DetectedObject to the area set, because it is already there ...
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -540,32 +820,44 @@ function DETECTION_UNITGROUPS:CreateDetectionSets()
|
||||
-- Note that the position of the area may have moved due to the center unit repositioning.
|
||||
-- If no center unit was identified, then the detected area does not exist anymore and should be deleted, as there are no valid units that can be the center unit.
|
||||
if AreaExists then
|
||||
|
||||
-- ok, we found the center unit of the area, now iterate through the detected area set and see which units are still within the center unit zone ...
|
||||
-- Those units within the zone are flagged as Identified.
|
||||
-- If a unit was not found in the set, remove it from the set. This may be added later to other existing or new sets.
|
||||
for DetectedUnitName, DetectedUnitData in pairs( DetectedSet:GetSet() ) do
|
||||
|
||||
local DetectedUnit = DetectedUnitData -- Unit#UNIT
|
||||
local DetectedObject = self:GetDetectedObject( DetectedUnit:GetName() )
|
||||
local DetectedObject = nil
|
||||
if DetectedUnit:IsAlive() then
|
||||
--self:E(DetectedUnit:GetName())
|
||||
DetectedObject = self:GetDetectedObject( DetectedUnit:GetName() )
|
||||
end
|
||||
if DetectedObject then
|
||||
if DetectedObject.Identified == false then
|
||||
if DetectedUnit:IsInZone( DetectedZone ) then
|
||||
DetectedObject.Identified = true
|
||||
self:T( { DetectedArea = DetectedArea.AreaID, "Unit in zone " .. DetectedUnit.UnitName } )
|
||||
else
|
||||
-- Not anymore in the zone. Remove from the set.
|
||||
DetectedSet:Remove( DetectedUnitName )
|
||||
self:T( { DetectedArea = DetectedArea.AreaID, "Unit not in zone " .. DetectedUnit.UnitName } )
|
||||
end
|
||||
|
||||
-- Check if the DetectedUnit is within the DetectedArea.Zone
|
||||
if DetectedUnit:IsInZone( DetectedArea.Zone ) then
|
||||
|
||||
-- Yes, the DetectedUnit is within the DetectedArea.Zone, no changes, DetectedUnit can be kept within the Set.
|
||||
self:IdentifyDetectedObject( DetectedObject )
|
||||
|
||||
else
|
||||
-- No, the DetectedUnit is not within the DetectedArea.Zone, remove DetectedUnit from the Set.
|
||||
DetectedSet:Remove( DetectedUnitName )
|
||||
self:AddChangeUnit( DetectedArea, "RU", DetectedUnit:GetTypeName() )
|
||||
end
|
||||
|
||||
else
|
||||
-- The detected object has not been found, delete from the Set!
|
||||
-- There was no DetectedObject, remove DetectedUnit from the Set.
|
||||
self:AddChangeUnit( DetectedArea, "RU", "destroyed target" )
|
||||
DetectedSet:Remove( DetectedUnitName )
|
||||
self:T( { DetectedArea = DetectedArea.AreaID, "Unit not found " .. DetectedUnit.UnitName } )
|
||||
|
||||
-- The DetectedObject has been identified, because it does not exist ...
|
||||
-- self:IdentifyDetectedObject( DetectedObject )
|
||||
end
|
||||
end
|
||||
else
|
||||
self:T( { DetectedArea = DetectedArea.AreaID, "Removed detected area " } )
|
||||
self:RemoveDetectedArea( DetectedAreaID )
|
||||
self:AddChangeArea( DetectedArea, "RA" )
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -579,72 +871,77 @@ function DETECTION_UNITGROUPS:CreateDetectionSets()
|
||||
-- - They can be added to a new detection area.
|
||||
for DetectedUnitName, DetectedObjectData in pairs( self.DetectedObjects ) do
|
||||
|
||||
local DetectedObject = DetectedObjectData -- #DETECTION_BASE.DetectedObject
|
||||
local DetectedObject = self:GetDetectedObject( DetectedUnitName )
|
||||
|
||||
if DetectedObject.Identified == false then
|
||||
-- We found an unidentified unit outside of any existing detection area.
|
||||
|
||||
local DetectedUnit = UNIT:FindByName( DetectedObjectData.Name ) -- Unit#UNIT
|
||||
|
||||
if DetectedUnit and DetectedUnit:IsAlive() then
|
||||
self:T( { "Search for " .. DetectedObjectData.Name, DetectedObjectData.Identified } )
|
||||
if DetectedObject then
|
||||
|
||||
local AddedToDetectionArea = false
|
||||
for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do
|
||||
|
||||
local DetectedArea = DetectedAreaData -- #DETECTION_UNITGROUPS.DetectedArea
|
||||
if DetectedArea then
|
||||
self:T( "Detection Area #" .. DetectedArea.AreaID )
|
||||
local DetectedSet = DetectedArea.Set
|
||||
local DetectedZone = DetectedArea.Zone -- Zone#ZONE_UNIT
|
||||
if DetectedUnit:IsInZone( DetectedZone ) then
|
||||
DetectedSet:AddUnit( DetectedUnit )
|
||||
AddedToDetectionArea = true
|
||||
DetectedObject.Identified = true
|
||||
self:T( "Detection Area #" .. DetectedArea.AreaID .. " added unit " .. DetectedUnit.UnitName )
|
||||
end
|
||||
-- We found an unidentified unit outside of any existing detection area.
|
||||
local DetectedUnit = UNIT:FindByName( DetectedUnitName ) -- Unit#UNIT
|
||||
|
||||
local AddedToDetectionArea = false
|
||||
|
||||
for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do
|
||||
|
||||
local DetectedArea = DetectedAreaData -- #DETECTION_AREAS.DetectedArea
|
||||
if DetectedArea then
|
||||
self:T( "Detection Area #" .. DetectedArea.AreaID )
|
||||
local DetectedSet = DetectedArea.Set
|
||||
if not self:IsDetectedObjectIdentified( DetectedObject ) and DetectedUnit:IsInZone( DetectedArea.Zone ) then
|
||||
self:IdentifyDetectedObject( DetectedObject )
|
||||
DetectedSet:AddUnit( DetectedUnit )
|
||||
AddedToDetectionArea = true
|
||||
self:AddChangeUnit( DetectedArea, "AU", DetectedUnit:GetTypeName() )
|
||||
end
|
||||
end
|
||||
if AddedToDetectionArea == false then
|
||||
-- New detection area
|
||||
local DetectedArea = self:AddDetectedArea(
|
||||
SET_UNIT:New(),
|
||||
ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange )
|
||||
)
|
||||
self:T( { "Added Detection Area #", DetectedArea.AreaID } )
|
||||
DetectedArea.Set:AddUnit( DetectedUnit )
|
||||
self:T( "Detection Area #" .. DetectedArea.AreaID .. " added unit " .. DetectedUnit.UnitName )
|
||||
DetectedObject.Identified = true
|
||||
end
|
||||
end
|
||||
|
||||
if AddedToDetectionArea == false then
|
||||
|
||||
-- New detection area
|
||||
local DetectedArea = self:AddDetectedArea(
|
||||
SET_UNIT:New(),
|
||||
ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange )
|
||||
)
|
||||
--self:E( DetectedArea.Zone.ZoneUNIT.UnitName )
|
||||
DetectedArea.Set:AddUnit( DetectedUnit )
|
||||
self:AddChangeArea( DetectedArea, "AA", DetectedUnit:GetTypeName() )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Now all the tests should have been build, now make some smoke and flares...
|
||||
-- We also report here the friendlies within the detected areas.
|
||||
|
||||
for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do
|
||||
|
||||
|
||||
local DetectedArea = DetectedAreaData -- #DETECTION_UNITGROUPS.DetectedArea
|
||||
local DetectedArea = DetectedAreaData -- #DETECTION_AREAS.DetectedArea
|
||||
local DetectedSet = DetectedArea.Set
|
||||
local DetectedZone = DetectedArea.Zone
|
||||
DetectedZone.ZoneUNIT:SmokeRed()
|
||||
|
||||
self:ReportFriendliesNearBy( { DetectedArea = DetectedArea, ReportSetGroup = self.DetectionSetGroup } ) -- Fill the Friendlies table
|
||||
self:CalculateThreatLevelA2G( DetectedArea ) -- Calculate A2G threat level
|
||||
|
||||
if DETECTION_AREAS._SmokeDetectedUnits or self._SmokeDetectedUnits then
|
||||
DetectedZone.ZoneUNIT:SmokeRed()
|
||||
end
|
||||
DetectedSet:ForEachUnit(
|
||||
--- @param Unit#UNIT DetectedUnit
|
||||
function( DetectedUnit )
|
||||
self:T( "Detected Set #" .. DetectedArea.AreaID .. ":" .. DetectedUnit:GetName() )
|
||||
if self._FlareDetectedUnits then
|
||||
DetectedUnit:FlareRed()
|
||||
end
|
||||
if self._SmokeDetectedUnits then
|
||||
DetectedUnit:SmokeRed()
|
||||
if DetectedUnit:IsAlive() then
|
||||
self:T( "Detected Set #" .. DetectedArea.AreaID .. ":" .. DetectedUnit:GetName() )
|
||||
if DETECTION_AREAS._FlareDetectedUnits or self._FlareDetectedUnits then
|
||||
DetectedUnit:FlareGreen()
|
||||
end
|
||||
if DETECTION_AREAS._SmokeDetectedUnits or self._SmokeDetectedUnits then
|
||||
DetectedUnit:SmokeGreen()
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
if self._FlareDetectedZones then
|
||||
if DETECTION_AREAS._FlareDetectedZones or self._FlareDetectedZones then
|
||||
DetectedZone:FlareZone( POINT_VEC3.SmokeColor.White, 30, math.random( 0,90 ) )
|
||||
end
|
||||
if self._SmokeDetectedZones then
|
||||
if DETECTION_AREAS._SmokeDetectedZones or self._SmokeDetectedZones then
|
||||
DetectedZone:SmokeZone( POINT_VEC3.SmokeColor.White, 30 )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
--- This module contains the DETECTION_MANAGER class and derived classes.
|
||||
-- @module DetectionManager
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -27,396 +26,479 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 2) @{DetectionManager#FAC_REPORTING} class, extends @{DetectionManager#DETECTION_MANAGER}
|
||||
-- ======================================================
|
||||
-- The @{DetectionManager#FAC_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{DetectionManager#DETECTION_MANAGER} class.
|
||||
-- 2) @{DetectionManager#DETECTION_REPORTING} class, extends @{DetectionManager#DETECTION_MANAGER}
|
||||
-- =========================================================================================
|
||||
-- The @{DetectionManager#DETECTION_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{DetectionManager#DETECTION_MANAGER} class.
|
||||
--
|
||||
-- 2.1) FAC_REPORTING constructor:
|
||||
-- 2.1) DETECTION_REPORTING constructor:
|
||||
-- -------------------------------
|
||||
-- The @{DetectionManager#FAC_REPORTING.New}() method creates a new FAC_REPORTING instance.
|
||||
-- The @{DetectionManager#DETECTION_REPORTING.New}() method creates a new DETECTION_REPORTING instance.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Contributions - Mechanic, Prof_Hilactic, FlightControl : Concept & Testing
|
||||
-- ### Author - FlightControl : Framework Design & Programming
|
||||
-- 3) @{#DETECTION_DISPATCHER} class, extends @{#DETECTION_MANAGER}
|
||||
-- ================================================================
|
||||
-- The @{#DETECTION_DISPATCHER} class implements the dynamic dispatching of tasks upon groups of detected units determined a @{Set} of FAC (groups).
|
||||
-- The FAC will detect units, will group them, and will dispatch @{Task}s to groups. Depending on the type of target detected, different tasks will be dispatched.
|
||||
-- Find a summary below describing for which situation a task type is created:
|
||||
--
|
||||
-- * **CAS Task**: Is created when there are enemy ground units within range of the FAC, while there are friendly units in the FAC perimeter.
|
||||
-- * **BAI Task**: Is created when there are enemy ground units within range of the FAC, while there are NO other friendly units within the FAC perimeter.
|
||||
-- * **SEAD Task**: Is created when there are enemy ground units wihtin range of the FAC, with air search radars.
|
||||
--
|
||||
-- Other task types will follow...
|
||||
--
|
||||
-- 3.1) DETECTION_DISPATCHER constructor:
|
||||
-- --------------------------------------
|
||||
-- The @{#DETECTION_DISPATCHER.New}() method creates a new DETECTION_DISPATCHER instance.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Contributions: Mechanic, Prof_Hilactic, FlightControl - Concept & Testing
|
||||
-- ### Author: FlightControl - Framework Design & Programming
|
||||
--
|
||||
-- @module DetectionManager
|
||||
|
||||
|
||||
|
||||
--- DETECTION_MANAGER class.
|
||||
-- @type DETECTION_MANAGER
|
||||
-- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to.
|
||||
-- @field Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects.
|
||||
-- @extends Base#BASE
|
||||
DETECTION_MANAGER = {
|
||||
ClassName = "DETECTION_MANAGER",
|
||||
SetGroup = nil,
|
||||
Detection = nil,
|
||||
}
|
||||
|
||||
--- FAC constructor.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @param Set#SET_GROUP SetGroup
|
||||
-- @param Detection#DETECTION_BASE Detection
|
||||
-- @return #DETECTION_MANAGER self
|
||||
function DETECTION_MANAGER:New( SetGroup, Detection )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- Detection#DETECTION_MANAGER
|
||||
do -- DETECTION MANAGER
|
||||
|
||||
self.SetGroup = SetGroup
|
||||
self.Detection = Detection
|
||||
--- DETECTION_MANAGER class.
|
||||
-- @type DETECTION_MANAGER
|
||||
-- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to.
|
||||
-- @field Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects.
|
||||
-- @extends Base#BASE
|
||||
DETECTION_MANAGER = {
|
||||
ClassName = "DETECTION_MANAGER",
|
||||
SetGroup = nil,
|
||||
Detection = nil,
|
||||
}
|
||||
|
||||
self:SetReportInterval( 60 )
|
||||
self:SetReportDisplayTime( 15 )
|
||||
--- FAC constructor.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @param Set#SET_GROUP SetGroup
|
||||
-- @param Detection#DETECTION_BASE Detection
|
||||
-- @return #DETECTION_MANAGER self
|
||||
function DETECTION_MANAGER:New( SetGroup, Detection )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the reporting time interval.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @param #number ReportInterval The interval in seconds when a report needs to be done.
|
||||
-- @return #DETECTION_MANAGER self
|
||||
function DETECTION_MANAGER:SetReportInterval( ReportInterval )
|
||||
self:F2()
|
||||
|
||||
self._ReportInterval = ReportInterval
|
||||
end
|
||||
|
||||
|
||||
--- Set the reporting message display time.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @param #number ReportDisplayTime The display time in seconds when a report needs to be done.
|
||||
-- @return #DETECTION_MANAGER self
|
||||
function DETECTION_MANAGER:SetReportDisplayTime( ReportDisplayTime )
|
||||
self:F2()
|
||||
|
||||
self._ReportDisplayTime = ReportDisplayTime
|
||||
end
|
||||
|
||||
--- Get the reporting message display time.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @return #number ReportDisplayTime The display time in seconds when a report needs to be done.
|
||||
function DETECTION_MANAGER:GetReportDisplayTime()
|
||||
self:F2()
|
||||
|
||||
return self._ReportDisplayTime
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Reports the detected items to the @{Set#SET_GROUP}.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @param Detection#DETECTION_BASE Detection
|
||||
-- @return #DETECTION_MANAGER self
|
||||
function DETECTION_MANAGER:ReportDetected( Detection )
|
||||
self:F2()
|
||||
|
||||
end
|
||||
|
||||
--- Schedule the FAC reporting.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @param #number DelayTime The delay in seconds to wait the reporting.
|
||||
-- @param #number ReportInterval The repeat interval in seconds for the reporting to happen repeatedly.
|
||||
-- @return #DETECTION_MANAGER self
|
||||
function DETECTION_MANAGER:Schedule( DelayTime, ReportInterval )
|
||||
self:F2()
|
||||
|
||||
self._ScheduleDelayTime = DelayTime
|
||||
|
||||
self:SetReportInterval( ReportInterval )
|
||||
|
||||
self.FacScheduler = SCHEDULER:New(self, self._FacScheduler, { self, "DetectionManager" }, self._ScheduleDelayTime, self._ReportInterval )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Report the detected @{Unit#UNIT}s detected within the @{Detection#DETECTION_BASE} object to the @{Set#SET_GROUP}s.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
function DETECTION_MANAGER:_FacScheduler( SchedulerName )
|
||||
self:F2( { SchedulerName } )
|
||||
|
||||
self.SetGroup:ForEachGroup(
|
||||
--- @param Group#GROUP Group
|
||||
function( Group )
|
||||
if Group:IsAlive() then
|
||||
return self:ProcessDetected( Group, self.Detection )
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- FAC_REPORTING
|
||||
|
||||
--- FAC_REPORTING class.
|
||||
-- @type FAC_REPORTING
|
||||
-- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to.
|
||||
-- @field Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects.
|
||||
-- @extends #DETECTION_MANAGER
|
||||
FAC_REPORTING = {
|
||||
ClassName = "FAC_REPORTING",
|
||||
}
|
||||
|
||||
|
||||
--- FAC_REPORTING constructor.
|
||||
-- @param #FAC_REPORTING self
|
||||
-- @param Set#SET_GROUP SetGroup
|
||||
-- @param Detection#DETECTION_UNITGROUPS Detection
|
||||
-- @return #FAC_REPORTING self
|
||||
function FAC_REPORTING:New( SetGroup, Detection )
|
||||
|
||||
-- Inherits from DETECTION_MANAGER
|
||||
local self = BASE:Inherit( self, DETECTION_MANAGER:New( SetGroup, Detection ) ) -- #FAC_REPORTING
|
||||
|
||||
self:Schedule( 5, 60 )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Creates a string of the detected items in a @{Detection}.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @param Set#SET_UNIT DetectedSet The detected Set created by the @{Detection#DETECTION_BASE} object.
|
||||
-- @return #DETECTION_MANAGER self
|
||||
function FAC_REPORTING:GetDetectedItemsText( DetectedSet )
|
||||
self:F2()
|
||||
|
||||
local MT = {} -- Message Text
|
||||
local UnitTypes = {}
|
||||
|
||||
for DetectedUnitID, DetectedUnitData in pairs( DetectedSet:GetSet() ) do
|
||||
local DetectedUnit = DetectedUnitData -- Unit#UNIT
|
||||
local UnitType = DetectedUnit:GetTypeName()
|
||||
|
||||
if not UnitTypes[UnitType] then
|
||||
UnitTypes[UnitType] = 1
|
||||
else
|
||||
UnitTypes[UnitType] = UnitTypes[UnitType] + 1
|
||||
end
|
||||
end
|
||||
|
||||
for UnitTypeID, UnitType in pairs( UnitTypes ) do
|
||||
MT[#MT+1] = UnitType .. " of " .. UnitTypeID
|
||||
end
|
||||
|
||||
return table.concat( MT, ", " )
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Reports the detected items to the @{Set#SET_GROUP}.
|
||||
-- @param #FAC_REPORTING self
|
||||
-- @param Group#GROUP Group The @{Group} object to where the report needs to go.
|
||||
-- @param Detection#DETECTION_UNITGROUPS Detection The detection created by the @{Detection#DETECTION_BASE} object.
|
||||
-- @return #boolean Return true if you want the reporting to continue... false will cancel the reporting loop.
|
||||
function FAC_REPORTING:ProcessDetected( Group, Detection )
|
||||
self:F2( Group )
|
||||
|
||||
self:E( Group )
|
||||
local DetectedMsg = {}
|
||||
for DetectedAreaID, DetectedAreaData in pairs( Detection:GetDetectedAreas() ) do
|
||||
local DetectedArea = DetectedAreaData -- Detection#DETECTION_UNITGROUPS.DetectedArea
|
||||
DetectedMsg[#DetectedMsg+1] = " - Group #" .. DetectedAreaID .. ": " .. self:GetDetectedItemsText( DetectedArea.Set )
|
||||
end
|
||||
local FACGroup = Detection:GetDetectionGroups()
|
||||
FACGroup:MessageToGroup( "Reporting detected target groups:\n" .. table.concat( DetectedMsg, "\n" ), self:GetReportDisplayTime(), Group )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
--- TASK_DISPATCHER
|
||||
|
||||
--- TASK_DISPATCHER class.
|
||||
-- @type TASK_DISPATCHER
|
||||
-- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to.
|
||||
-- @field Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects.
|
||||
-- @field Mission#MISSION Mission
|
||||
-- @field Group#GROUP CommandCenter
|
||||
-- @extends DetectionManager#DETECTION_MANAGER
|
||||
TASK_DISPATCHER = {
|
||||
ClassName = "TASK_DISPATCHER",
|
||||
Mission = nil,
|
||||
CommandCenter = nil,
|
||||
Detection = nil,
|
||||
}
|
||||
|
||||
|
||||
--- TASK_DISPATCHER constructor.
|
||||
-- @param #TASK_DISPATCHER self
|
||||
-- @param Set#SET_GROUP SetGroup
|
||||
-- @param Detection#DETECTION_BASE Detection
|
||||
-- @return #TASK_DISPATCHER self
|
||||
function TASK_DISPATCHER:New( Mission, CommandCenter, SetGroup, Detection )
|
||||
|
||||
-- Inherits from DETECTION_MANAGER
|
||||
local self = BASE:Inherit( self, DETECTION_MANAGER:New( SetGroup, Detection ) ) -- #TASK_DISPATCHER
|
||||
|
||||
self.Detection = Detection
|
||||
self.CommandCenter = CommandCenter
|
||||
self.Mission = Mission
|
||||
|
||||
self:Schedule( 30 )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Creates a SEAD task when there are targets for it.
|
||||
-- @param #TASK_DISPATCHER self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Detection#DETECTION_UNITGROUPS.DetectedArea DetectedArea
|
||||
-- @return #string Message explaining which task was added.
|
||||
function TASK_DISPATCHER:EvaluateTaskSEAD( Mission, DetectedArea )
|
||||
self:F( { Mission, DetectedArea.AreaID } )
|
||||
|
||||
local MT = {}
|
||||
|
||||
local DetectedSet = DetectedArea.Set
|
||||
local DetectedZone = DetectedArea.Zone
|
||||
|
||||
-- Determine if the set has radar targets. If it does, construct a SEAD task.
|
||||
local RadarCount = DetectedSet:HasRadar( Unit.RadarType.AS )
|
||||
DetectedArea.Tasks = DetectedArea.Tasks or {}
|
||||
self:E(RadarCount)
|
||||
if RadarCount > 0 then
|
||||
if not DetectedArea.Tasks.SEADTask then
|
||||
-- Here we're doing something advanced... We're copying the DetectedSet, but making a new Set only with Radar units in it.
|
||||
local TargetSetUnit = SET_UNIT:New():SetDatabase( DetectedSet )
|
||||
TargetSetUnit:FilterHasRadar( Unit.RadarType.AS )
|
||||
self:E( TargetSetUnit.Filter )
|
||||
TargetSetUnit:FilterStart()
|
||||
|
||||
local MenuText = "SEAD " .. self:GetDetectedItemsText( TargetSetUnit )
|
||||
MT[#MT+1] = " - " .. MenuText
|
||||
local Task = TASK_SEAD:New( Mission, MenuText, TargetSetUnit, DetectedZone )
|
||||
self.Mission:AddTask( Task )
|
||||
DetectedArea.Tasks.SEADTask = Task
|
||||
end
|
||||
else
|
||||
if DetectedArea.Tasks.SEADTask then
|
||||
-- Abort Task
|
||||
end
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- Detection#DETECTION_MANAGER
|
||||
|
||||
self.SetGroup = SetGroup
|
||||
self.Detection = Detection
|
||||
|
||||
self:SetReportInterval( 30 )
|
||||
self:SetReportDisplayTime( 25 )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
if #MT > 0 then
|
||||
return table.concat( MT, "," )
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates a CAS task when there are targets for it.
|
||||
-- @param #TASK_DISPATCHER self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Detection#DETECTION_UNITGROUPS.DetectedArea DetectedArea
|
||||
-- @return #string Message explaining which task was added.
|
||||
function TASK_DISPATCHER:EvaluateTaskCAS( Mission, DetectedArea )
|
||||
self:F2( { Mission, DetectedArea.AreaID } )
|
||||
|
||||
local MT = {}
|
||||
|
||||
local DetectedSet = DetectedArea.Set
|
||||
local DetectedZone = DetectedArea.Zone
|
||||
--- Set the reporting time interval.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @param #number ReportInterval The interval in seconds when a report needs to be done.
|
||||
-- @return #DETECTION_MANAGER self
|
||||
function DETECTION_MANAGER:SetReportInterval( ReportInterval )
|
||||
self:F2()
|
||||
|
||||
-- Determine if the set has radar targets. If it does, construct a SEAD task.
|
||||
local GroundUnitCount = DetectedSet:HasGroundUnits()
|
||||
DetectedArea.Tasks = DetectedArea.Tasks or {}
|
||||
if GroundUnitCount > 0 then
|
||||
if not DetectedArea.Tasks.CASTask then
|
||||
local MenuText = "CAS " .. self:GetDetectedItemsText( DetectedSet )
|
||||
MT[#MT+1] = " -" .. MenuText
|
||||
local Task = TASK_CAS:New( Mission, MenuText, DetectedSet , DetectedZone )
|
||||
self.Mission:AddTask( Task )
|
||||
DetectedArea.Tasks.CASTask = Task
|
||||
end
|
||||
else
|
||||
if DetectedArea.Tasks.CASTask then
|
||||
-- Abort Mission
|
||||
end
|
||||
self._ReportInterval = ReportInterval
|
||||
end
|
||||
|
||||
|
||||
--- Set the reporting message display time.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @param #number ReportDisplayTime The display time in seconds when a report needs to be done.
|
||||
-- @return #DETECTION_MANAGER self
|
||||
function DETECTION_MANAGER:SetReportDisplayTime( ReportDisplayTime )
|
||||
self:F2()
|
||||
|
||||
self._ReportDisplayTime = ReportDisplayTime
|
||||
end
|
||||
|
||||
--- Get the reporting message display time.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @return #number ReportDisplayTime The display time in seconds when a report needs to be done.
|
||||
function DETECTION_MANAGER:GetReportDisplayTime()
|
||||
self:F2()
|
||||
|
||||
return self._ReportDisplayTime
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Reports the detected items to the @{Set#SET_GROUP}.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @param Detection#DETECTION_BASE Detection
|
||||
-- @return #DETECTION_MANAGER self
|
||||
function DETECTION_MANAGER:ReportDetected( Detection )
|
||||
self:F2()
|
||||
|
||||
end
|
||||
|
||||
--- Schedule the FAC reporting.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @param #number DelayTime The delay in seconds to wait the reporting.
|
||||
-- @param #number ReportInterval The repeat interval in seconds for the reporting to happen repeatedly.
|
||||
-- @return #DETECTION_MANAGER self
|
||||
function DETECTION_MANAGER:Schedule( DelayTime, ReportInterval )
|
||||
self:F2()
|
||||
|
||||
self._ScheduleDelayTime = DelayTime
|
||||
|
||||
self:SetReportInterval( ReportInterval )
|
||||
|
||||
self.FacScheduler = SCHEDULER:New(self, self._FacScheduler, { self, "DetectionManager" }, self._ScheduleDelayTime, self._ReportInterval )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Report the detected @{Unit#UNIT}s detected within the @{Detection#DETECTION_BASE} object to the @{Set#SET_GROUP}s.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
function DETECTION_MANAGER:_FacScheduler( SchedulerName )
|
||||
self:F2( { SchedulerName } )
|
||||
|
||||
return self:ProcessDetected( self.Detection )
|
||||
|
||||
-- self.SetGroup:ForEachGroup(
|
||||
-- --- @param Group#GROUP Group
|
||||
-- function( Group )
|
||||
-- if Group:IsAlive() then
|
||||
-- return self:ProcessDetected( self.Detection )
|
||||
-- end
|
||||
-- end
|
||||
-- )
|
||||
|
||||
-- return true
|
||||
end
|
||||
|
||||
if #MT > 0 then
|
||||
return table.concat( MT, "," )
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates a string of the detected items in a @{Detection}.
|
||||
-- @param #TASK_DISPATCHER self
|
||||
-- @param Set#SET_UNIT DetectedSet The detected Set created by the @{Detection#DETECTION_BASE} object.
|
||||
-- @return #string The text
|
||||
function TASK_DISPATCHER:GetDetectedItemsText( DetectedSet )
|
||||
self:F2()
|
||||
|
||||
local MT = {} -- Message Text
|
||||
local UnitTypes = {}
|
||||
|
||||
for DetectedUnitID, DetectedUnitData in pairs( DetectedSet:GetSet() ) do
|
||||
local DetectedUnit = DetectedUnitData -- Unit#UNIT
|
||||
local UnitType = DetectedUnit:GetTypeName()
|
||||
|
||||
if not UnitTypes[UnitType] then
|
||||
UnitTypes[UnitType] = 1
|
||||
else
|
||||
UnitTypes[UnitType] = UnitTypes[UnitType] + 1
|
||||
end
|
||||
end
|
||||
|
||||
for UnitTypeID, UnitType in pairs( UnitTypes ) do
|
||||
MT[#MT+1] = UnitType .. " of " .. UnitTypeID
|
||||
end
|
||||
|
||||
return table.concat( MT, ", " )
|
||||
end
|
||||
|
||||
|
||||
do -- DETECTION_REPORTING
|
||||
|
||||
--- Assigns tasks in relation to the detected items to the @{Set#SET_GROUP}.
|
||||
-- @param #TASK_DISPATCHER self
|
||||
-- @param Group#GROUP Group The @{Group} object to where the report needs to go.
|
||||
-- @param Detection#DETECTION_UNITGROUPS Detection The detection created by the @{Detection#DETECTION_UNITGROUPS} object.
|
||||
-- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop.
|
||||
function TASK_DISPATCHER:ProcessDetected( TaskGroup, Detection )
|
||||
self:F2( TaskGroup )
|
||||
|
||||
local DetectedMsg = {}
|
||||
|
||||
local FACGroup = self.Detection:GetDetectionGroups()
|
||||
local FACGroupName = FACGroup:GetName()
|
||||
|
||||
self:E( TaskGroup )
|
||||
|
||||
|
||||
--- First we need to the detected targets.
|
||||
for DetectedAreaID, DetectedAreaData in ipairs( Detection:GetDetectedAreas() ) do
|
||||
--- DETECTION_REPORTING class.
|
||||
-- @type DETECTION_REPORTING
|
||||
-- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to.
|
||||
-- @field Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects.
|
||||
-- @extends #DETECTION_MANAGER
|
||||
DETECTION_REPORTING = {
|
||||
ClassName = "DETECTION_REPORTING",
|
||||
}
|
||||
|
||||
|
||||
--- DETECTION_REPORTING constructor.
|
||||
-- @param #DETECTION_REPORTING self
|
||||
-- @param Set#SET_GROUP SetGroup
|
||||
-- @param Detection#DETECTION_AREAS Detection
|
||||
-- @return #DETECTION_REPORTING self
|
||||
function DETECTION_REPORTING:New( SetGroup, Detection )
|
||||
|
||||
-- Inherits from DETECTION_MANAGER
|
||||
local self = BASE:Inherit( self, DETECTION_MANAGER:New( SetGroup, Detection ) ) -- #DETECTION_REPORTING
|
||||
|
||||
self:Schedule( 1, 30 )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Creates a string of the detected items in a @{Detection}.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @param Set#SET_UNIT DetectedSet The detected Set created by the @{Detection#DETECTION_BASE} object.
|
||||
-- @return #DETECTION_MANAGER self
|
||||
function DETECTION_REPORTING:GetDetectedItemsText( DetectedSet )
|
||||
self:F2()
|
||||
|
||||
local MT = {} -- Message Text
|
||||
|
||||
local DetectedArea = DetectedAreaData -- Detection#DETECTION_UNITGROUPS.DetectedArea
|
||||
local TargetSetUnit = DetectedArea.Set
|
||||
self:E( "Targets in DetectedArea " .. DetectedArea.AreaID .. ":" .. TargetSetUnit:Count() )
|
||||
TargetSetUnit:Flush()
|
||||
local TargetZone = DetectedArea.Zone -- Zone#ZONE_BASE
|
||||
Detection:FlareDetectedZones()
|
||||
Detection:FlareDetectedUnits()
|
||||
|
||||
-- Evaluate SEAD Task
|
||||
local SEADText = self:EvaluateTaskSEAD( self.Mission, DetectedArea )
|
||||
if SEADText then
|
||||
MT[#MT+1] = SEADText
|
||||
end
|
||||
local UnitTypes = {}
|
||||
|
||||
for DetectedUnitID, DetectedUnitData in pairs( DetectedSet:GetSet() ) do
|
||||
local DetectedUnit = DetectedUnitData -- Unit#UNIT
|
||||
if DetectedUnit:IsAlive() then
|
||||
local UnitType = DetectedUnit:GetTypeName()
|
||||
|
||||
-- Evaluate CAS task
|
||||
local CASText = self:EvaluateTaskCAS( self.Mission, DetectedArea )
|
||||
if CASText then
|
||||
MT[#MT+1] = CASText
|
||||
if not UnitTypes[UnitType] then
|
||||
UnitTypes[UnitType] = 1
|
||||
else
|
||||
UnitTypes[UnitType] = UnitTypes[UnitType] + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
DetectedMsg[#DetectedMsg+1] = "- Group #" .. DetectedAreaID .. ":" .. table.concat( MT, "," )
|
||||
|
||||
for UnitTypeID, UnitType in pairs( UnitTypes ) do
|
||||
MT[#MT+1] = UnitType .. " of " .. UnitTypeID
|
||||
end
|
||||
|
||||
return table.concat( MT, ", " )
|
||||
end
|
||||
|
||||
self.CommandCenter:MessageToGroup( "Reporting tasks for target groups:\n" .. table.concat( DetectedMsg, "\n" ), self:GetReportDisplayTime(), TaskGroup )
|
||||
self.Mission:CreateTaskMenus( TaskGroup )
|
||||
|
||||
|
||||
--- Reports the detected items to the @{Set#SET_GROUP}.
|
||||
-- @param #DETECTION_REPORTING self
|
||||
-- @param Group#GROUP Group The @{Group} object to where the report needs to go.
|
||||
-- @param Detection#DETECTION_AREAS Detection The detection created by the @{Detection#DETECTION_BASE} object.
|
||||
-- @return #boolean Return true if you want the reporting to continue... false will cancel the reporting loop.
|
||||
function DETECTION_REPORTING:ProcessDetected( Group, Detection )
|
||||
self:F2( Group )
|
||||
|
||||
self:E( Group )
|
||||
local DetectedMsg = {}
|
||||
for DetectedAreaID, DetectedAreaData in pairs( Detection:GetDetectedAreas() ) do
|
||||
local DetectedArea = DetectedAreaData -- Detection#DETECTION_AREAS.DetectedArea
|
||||
DetectedMsg[#DetectedMsg+1] = " - Group #" .. DetectedAreaID .. ": " .. self:GetDetectedItemsText( DetectedArea.Set )
|
||||
end
|
||||
local FACGroup = Detection:GetDetectionGroups()
|
||||
FACGroup:MessageToGroup( "Reporting detected target groups:\n" .. table.concat( DetectedMsg, "\n" ), self:GetReportDisplayTime(), Group )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
do -- DETECTION_DISPATCHER
|
||||
|
||||
--- DETECTION_DISPATCHER class.
|
||||
-- @type DETECTION_DISPATCHER
|
||||
-- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to.
|
||||
-- @field Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects.
|
||||
-- @field Mission#MISSION Mission
|
||||
-- @field Group#GROUP CommandCenter
|
||||
-- @extends DetectionManager#DETECTION_MANAGER
|
||||
DETECTION_DISPATCHER = {
|
||||
ClassName = "DETECTION_DISPATCHER",
|
||||
Mission = nil,
|
||||
CommandCenter = nil,
|
||||
Detection = nil,
|
||||
}
|
||||
|
||||
|
||||
--- DETECTION_DISPATCHER constructor.
|
||||
-- @param #DETECTION_DISPATCHER self
|
||||
-- @param Set#SET_GROUP SetGroup
|
||||
-- @param Detection#DETECTION_BASE Detection
|
||||
-- @return #DETECTION_DISPATCHER self
|
||||
function DETECTION_DISPATCHER:New( Mission, CommandCenter, SetGroup, Detection )
|
||||
|
||||
-- Inherits from DETECTION_MANAGER
|
||||
local self = BASE:Inherit( self, DETECTION_MANAGER:New( SetGroup, Detection ) ) -- #DETECTION_DISPATCHER
|
||||
|
||||
self.Detection = Detection
|
||||
self.CommandCenter = CommandCenter
|
||||
self.Mission = Mission
|
||||
|
||||
self:Schedule( 30 )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Creates a SEAD task when there are targets for it.
|
||||
-- @param #DETECTION_DISPATCHER self
|
||||
-- @param Detection#DETECTION_AREAS.DetectedArea DetectedArea
|
||||
-- @return Set#SET_UNIT TargetSetUnit: The target set of units.
|
||||
-- @return #nil If there are no targets to be set.
|
||||
function DETECTION_DISPATCHER:EvaluateSEAD( DetectedArea )
|
||||
self:F( { DetectedArea.AreaID } )
|
||||
|
||||
local DetectedSet = DetectedArea.Set
|
||||
local DetectedZone = DetectedArea.Zone
|
||||
|
||||
-- Determine if the set has radar targets. If it does, construct a SEAD task.
|
||||
local RadarCount = DetectedSet:HasSEAD()
|
||||
|
||||
if RadarCount > 0 then
|
||||
|
||||
-- Here we're doing something advanced... We're copying the DetectedSet, but making a new Set only with SEADable Radar units in it.
|
||||
local TargetSetUnit = SET_UNIT:New()
|
||||
TargetSetUnit:SetDatabase( DetectedSet )
|
||||
TargetSetUnit:FilterHasSEAD()
|
||||
TargetSetUnit:FilterOnce() -- Filter but don't do any events!!! Elements are added manually upon each detection.
|
||||
|
||||
return TargetSetUnit
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Creates a CAS task when there are targets for it.
|
||||
-- @param #DETECTION_DISPATCHER self
|
||||
-- @param Detection#DETECTION_AREAS.DetectedArea DetectedArea
|
||||
-- @return Task#TASK_BASE
|
||||
function DETECTION_DISPATCHER:EvaluateCAS( DetectedArea )
|
||||
self:F( { DetectedArea.AreaID } )
|
||||
|
||||
local DetectedSet = DetectedArea.Set
|
||||
local DetectedZone = DetectedArea.Zone
|
||||
|
||||
|
||||
-- Determine if the set has radar targets. If it does, construct a SEAD task.
|
||||
local GroundUnitCount = DetectedSet:HasGroundUnits()
|
||||
local FriendliesNearBy = self.Detection:IsFriendliesNearBy( DetectedArea )
|
||||
|
||||
if GroundUnitCount > 0 and FriendliesNearBy == true then
|
||||
|
||||
-- Copy the Set
|
||||
local TargetSetUnit = SET_UNIT:New()
|
||||
TargetSetUnit:SetDatabase( DetectedSet )
|
||||
TargetSetUnit:FilterOnce() -- Filter but don't do any events!!! Elements are added manually upon each detection.
|
||||
|
||||
return TargetSetUnit
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Creates a BAI task when there are targets for it.
|
||||
-- @param #DETECTION_DISPATCHER self
|
||||
-- @param Detection#DETECTION_AREAS.DetectedArea DetectedArea
|
||||
-- @return Task#TASK_BASE
|
||||
function DETECTION_DISPATCHER:EvaluateBAI( DetectedArea, FriendlyCoalition )
|
||||
self:F( { DetectedArea.AreaID } )
|
||||
|
||||
local DetectedSet = DetectedArea.Set
|
||||
local DetectedZone = DetectedArea.Zone
|
||||
|
||||
|
||||
-- Determine if the set has radar targets. If it does, construct a SEAD task.
|
||||
local GroundUnitCount = DetectedSet:HasGroundUnits()
|
||||
local FriendliesNearBy = self.Detection:IsFriendliesNearBy( DetectedArea )
|
||||
|
||||
if GroundUnitCount > 0 and FriendliesNearBy == false then
|
||||
|
||||
-- Copy the Set
|
||||
local TargetSetUnit = SET_UNIT:New()
|
||||
TargetSetUnit:SetDatabase( DetectedSet )
|
||||
TargetSetUnit:FilterOnce() -- Filter but don't do any events!!! Elements are added manually upon each detection.
|
||||
|
||||
return TargetSetUnit
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Evaluates the removal of the Task from the Mission.
|
||||
-- Can only occur when the DetectedArea is Changed AND the state of the Task is "Planned".
|
||||
-- @param #DETECTION_DISPATCHER self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Task#TASK_BASE Task
|
||||
-- @param Detection#DETECTION_AREAS.DetectedArea DetectedArea
|
||||
-- @return Task#TASK_BASE
|
||||
function DETECTION_DISPATCHER:EvaluateRemoveTask( Mission, Task, DetectedArea )
|
||||
|
||||
if Task then
|
||||
if Task:IsStatePlanned() and DetectedArea.Changed == true then
|
||||
Mission:RemoveTaskMenu( Task )
|
||||
Task = Mission:RemoveTask( Task )
|
||||
end
|
||||
end
|
||||
|
||||
return Task
|
||||
end
|
||||
|
||||
|
||||
--- Assigns tasks in relation to the detected items to the @{Set#SET_GROUP}.
|
||||
-- @param #DETECTION_DISPATCHER self
|
||||
-- @param Detection#DETECTION_AREAS Detection The detection created by the @{Detection#DETECTION_AREAS} object.
|
||||
-- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop.
|
||||
function DETECTION_DISPATCHER:ProcessDetected( Detection )
|
||||
self:F2()
|
||||
|
||||
local AreaMsg = {}
|
||||
local TaskMsg = {}
|
||||
local ChangeMsg = {}
|
||||
|
||||
local Mission = self.Mission
|
||||
|
||||
--- First we need to the detected targets.
|
||||
for DetectedAreaID, DetectedAreaData in ipairs( Detection:GetDetectedAreas() ) do
|
||||
|
||||
local DetectedArea = DetectedAreaData -- Detection#DETECTION_AREAS.DetectedArea
|
||||
local DetectedSet = DetectedArea.Set
|
||||
local DetectedZone = DetectedArea.Zone
|
||||
self:E( { "Targets in DetectedArea", DetectedArea.AreaID, DetectedSet:Count(), tostring( DetectedArea ) } )
|
||||
DetectedSet:Flush()
|
||||
|
||||
local AreaID = DetectedArea.AreaID
|
||||
|
||||
-- Evaluate SEAD Tasking
|
||||
local SEADTask = Mission:GetTask( "SEAD." .. AreaID )
|
||||
SEADTask = self:EvaluateRemoveTask( Mission, SEADTask, DetectedArea )
|
||||
if not SEADTask then
|
||||
local TargetSetUnit = self:EvaluateSEAD( DetectedArea ) -- Returns a SetUnit if there are targets to be SEADed...
|
||||
if TargetSetUnit then
|
||||
SEADTask = Mission:AddTask( TASK_SEAD:New( Mission, self.SetGroup, "SEAD." .. AreaID, TargetSetUnit , DetectedZone ) ):StatePlanned()
|
||||
end
|
||||
end
|
||||
if SEADTask and SEADTask:IsStatePlanned() then
|
||||
SEADTask:SetPlannedMenu()
|
||||
TaskMsg[#TaskMsg+1] = " - " .. SEADTask:GetStateString() .. " SEAD " .. AreaID .. " - " .. SEADTask.TargetSetUnit:GetUnitTypesText()
|
||||
end
|
||||
|
||||
-- Evaluate CAS Tasking
|
||||
local CASTask = Mission:GetTask( "CAS." .. AreaID )
|
||||
CASTask = self:EvaluateRemoveTask( Mission, CASTask, DetectedArea )
|
||||
if not CASTask then
|
||||
local TargetSetUnit = self:EvaluateCAS( DetectedArea ) -- Returns a SetUnit if there are targets to be SEADed...
|
||||
if TargetSetUnit then
|
||||
CASTask = Mission:AddTask( TASK_CAS:New( Mission, self.SetGroup, "CAS." .. AreaID, TargetSetUnit , DetectedZone ) ):StatePlanned()
|
||||
end
|
||||
end
|
||||
if CASTask and CASTask:IsStatePlanned() then
|
||||
CASTask:SetPlannedMenu()
|
||||
TaskMsg[#TaskMsg+1] = " - " .. CASTask:GetStateString() .. " CAS " .. AreaID .. " - " .. CASTask.TargetSetUnit:GetUnitTypesText()
|
||||
end
|
||||
|
||||
-- Evaluate BAI Tasking
|
||||
local BAITask = Mission:GetTask( "BAI." .. AreaID )
|
||||
BAITask = self:EvaluateRemoveTask( Mission, BAITask, DetectedArea )
|
||||
if not BAITask then
|
||||
local TargetSetUnit = self:EvaluateBAI( DetectedArea, self.CommandCenter:GetCoalition() ) -- Returns a SetUnit if there are targets to be SEADed...
|
||||
if TargetSetUnit then
|
||||
BAITask = Mission:AddTask( TASK_BAI:New( Mission, self.SetGroup, "BAI." .. AreaID, TargetSetUnit , DetectedZone ) ):StatePlanned()
|
||||
end
|
||||
end
|
||||
if BAITask and BAITask:IsStatePlanned() then
|
||||
BAITask:SetPlannedMenu()
|
||||
TaskMsg[#TaskMsg+1] = " - " .. BAITask:GetStateString() .. " BAI " .. AreaID .. " - " .. BAITask.TargetSetUnit:GetUnitTypesText()
|
||||
end
|
||||
|
||||
if #TaskMsg > 0 then
|
||||
|
||||
local ThreatLevel = Detection:GetTreatLevelA2G( DetectedArea )
|
||||
|
||||
local DetectedAreaVec3 = DetectedZone:GetPointVec3()
|
||||
local DetectedAreaPointVec3 = POINT_VEC3:New( DetectedAreaVec3.x, DetectedAreaVec3.y, DetectedAreaVec3.z )
|
||||
local DetectedAreaPointLL = DetectedAreaPointVec3:ToStringLL( 3, true )
|
||||
AreaMsg[#AreaMsg+1] = string.format( " - Area #%d - %s - Threat Level [%s] (%2d)",
|
||||
DetectedAreaID,
|
||||
DetectedAreaPointLL,
|
||||
string.rep( "■", ThreatLevel ),
|
||||
ThreatLevel
|
||||
)
|
||||
|
||||
-- Loop through the changes ...
|
||||
local ChangeText = Detection:GetChangeText( DetectedArea )
|
||||
|
||||
if ChangeText ~= "" then
|
||||
ChangeMsg[#ChangeMsg+1] = string.gsub( string.gsub( ChangeText, "\n", "%1 - " ), "^.", " - %1" )
|
||||
end
|
||||
end
|
||||
|
||||
-- OK, so the tasking has been done, now delete the changes reported for the area.
|
||||
Detection:AcceptChanges( DetectedArea )
|
||||
|
||||
end
|
||||
|
||||
if #AreaMsg > 0 then
|
||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||
if not TaskGroup:GetState( TaskGroup, "Assigned" ) then
|
||||
self.CommandCenter:MessageToGroup(
|
||||
string.format( "HQ Reporting - Target areas for mission '%s':\nAreas:\n%s\n\nTasks:\n%s\n\nChanges:\n%s ",
|
||||
self.Mission:GetName(),
|
||||
table.concat( AreaMsg, "\n" ),
|
||||
table.concat( TaskMsg, "\n" ),
|
||||
table.concat( ChangeMsg, "\n" )
|
||||
), self:GetReportDisplayTime(), TaskGroup
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
@@ -94,6 +94,18 @@ function EVENT:Init( EventID, EventClass )
|
||||
return self.Events[EventID][EventClass]
|
||||
end
|
||||
|
||||
--- Removes an Events entry
|
||||
-- @param #EVENT self
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @param DCSWorld#world.event EventID
|
||||
-- @return #EVENT.Events
|
||||
function EVENT:Remove( EventSelf, EventID )
|
||||
self:F3( { EventSelf, _EVENTCODES[EventID] } )
|
||||
|
||||
local EventClass = EventSelf:GetClassNameAndID()
|
||||
self.Events[EventID][EventClass] = nil
|
||||
end
|
||||
|
||||
|
||||
--- Create an OnDead event handler for a group
|
||||
-- @param #EVENT self
|
||||
@@ -147,336 +159,529 @@ function EVENT:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, Event
|
||||
return self
|
||||
end
|
||||
|
||||
do -- OnBirth
|
||||
|
||||
--- Create an OnBirth event handler for a group
|
||||
-- @param #EVENT self
|
||||
-- @param Group#GROUP EventGroup
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnBirthForTemplate( EventTemplate, EventFunction, EventSelf )
|
||||
self:F2( EventTemplate.name )
|
||||
|
||||
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnBirthForUnit )
|
||||
--- Create an OnBirth event handler for a group
|
||||
-- @param #EVENT self
|
||||
-- @param Group#GROUP EventGroup
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnBirthForTemplate( EventTemplate, EventFunction, EventSelf )
|
||||
self:F2( EventTemplate.name )
|
||||
|
||||
return self
|
||||
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnBirthForUnit )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_BIRTH event, and registers the unit born.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnBirth( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_BIRTH )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_BIRTH event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName The id of the unit for the event to be handled.
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnBirthForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_BIRTH )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop listening to S_EVENT_BIRTH event.
|
||||
-- @param #EVENT self
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnBirthRemove( EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:Remove( EventSelf, world.event.S_EVENT_BIRTH )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_BIRTH event, and registers the unit born.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnBirth( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
do -- OnCrash
|
||||
|
||||
--- Create an OnCrash event handler for a group
|
||||
-- @param #EVENT self
|
||||
-- @param Group#GROUP EventGroup
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnCrashForTemplate( EventTemplate, EventFunction, EventSelf )
|
||||
self:F2( EventTemplate.name )
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_BIRTH )
|
||||
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnCrashForUnit )
|
||||
|
||||
return self
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_CRASH event.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnCrash( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_CRASH )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_CRASH event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnCrashForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_CRASH )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop listening to S_EVENT_CRASH event.
|
||||
-- @param #EVENT self
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnCrashRemove( EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:Remove( EventSelf, world.event.S_EVENT_CRASH )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_BIRTH event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName The id of the unit for the event to be handled.
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnBirthForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
do -- OnDead
|
||||
|
||||
--- Create an OnDead event handler for a group
|
||||
-- @param #EVENT self
|
||||
-- @param Group#GROUP EventGroup
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnDeadForTemplate( EventTemplate, EventFunction, EventSelf )
|
||||
self:F2( EventTemplate.name )
|
||||
|
||||
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnDeadForUnit )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_BIRTH )
|
||||
return self
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create an OnCrash event handler for a group
|
||||
-- @param #EVENT self
|
||||
-- @param Group#GROUP EventGroup
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnCrashForTemplate( EventTemplate, EventFunction, EventSelf )
|
||||
self:F2( EventTemplate.name )
|
||||
|
||||
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnCrashForUnit )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_CRASH event.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnCrash( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
--- Set a new listener for an S_EVENT_DEAD event.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnDead( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_DEAD )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_CRASH )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_CRASH event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnCrashForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
--- Set a new listener for an S_EVENT_DEAD event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnDeadForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_CRASH )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create an OnDead event handler for a group
|
||||
-- @param #EVENT self
|
||||
-- @param Group#GROUP EventGroup
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnDeadForTemplate( EventTemplate, EventFunction, EventSelf )
|
||||
self:F2( EventTemplate.name )
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_DEAD )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnDeadForUnit )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_DEAD event.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnDead( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
--- Stop listening to S_EVENT_DEAD event.
|
||||
-- @param #EVENT self
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnDeadRemove( EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:Remove( EventSelf, world.event.S_EVENT_DEAD )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_DEAD )
|
||||
|
||||
end
|
||||
|
||||
do -- OnPilotDead
|
||||
|
||||
--- Set a new listener for an S_EVENT_PILOT_DEAD event.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnPilotDead( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_PILOT_DEAD )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set a new listener for an S_EVENT_DEAD event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnDeadForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_DEAD )
|
||||
--- Set a new listener for an S_EVENT_PILOT_DEAD event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnPilotDeadForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_PILOT_DEAD event.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnPilotDead( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_PILOT_DEAD )
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_PILOT_DEAD )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop listening to S_EVENT_PILOT_DEAD event.
|
||||
-- @param #EVENT self
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnPilotDeadRemove( EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:Remove( EventSelf, world.event.S_EVENT_PILOT_DEAD )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do -- OnLand
|
||||
--- Create an OnLand event handler for a group
|
||||
-- @param #EVENT self
|
||||
-- @param #table EventTemplate
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnLandForTemplate( EventTemplate, EventFunction, EventSelf )
|
||||
self:F2( EventTemplate.name )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_PILOT_DEAD event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnPilotDeadForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_PILOT_DEAD )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create an OnDead event handler for a group
|
||||
-- @param #EVENT self
|
||||
-- @param #table EventTemplate
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnLandForTemplate( EventTemplate, EventFunction, EventSelf )
|
||||
self:F2( EventTemplate.name )
|
||||
|
||||
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnLandForUnit )
|
||||
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnLandForUnit )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_LAND event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnLandForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_LAND )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create an OnDead event handler for a group
|
||||
-- @param #EVENT self
|
||||
-- @param #table EventTemplate
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnTakeOffForTemplate( EventTemplate, EventFunction, EventSelf )
|
||||
self:F2( EventTemplate.name )
|
||||
|
||||
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnTakeOffForUnit )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_TAKEOFF event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnTakeOffForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_TAKEOFF )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create an OnDead event handler for a group
|
||||
-- @param #EVENT self
|
||||
-- @param #table EventTemplate
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnEngineShutDownForTemplate( EventTemplate, EventFunction, EventSelf )
|
||||
self:F2( EventTemplate.name )
|
||||
|
||||
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnEngineShutDownForUnit )
|
||||
--- Set a new listener for an S_EVENT_LAND event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnLandForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_ENGINE_SHUTDOWN event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnEngineShutDownForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_ENGINE_SHUTDOWN )
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_LAND )
|
||||
|
||||
return self
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop listening to S_EVENT_LAND event.
|
||||
-- @param #EVENT self
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnLandRemove( EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:Remove( EventSelf, world.event.S_EVENT_LAND )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_ENGINE_STARTUP event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnEngineStartUpForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_ENGINE_STARTUP )
|
||||
do -- OnTakeOff
|
||||
--- Create an OnTakeOff event handler for a group
|
||||
-- @param #EVENT self
|
||||
-- @param #table EventTemplate
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnTakeOffForTemplate( EventTemplate, EventFunction, EventSelf )
|
||||
self:F2( EventTemplate.name )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_SHOT event.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnShot( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_SHOT )
|
||||
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnTakeOffForUnit )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_SHOT event for a unit.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnShotForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_SHOT )
|
||||
return self
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_HIT event.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnHit( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_HIT )
|
||||
--- Set a new listener for an S_EVENT_TAKEOFF event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnTakeOffForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_HIT event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnHitForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_HIT )
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_TAKEOFF )
|
||||
|
||||
return self
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop listening to S_EVENT_TAKEOFF event.
|
||||
-- @param #EVENT self
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnTakeOffRemove( EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:Remove( EventSelf, world.event.S_EVENT_TAKEOFF )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_PLAYER_ENTER_UNIT event.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnPlayerEnterUnit( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
do -- OnEngineShutDown
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_PLAYER_ENTER_UNIT )
|
||||
--- Create an OnDead event handler for a group
|
||||
-- @param #EVENT self
|
||||
-- @param #table EventTemplate
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnEngineShutDownForTemplate( EventTemplate, EventFunction, EventSelf )
|
||||
self:F2( EventTemplate.name )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_PLAYER_LEAVE_UNIT event.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnPlayerLeaveUnit( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_PLAYER_LEAVE_UNIT )
|
||||
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnEngineShutDownForUnit )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return self
|
||||
--- Set a new listener for an S_EVENT_ENGINE_SHUTDOWN event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnEngineShutDownForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_ENGINE_SHUTDOWN )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop listening to S_EVENT_ENGINE_SHUTDOWN event.
|
||||
-- @param #EVENT self
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnEngineShutDownRemove( EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:Remove( EventSelf, world.event.S_EVENT_ENGINE_SHUTDOWN )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do -- OnEngineStartUp
|
||||
|
||||
--- Set a new listener for an S_EVENT_ENGINE_STARTUP event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnEngineStartUpForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_ENGINE_STARTUP )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop listening to S_EVENT_ENGINE_STARTUP event.
|
||||
-- @param #EVENT self
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnEngineStartUpRemove( EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:Remove( EventSelf, world.event.S_EVENT_ENGINE_STARTUP )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do -- OnShot
|
||||
--- Set a new listener for an S_EVENT_SHOT event.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnShot( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_SHOT )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_SHOT event for a unit.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnShotForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_SHOT )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop listening to S_EVENT_SHOT event.
|
||||
-- @param #EVENT self
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnShotRemove( EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:Remove( EventSelf, world.event.S_EVENT_SHOT )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
do -- OnHit
|
||||
|
||||
--- Set a new listener for an S_EVENT_HIT event.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnHit( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_HIT )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a new listener for an S_EVENT_HIT event.
|
||||
-- @param #EVENT self
|
||||
-- @param #string EventDCSUnitName
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnHitForUnit( EventDCSUnitName, EventFunction, EventSelf )
|
||||
self:F2( EventDCSUnitName )
|
||||
|
||||
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_HIT )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop listening to S_EVENT_HIT event.
|
||||
-- @param #EVENT self
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnHitRemove( EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:Remove( EventSelf, world.event.S_EVENT_HIT )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do -- OnPlayerEnterUnit
|
||||
|
||||
--- Set a new listener for an S_EVENT_PLAYER_ENTER_UNIT event.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnPlayerEnterUnit( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_PLAYER_ENTER_UNIT )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop listening to S_EVENT_PLAYER_ENTER_UNIT event.
|
||||
-- @param #EVENT self
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnPlayerEnterRemove( EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:Remove( EventSelf, world.event.S_EVENT_PLAYER_ENTER_UNIT )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do -- OnPlayerLeaveUnit
|
||||
--- Set a new listener for an S_EVENT_PLAYER_LEAVE_UNIT event.
|
||||
-- @param #EVENT self
|
||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||
-- @param Base#BASE EventSelf The self instance of the class for which the event is.
|
||||
-- @return #EVENT
|
||||
function EVENT:OnPlayerLeaveUnit( EventFunction, EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_PLAYER_LEAVE_UNIT )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop listening to S_EVENT_PLAYER_LEAVE_UNIT event.
|
||||
-- @param #EVENT self
|
||||
-- @param Base#BASE EventSelf
|
||||
-- @return #EVENT
|
||||
function EVENT:OnPlayerLeaveRemove( EventSelf )
|
||||
self:F2()
|
||||
|
||||
self:Remove( EventSelf, world.event.S_EVENT_PLAYER_LEAVE_UNIT )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @param #EVENT self
|
||||
-- @param #EVENTDATA Event
|
||||
@@ -512,16 +717,16 @@ function EVENT:onEvent( Event )
|
||||
Event.WeaponName = Event.Weapon:getTypeName()
|
||||
--Event.WeaponTgtDCSUnit = Event.Weapon:getTarget()
|
||||
end
|
||||
self:E( { _EVENTCODES[Event.id], Event } )
|
||||
--self:E( { _EVENTCODES[Event.id], Event.IniUnitName, Event.TgtUnitName, Event.WeaponName } )
|
||||
self:E( { _EVENTCODES[Event.id], Event.IniUnitName, Event.TgtUnitName, Event.WeaponName } )
|
||||
for ClassName, EventData in pairs( self.Events[Event.id] ) do
|
||||
self:T( { "Evaluating class ", { EventData.EventSelf:GetClassNameAndID(), ClassName } } )
|
||||
if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then
|
||||
self:E( { "Calling event function for class ", ClassName, " unit ", Event.IniUnitName } )
|
||||
self:T( { "Calling event function for class ", ClassName, " unit ", Event.IniUnitName } )
|
||||
EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventSelf, Event )
|
||||
else
|
||||
if Event.IniDCSUnit and not EventData.IniUnit then
|
||||
if ClassName == EventData.EventSelf:GetClassNameAndID() then
|
||||
self:E( { "Calling event function for class ", ClassName } )
|
||||
self:T( { "Calling event function for class ", ClassName } )
|
||||
EventData.EventFunction( EventData.EventSelf, Event )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -960,7 +960,9 @@ function GROUP:MessageToGroup( Message, Duration, MsgGroup )
|
||||
|
||||
local DCSGroup = self:GetDCSObject()
|
||||
if DCSGroup then
|
||||
self:GetMessage( Message, Duration ):ToGroup( MsgGroup )
|
||||
if DCSGroup:isExist() then
|
||||
self:GetMessage( Message, Duration ):ToGroup( MsgGroup )
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
@@ -301,6 +301,7 @@ do
|
||||
missionCommands.removeItemForGroup( self.MenuGroupID, MenuPath[MenuPathID] )
|
||||
end
|
||||
|
||||
self:T( { "Adding for MenuPath ", MenuText, MenuParentPath } )
|
||||
self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuGroupID, MenuText, MenuParentPath )
|
||||
MenuPath[MenuPathID] = self.MenuPath
|
||||
|
||||
@@ -395,6 +396,7 @@ do
|
||||
missionCommands.removeItemForGroup( self.MenuGroupID, MenuPath[MenuPathID] )
|
||||
end
|
||||
|
||||
self:T( { "Adding for MenuPath ", MenuText, MenuParentPath } )
|
||||
self.MenuPath = missionCommands.addCommandForGroup( self.MenuGroupID, MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument )
|
||||
MenuPath[MenuPathID] = self.MenuPath
|
||||
|
||||
@@ -414,6 +416,7 @@ do
|
||||
end
|
||||
|
||||
local MenuPath = _MENUGROUPS[self.MenuGroupID]
|
||||
|
||||
|
||||
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
|
||||
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
|
||||
|
||||
@@ -37,7 +37,6 @@ MISSION = {
|
||||
function MISSION:Meta()
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
self:F()
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -59,8 +58,6 @@ function MISSION:New( MissionName, MissionPriority, MissionBriefing, MissionCoal
|
||||
self.MissionBriefing = MissionBriefing
|
||||
self.MissionCoalition = MissionCoalition
|
||||
|
||||
self:SetMissionMenu()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -86,18 +83,51 @@ function MISSION:GetScoring()
|
||||
return self.Scoring
|
||||
end
|
||||
|
||||
--- Sets the mission menu for the coalition.
|
||||
|
||||
--- Sets the Planned Task menu.
|
||||
-- @param #MISSION self
|
||||
-- @return #MISSION self
|
||||
function MISSION:SetMissionMenu()
|
||||
self.MissionMenu = MENU_COALITION:New( self.MissionCoalition, self.Name )
|
||||
function MISSION:SetPlannedMenu()
|
||||
|
||||
for _, Task in pairs( self.Tasks ) do
|
||||
local Task = Task -- Task#TASK_BASE
|
||||
Task:RemoveMenu()
|
||||
Task:SetPlannedMenu()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Sets the Assigned Task menu.
|
||||
-- @param #MISSION self
|
||||
-- @param Task#TASK_BASE Task
|
||||
-- @param #string MenuText The menu text.
|
||||
-- @return #MISSION self
|
||||
function MISSION:SetAssignedMenu( Task )
|
||||
|
||||
for _, Task in pairs( self.Tasks ) do
|
||||
local Task = Task -- Task#TASK_BASE
|
||||
Task:RemoveMenu()
|
||||
Task:SetAssignedMenu()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Removes a Task menu.
|
||||
-- @param #MISSION self
|
||||
-- @param Task#TASK_BASE Task
|
||||
-- @return #MISSION self
|
||||
function MISSION:RemoveTaskMenu( Task )
|
||||
|
||||
Task:RemoveMenu()
|
||||
end
|
||||
|
||||
|
||||
--- Gets the mission menu for the coalition.
|
||||
-- @param #MISSION self
|
||||
-- @param Group#GROUP TaskGroup
|
||||
-- @return Menu#MENU_COALITION self
|
||||
function MISSION:GetMissionMenu()
|
||||
return self.MissionMenu
|
||||
function MISSION:GetMissionMenu( TaskGroup )
|
||||
local TaskGroupName = TaskGroup:GetName()
|
||||
return self.MenuMission[TaskGroupName]
|
||||
end
|
||||
|
||||
|
||||
@@ -109,59 +139,17 @@ function MISSION:ClearMissionMenu()
|
||||
self.MissionMenu = nil
|
||||
end
|
||||
|
||||
--- Fill mission menu for the Group.
|
||||
-- @param #MISSION self
|
||||
-- @return #MISSION self
|
||||
function MISSION:CreateTaskMenus( TaskGroup )
|
||||
--- Get the TASK identified by the TaskNumber from the Mission. This function is useful in GoalFunctions.
|
||||
-- @param #string TaskIndex is the Index of the @{Task} within the @{Mission}.
|
||||
-- @param #number TaskID is the ID of the @{Task} within the @{Mission}.
|
||||
-- @return Task#TASK_BASE The Task
|
||||
-- @return #nil Returns nil if no task was found.
|
||||
function MISSION:GetTask( TaskName )
|
||||
self:F( { TaskName } )
|
||||
|
||||
local MissionMenu = self:GetMissionMenu()
|
||||
local TaskMenus = self.TaskMenus
|
||||
local TaskCategoryMenus = self.TaskCategoryMenus
|
||||
local TaskTypeMenus = self.TaskTypeMenus
|
||||
|
||||
for TaskIndex, TaskTable in pairs( self.Tasks ) do
|
||||
for _, Task in pairs( TaskTable ) do
|
||||
Task = Task -- Task#TASK_BASE
|
||||
local TaskType = Task:GetType()
|
||||
local TaskName = Task:GetName()
|
||||
local TaskID = Task:GetID()
|
||||
local TaskCategory = Task:GetCategory()
|
||||
local TaskMenuID = TaskCategory .. "." ..TaskType .. "." .. TaskName .. "." .. TaskID
|
||||
|
||||
if not TaskMenus[TaskMenuID] then
|
||||
|
||||
TaskMenus[TaskMenuID] = {}
|
||||
|
||||
if not TaskCategoryMenus[TaskCategory] then
|
||||
TaskCategoryMenus[TaskCategory] = MENU_COALITION:New( self.MissionCoalition, TaskCategory, MissionMenu )
|
||||
end
|
||||
TaskMenus[TaskMenuID].MenuCategory = TaskCategoryMenus[TaskCategory]
|
||||
|
||||
if not TaskTypeMenus[TaskType] then
|
||||
TaskTypeMenus[TaskType] = MENU_COALITION:New( self.MissionCoalition, TaskType, TaskMenus[TaskMenuID].MenuCategory )
|
||||
end
|
||||
TaskMenus[TaskMenuID].MenuType = TaskTypeMenus[TaskType]
|
||||
|
||||
if TaskMenus[TaskMenuID].Menu then
|
||||
TaskMenus[TaskMenuID].Menu:Remove()
|
||||
end
|
||||
TaskMenus[TaskMenuID].Menu = MENU_GROUP_COMMAND:New( TaskGroup, TaskName .. "." .. TaskID, TaskMenus[TaskMenuID].MenuType, self.AssignTaskToGroup, { self = self, Task = Task, TaskGroup = TaskGroup } )
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
return self.Tasks[TaskName]
|
||||
end
|
||||
|
||||
function MISSION.AssignTaskToGroup( MenuParam )
|
||||
|
||||
local self = MenuParam.self
|
||||
local Task = MenuParam.Task -- Task#TASK_BASE
|
||||
local TaskGroup = MenuParam.TaskGroup
|
||||
|
||||
Task:AssignToGroup( TaskGroup )
|
||||
|
||||
|
||||
end
|
||||
|
||||
--- Register a @{Task} to be completed within the @{Mission}.
|
||||
-- Note that there can be multiple @{Task}s registered to be completed.
|
||||
@@ -170,21 +158,52 @@ end
|
||||
-- @param Task#TASK_BASE Task is the @{Task} object.
|
||||
-- @return Task#TASK_BASE The task added.
|
||||
function MISSION:AddTask( Task )
|
||||
self:F()
|
||||
|
||||
local TaskCategory = Task:GetCategory()
|
||||
local TaskType = Task:GetType()
|
||||
local TaskName = Task:GetName()
|
||||
local TaskIndex = TaskCategory .. "." ..TaskType .. "." .. TaskName
|
||||
local TaskName = Task:GetTaskName()
|
||||
self:F( TaskName )
|
||||
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
|
||||
|
||||
self.Tasks[TaskIndex] = self.Tasks[TaskIndex] or {}
|
||||
local TaskID = #self.Tasks[TaskIndex] + 1
|
||||
|
||||
self.Tasks[TaskIndex][TaskID] = Task
|
||||
Task:SetID( TaskID )
|
||||
self.Tasks[TaskName] = Task
|
||||
|
||||
return Task
|
||||
end
|
||||
end
|
||||
|
||||
--- Removes a @{Task} to be completed within the @{Mission}.
|
||||
-- Note that there can be multiple @{Task}s registered to be completed.
|
||||
-- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached.
|
||||
-- @param #MISSION self
|
||||
-- @param Task#TASK_BASE Task is the @{Task} object.
|
||||
-- @return #nil The cleaned Task reference.
|
||||
function MISSION:RemoveTask( Task )
|
||||
|
||||
local TaskName = Task:GetTaskName()
|
||||
self:F( TaskName )
|
||||
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
|
||||
|
||||
Task:CleanUp() -- Cleans all events and sets task to nil to get Garbage Collected
|
||||
|
||||
-- Ensure everything gets garbarge collected.
|
||||
self.Tasks[TaskName] = nil
|
||||
Task = nil
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Return the next @{Task} ID to be completed within the @{Mission}.
|
||||
-- @param #MISSION self
|
||||
-- @param Task#TASK_BASE Task is the @{Task} object.
|
||||
-- @return Task#TASK_BASE The task added.
|
||||
function MISSION:GetNextTaskID( Task )
|
||||
|
||||
local TaskName = Task:GetTaskName()
|
||||
self:F( TaskName )
|
||||
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
|
||||
|
||||
self.Tasks[TaskName].n = self.Tasks[TaskName].n + 1
|
||||
|
||||
return self.Tasks[TaskName].n
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- old stuff
|
||||
@@ -377,31 +396,6 @@ function MISSION:FindClient( ClientName )
|
||||
end
|
||||
|
||||
|
||||
--- Get the TASK idenified by the TaskNumber from the Mission. This function is useful in GoalFunctions.
|
||||
-- @param number TaskNumber is the number of the @{TASK} within the @{MISSION}.
|
||||
-- @return TASK
|
||||
-- @usage
|
||||
-- -- Get Task 2 from the Mission.
|
||||
-- Task2 = Mission:GetTask( 2 )
|
||||
|
||||
function MISSION:GetTask( TaskNumber )
|
||||
self:F()
|
||||
|
||||
local Valid = true
|
||||
|
||||
local Task = nil
|
||||
|
||||
if type(TaskNumber) ~= "number" then
|
||||
Valid = false
|
||||
end
|
||||
|
||||
if Valid then
|
||||
Task = self._Tasks[TaskNumber]
|
||||
end
|
||||
|
||||
return Task
|
||||
end
|
||||
|
||||
--- Get all the TASKs from the Mission. This function is useful in GoalFunctions.
|
||||
-- @return {TASK,...} Structure of TASKS with the @{TASK} number as the key.
|
||||
-- @usage
|
||||
|
||||
@@ -44,16 +44,22 @@ Include.File( "MissileTrainer" )
|
||||
Include.File( "PatrolZone" )
|
||||
Include.File( "AIBalancer" )
|
||||
Include.File( "AirbasePolice" )
|
||||
|
||||
Include.File( "Detection" )
|
||||
Include.File( "DetectionManager" )
|
||||
|
||||
Include.File( "StateMachine" )
|
||||
|
||||
Include.File( "Process" )
|
||||
Include.File( "Process_Assign" )
|
||||
Include.File( "Process_Route" )
|
||||
Include.File( "Process_SEAD" )
|
||||
Include.File( "Process_Smoke" )
|
||||
Include.File( "Process_Destroy" )
|
||||
|
||||
Include.File( "Task" )
|
||||
Include.File( "Task_CAS" )
|
||||
Include.File( "Task_SEAD" )
|
||||
Include.File( "Task_CAS" )
|
||||
Include.File( "Task_BAI" )
|
||||
|
||||
-- The order of the declarations is important here. Don't touch it.
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ end
|
||||
-- @return #number DirectionRadians The direction in radians.
|
||||
function POINT_VEC3:GetDirectionRadians( DirectionVec3 )
|
||||
local DirectionRadians = math.atan2( DirectionVec3.z, DirectionVec3.x )
|
||||
DirectionRadians = DirectionRadians + self:GetNorthCorrectionRadians()
|
||||
--DirectionRadians = DirectionRadians + self:GetNorthCorrectionRadians()
|
||||
if DirectionRadians < 0 then
|
||||
DirectionRadians = DirectionRadians + 2 * math.pi -- put dir in range of 0 to 2*pi ( the full circle )
|
||||
end
|
||||
@@ -222,6 +222,18 @@ function POINT_VEC3:ToStringBR( AngleRadians, Distance )
|
||||
return s
|
||||
end
|
||||
|
||||
--- Provides a Bearing / Range string
|
||||
-- @param #POINT_VEC3 self
|
||||
-- @param #number AngleRadians The angle in randians
|
||||
-- @param #number Distance The distance
|
||||
-- @return #string The BR Text
|
||||
function POINT_VEC3:ToStringLL( acc, DMS )
|
||||
|
||||
acc = acc or 3
|
||||
local lat, lon = coord.LOtoLL( self.PointVec3 )
|
||||
return UTILS.tostringLL(lat, lon, acc, DMS)
|
||||
end
|
||||
|
||||
--- Return the altitude text of the POINT_VEC3.
|
||||
-- @param #POINT_VEC3 self
|
||||
-- @return #string Altitude text.
|
||||
|
||||
@@ -91,6 +91,30 @@ function POSITIONABLE:GetVec2()
|
||||
end
|
||||
|
||||
|
||||
--- Returns a random @{DCSTypes#Vec3} vector within a range, indicating the point in 3D of the DCS Positionable within the mission.
|
||||
-- @param Positionable#POSITIONABLE self
|
||||
-- @return DCSTypes#Vec3 The 3D point vector of the DCS Positionable.
|
||||
-- @return #nil The DCS Positionable is not existing or alive.
|
||||
function POSITIONABLE:GetRandomPointVec3( Radius )
|
||||
self:F2( self.PositionableName )
|
||||
|
||||
local DCSPositionable = self:GetDCSObject()
|
||||
|
||||
if DCSPositionable then
|
||||
local PositionablePointVec3 = DCSPositionable:getPosition().p
|
||||
local PositionableRandomPointVec3 = {}
|
||||
local angle = math.random() * math.pi*2;
|
||||
PositionableRandomPointVec3.x = PositionablePointVec3.x + math.cos( angle ) * math.random() * Radius;
|
||||
PositionableRandomPointVec3.y = PositionablePointVec3.y
|
||||
PositionableRandomPointVec3.z = PositionablePointVec3.z + math.sin( angle ) * math.random() * Radius;
|
||||
|
||||
self:T3( PositionableRandomPointVec3 )
|
||||
return PositionableRandomPointVec3
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns the @{DCSTypes#Vec3} vector indicating the point in 3D of the DCS Positionable within the mission.
|
||||
-- @param Positionable#POSITIONABLE self
|
||||
-- @return DCSTypes#Vec3 The 3D point vector of the DCS Positionable.
|
||||
@@ -209,5 +233,26 @@ function POSITIONABLE:GetVelocity()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns the @{Unit#UNIT} velocity in km/h.
|
||||
-- @param Positionable#POSITIONABLE self
|
||||
-- @return #number The velocity in km/h
|
||||
-- @return #nil The DCS Positionable is not existing or alive.
|
||||
function POSITIONABLE:GetVelocityKMH()
|
||||
self:F2( self.PositionableName )
|
||||
|
||||
local DCSPositionable = self:GetDCSObject()
|
||||
|
||||
if DCSPositionable then
|
||||
local VelocityVec3 = self:GetVelocity()
|
||||
local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec
|
||||
local Velocity = Velocity * 3.6 -- now it is in km/h.
|
||||
self:T3( Velocity )
|
||||
return Velocity
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -77,7 +77,9 @@ end
|
||||
function PROCESS:OnStateChange( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.ProcessUnit.UnitName } )
|
||||
|
||||
MESSAGE:New( "Process " .. self.ProcessName .. " : " .. Event .. " changed to state " .. To, 15 ):ToAll()
|
||||
if self:IsTrace() then
|
||||
MESSAGE:New( "Process " .. self.ProcessName .. " : " .. Event .. " changed to state " .. To, 15 ):ToAll()
|
||||
end
|
||||
|
||||
if self.Scores[To] then
|
||||
|
||||
|
||||
@@ -1,105 +1,185 @@
|
||||
--- @module Task_Assign
|
||||
|
||||
--- PROCESS_ASSIGN class
|
||||
-- @type PROCESS_ASSIGN
|
||||
-- @field Task#TASK_BASE Task
|
||||
-- @field Unit#UNIT ProcessUnit
|
||||
-- @field Zone#ZONE_BASE TargetZone
|
||||
-- @extends Task2#TASK2
|
||||
PROCESS_ASSIGN = {
|
||||
ClassName = "PROCESS_ASSIGN",
|
||||
}
|
||||
--- This module contains the TASK_ASSIGN classes.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 1) @{Task_Assign#TASK_ASSIGN_ACCEPT} class, extends @{Task#TASK_BASE}
|
||||
-- =====================================================================
|
||||
-- The @{Task_Assign#TASK_ASSIGN_ACCEPT} class accepts by default a task for a player. No player intervention is allowed to reject the task.
|
||||
--
|
||||
-- 2) @{Task_Assign#TASK_ASSIGN_MENU_ACCEPT} class, extends @{Task#TASK_BASE}
|
||||
-- ==========================================================================
|
||||
-- The @{Task_Assign#TASK_ASSIGN_MENU_ACCEPT} class accepts a task when the player accepts the task through an added menu option.
|
||||
-- This assignment type is useful to conditionally allow the player to choose whether or not he would accept the task.
|
||||
-- The assignment type also allows to reject the task.
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
-- @module Task_Assign
|
||||
--
|
||||
|
||||
|
||||
--- Creates a new task assignment state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
|
||||
-- @param #PROCESS_ASSIGN self
|
||||
-- @param Task#TASK Task
|
||||
-- @param Unit#UNIT Unit
|
||||
-- @return #PROCESS_ASSIGN self
|
||||
function PROCESS_ASSIGN:New( Task, ProcessUnit, TaskBriefing )
|
||||
do -- PROCESS_ASSIGN_ACCEPT
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, PROCESS:New( "ASSIGN", Task, ProcessUnit ) ) -- #PROCESS_ASSIGN
|
||||
--- PROCESS_ASSIGN_ACCEPT class
|
||||
-- @type PROCESS_ASSIGN_ACCEPT
|
||||
-- @field Task#TASK_BASE Task
|
||||
-- @field Unit#UNIT ProcessUnit
|
||||
-- @field Zone#ZONE_BASE TargetZone
|
||||
-- @extends Task2#TASK2
|
||||
PROCESS_ASSIGN_ACCEPT = {
|
||||
ClassName = "PROCESS_ASSIGN_ACCEPT",
|
||||
}
|
||||
|
||||
self.TaskBriefing = TaskBriefing
|
||||
|
||||
self.Fsm = STATEMACHINE_PROCESS:New( self, {
|
||||
initial = 'UnAssigned',
|
||||
events = {
|
||||
{ name = 'Menu', from = 'UnAssigned', to = 'AwaitAccept' },
|
||||
{ name = 'Assign', from = 'AwaitAccept', to = 'Assigned' },
|
||||
{ name = 'Reject', from = 'AwaitAccept', to = 'Rejected' },
|
||||
{ name = 'Fail', from = 'AwaitAccept', to = 'Rejected' },
|
||||
},
|
||||
callbacks = {
|
||||
onMenu = self.OnMenu,
|
||||
onAssign = self.OnAssign,
|
||||
onReject = self.OnReject,
|
||||
},
|
||||
endstates = {
|
||||
'Assigned', 'Rejected'
|
||||
},
|
||||
} )
|
||||
--- Creates a new task assignment state machine. The process will accept the task by default, no player intervention accepted.
|
||||
-- @param #PROCESS_ASSIGN_ACCEPT self
|
||||
-- @param Task#TASK Task
|
||||
-- @param Unit#UNIT Unit
|
||||
-- @return #PROCESS_ASSIGN_ACCEPT self
|
||||
function PROCESS_ASSIGN_ACCEPT:New( Task, ProcessUnit, TaskBriefing )
|
||||
|
||||
return self
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, PROCESS:New( "ASSIGN_ACCEPT", Task, ProcessUnit ) ) -- #PROCESS_ASSIGN_ACCEPT
|
||||
|
||||
self.TaskBriefing = TaskBriefing
|
||||
|
||||
self.Fsm = STATEMACHINE_PROCESS:New( self, {
|
||||
initial = 'UnAssigned',
|
||||
events = {
|
||||
{ name = 'Start', from = 'UnAssigned', to = 'Assigned' },
|
||||
{ name = 'Fail', from = 'UnAssigned', to = 'Failed' },
|
||||
},
|
||||
callbacks = {
|
||||
onAssign = self.OnAssign,
|
||||
},
|
||||
endstates = {
|
||||
'Assigned', 'Failed'
|
||||
},
|
||||
} )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #PROCESS_ASSIGN_ACCEPT self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_ASSIGN_ACCEPT:OnAssigned( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #PROCESS_ASSIGN self
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_ASSIGN:OnMenu( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
|
||||
|
||||
MESSAGE:New( self.TaskBriefing .. "\nAccess the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled.", 30, "Assignment" ):ToGroup( self.ProcessUnit:GetGroup() )
|
||||
self.MenuText = self.Task.TaskName
|
||||
|
||||
local ProcessGroup = self.ProcessUnit:GetGroup()
|
||||
self.Menu = MENU_GROUP:New( ProcessGroup, "Task " .. self.MenuText .. " acceptance" )
|
||||
self.MenuAcceptTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Accept task " .. self.MenuText, self.Menu, self.MenuAssign, self )
|
||||
self.MenuRejectTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Reject task " .. self.MenuText, self.Menu, self.MenuReject, self )
|
||||
end
|
||||
|
||||
--- Menu function.
|
||||
-- @param #PROCESS_ASSIGN self
|
||||
function PROCESS_ASSIGN:MenuAssign()
|
||||
self:E( )
|
||||
|
||||
self:NextEvent( self.Fsm.Assign )
|
||||
end
|
||||
|
||||
--- Menu function.
|
||||
-- @param #PROCESS_ASSIGN self
|
||||
function PROCESS_ASSIGN:MenuReject()
|
||||
self:E( )
|
||||
|
||||
self:NextEvent( self.Fsm.Reject )
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #PROCESS_ASSIGN self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_ASSIGN:OnAssign( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
|
||||
|
||||
self.Menu:Remove()
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #PROCESS_ASSIGN self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_ASSIGN:OnReject( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
|
||||
|
||||
self.Menu:Remove()
|
||||
self.Task:UnAssignFromUnit( self.ProcessUnit )
|
||||
self.ProcessUnit:Destroy()
|
||||
do -- PROCESS_ASSIGN_MENU_ACCEPT
|
||||
|
||||
--- PROCESS_ASSIGN_MENU_ACCEPT class
|
||||
-- @type PROCESS_ASSIGN_MENU_ACCEPT
|
||||
-- @field Task#TASK_BASE Task
|
||||
-- @field Unit#UNIT ProcessUnit
|
||||
-- @field Zone#ZONE_BASE TargetZone
|
||||
-- @extends Task2#TASK2
|
||||
PROCESS_ASSIGN_MENU_ACCEPT = {
|
||||
ClassName = "PROCESS_ASSIGN_MENU_ACCEPT",
|
||||
}
|
||||
|
||||
|
||||
--- Creates a new task assignment state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
|
||||
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
|
||||
-- @param Task#TASK Task
|
||||
-- @param Unit#UNIT Unit
|
||||
-- @return #PROCESS_ASSIGN_MENU_ACCEPT self
|
||||
function PROCESS_ASSIGN_MENU_ACCEPT:New( Task, ProcessUnit, TaskBriefing )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, PROCESS:New( "ASSIGN_MENU_ACCEPT", Task, ProcessUnit ) ) -- #PROCESS_ASSIGN_MENU_ACCEPT
|
||||
|
||||
self.TaskBriefing = TaskBriefing
|
||||
|
||||
self.Fsm = STATEMACHINE_PROCESS:New( self, {
|
||||
initial = 'UnAssigned',
|
||||
events = {
|
||||
{ name = 'Start', from = 'UnAssigned', to = 'AwaitAccept' },
|
||||
{ name = 'Assign', from = 'AwaitAccept', to = 'Assigned' },
|
||||
{ name = 'Reject', from = 'AwaitAccept', to = 'Rejected' },
|
||||
{ name = 'Fail', from = 'AwaitAccept', to = 'Rejected' },
|
||||
},
|
||||
callbacks = {
|
||||
onStart = self.OnStart,
|
||||
onAssign = self.OnAssign,
|
||||
onReject = self.OnReject,
|
||||
},
|
||||
endstates = {
|
||||
'Assigned', 'Rejected'
|
||||
},
|
||||
} )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_ASSIGN_MENU_ACCEPT:OnStart( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
|
||||
|
||||
MESSAGE:New( self.TaskBriefing .. "\nAccess the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled.", 30, "Assignment" ):ToGroup( self.ProcessUnit:GetGroup() )
|
||||
self.MenuText = self.Task.TaskName
|
||||
|
||||
local ProcessGroup = self.ProcessUnit:GetGroup()
|
||||
self.Menu = MENU_GROUP:New( ProcessGroup, "Task " .. self.MenuText .. " acceptance" )
|
||||
self.MenuAcceptTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Accept task " .. self.MenuText, self.Menu, self.MenuAssign, self )
|
||||
self.MenuRejectTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Reject task " .. self.MenuText, self.Menu, self.MenuReject, self )
|
||||
end
|
||||
|
||||
--- Menu function.
|
||||
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
|
||||
function PROCESS_ASSIGN_MENU_ACCEPT:MenuAssign()
|
||||
self:E( )
|
||||
|
||||
self:NextEvent( self.Fsm.Assign )
|
||||
end
|
||||
|
||||
--- Menu function.
|
||||
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
|
||||
function PROCESS_ASSIGN_MENU_ACCEPT:MenuReject()
|
||||
self:E( )
|
||||
|
||||
self:NextEvent( self.Fsm.Reject )
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_ASSIGN_MENU_ACCEPT:OnAssign( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
|
||||
|
||||
self.Menu:Remove()
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #PROCESS_ASSIGN_MENU_ACCEPT self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_ASSIGN_MENU_ACCEPT:OnReject( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
|
||||
|
||||
self.Menu:Remove()
|
||||
self.Task:UnAssignFromUnit( self.ProcessUnit )
|
||||
self.ProcessUnit:Destroy()
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
--- @module Process_SEAD
|
||||
--- @module Process_BAI
|
||||
|
||||
--- PROCESS_SEAD class
|
||||
-- @type PROCESS_SEAD
|
||||
--- PROCESS_BAI class
|
||||
-- @type PROCESS_BAI
|
||||
-- @field Unit#UNIT ProcessUnit
|
||||
-- @field Set#SET_UNIT TargetSetUnit
|
||||
-- @extends Process#PROCESS
|
||||
PROCESS_SEAD = {
|
||||
ClassName = "PROCESS_SEAD",
|
||||
PROCESS_BAI = {
|
||||
ClassName = "PROCESS_BAI",
|
||||
Fsm = {},
|
||||
TargetSetUnit = nil,
|
||||
}
|
||||
|
||||
|
||||
--- Creates a new SEAD task.
|
||||
-- @param #PROCESS_SEAD self
|
||||
--- Creates a new BAI task.
|
||||
-- @param #PROCESS_BAI self
|
||||
-- @param Task#TASK Task
|
||||
-- @param Unit#UNIT ProcessUnit
|
||||
-- @param Set#SET_UNIT TargetSetUnit
|
||||
-- @return #PROCESS_SEAD self
|
||||
function PROCESS_SEAD:New( Task, ProcessUnit, TargetSetUnit )
|
||||
-- @return #PROCESS_BAI self
|
||||
function PROCESS_BAI:New( Task, ProcessUnit, TargetSetUnit )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, PROCESS:New( "SEAD", Task, ProcessUnit ) ) -- #PROCESS_SEAD
|
||||
local self = BASE:Inherit( self, PROCESS:New( "BAI", Task, ProcessUnit ) ) -- #PROCESS_BAI
|
||||
|
||||
self.TargetSetUnit = TargetSetUnit
|
||||
|
||||
self.Fsm = STATEMACHINE_PROCESS:New( self, {
|
||||
initial = 'Assigned',
|
||||
events = {
|
||||
{ name = 'Await', from = 'Assigned', to = 'Waiting' },
|
||||
{ name = 'Start', from = 'Assigned', to = 'Waiting' },
|
||||
{ name = 'HitTarget', from = 'Waiting', to = 'Destroy' },
|
||||
{ name = 'MoreTargets', from = 'Destroy', to = 'Waiting' },
|
||||
{ name = 'Destroyed', from = 'Destroy', to = 'Success' },
|
||||
@@ -37,7 +37,7 @@ function PROCESS_SEAD:New( Task, ProcessUnit, TargetSetUnit )
|
||||
{ name = 'Fail', from = 'Destroy', to = 'Failed' },
|
||||
},
|
||||
callbacks = {
|
||||
onAwait = self.OnAwait,
|
||||
onStart = self.OnStart,
|
||||
onHitTarget = self.OnHitTarget,
|
||||
onMoreTargets = self.OnMoreTargets,
|
||||
onDestroyed = self.OnDestroyed,
|
||||
@@ -55,28 +55,26 @@ end
|
||||
--- Process Events
|
||||
|
||||
--- StateMachine callback function for a PROCESS
|
||||
-- @param #PROCESS_SEAD self
|
||||
-- @param #PROCESS_BAI self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_SEAD:OnAwait( Fsm, Event, From, To )
|
||||
function PROCESS_BAI:OnStart( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
|
||||
|
||||
self:NextEvent( Fsm.Await )
|
||||
self:NextEvent( Fsm.Start )
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a PROCESS
|
||||
-- @param #PROCESS_SEAD self
|
||||
-- @param #PROCESS_BAI self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Event#EVENTDATA Event
|
||||
function PROCESS_SEAD:OnHitTarget( Fsm, Event, From, To, Event )
|
||||
function PROCESS_BAI:OnHitTarget( Fsm, Event, From, To, Event )
|
||||
|
||||
MESSAGE:New( "TargetCount = " .. self.TargetSetUnit:Count(), 15 ):ToAll()
|
||||
self.TargetSetUnit:Flush()
|
||||
if self.TargetSetUnit:Count() > 0 then
|
||||
self:NextEvent( Fsm.MoreTargets )
|
||||
else
|
||||
@@ -85,58 +83,59 @@ function PROCESS_SEAD:OnHitTarget( Fsm, Event, From, To, Event )
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a PROCESS
|
||||
-- @param #PROCESS_SEAD self
|
||||
-- @param #PROCESS_BAI self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_SEAD:OnMoreTargets( Fsm, Event, From, To )
|
||||
function PROCESS_BAI:OnMoreTargets( Fsm, Event, From, To )
|
||||
|
||||
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a PROCESS
|
||||
-- @param #PROCESS_SEAD self
|
||||
-- @param #PROCESS_BAI self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Event#EVENTDATA DCSEvent
|
||||
function PROCESS_SEAD:OnKilled( Fsm, Event, From, To )
|
||||
function PROCESS_BAI:OnKilled( Fsm, Event, From, To )
|
||||
|
||||
self:NextEvent( Fsm.Restart )
|
||||
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a PROCESS
|
||||
-- @param #PROCESS_SEAD self
|
||||
-- @param #PROCESS_BAI self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_SEAD:OnRestart( Fsm, Event, From, To )
|
||||
function PROCESS_BAI:OnRestart( Fsm, Event, From, To )
|
||||
|
||||
self:NextEvent( Fsm.Menu )
|
||||
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a PROCESS
|
||||
-- @param #PROCESS_SEAD self
|
||||
-- @param #PROCESS_BAI self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_SEAD:OnDestroyed( Fsm, Event, From, To )
|
||||
function PROCESS_BAI:OnDestroyed( Fsm, Event, From, To )
|
||||
|
||||
end
|
||||
|
||||
--- DCS Events
|
||||
|
||||
--- @param #PROCESS_SEAD self
|
||||
--- @param #PROCESS_BAI self
|
||||
-- @param Event#EVENTDATA Event
|
||||
function PROCESS_SEAD:EventDead( Event )
|
||||
function PROCESS_BAI:EventDead( Event )
|
||||
|
||||
if Event.IniUnit then
|
||||
if Event.IniDCSUnit then
|
||||
self.TargetSetUnit:Remove( Event.IniDCSUnitName )
|
||||
self:NextEvent( self.Fsm.HitTarget, Event )
|
||||
end
|
||||
end
|
||||
@@ -28,7 +28,7 @@ function PROCESS_CAS:New( Task, ProcessUnit, TargetSetUnit )
|
||||
self.Fsm = STATEMACHINE_PROCESS:New( self, {
|
||||
initial = 'Assigned',
|
||||
events = {
|
||||
{ name = 'Await', from = 'Assigned', to = 'Waiting' },
|
||||
{ name = 'Start', from = 'Assigned', to = 'Waiting' },
|
||||
{ name = 'HitTarget', from = 'Waiting', to = 'Destroy' },
|
||||
{ name = 'MoreTargets', from = 'Destroy', to = 'Waiting' },
|
||||
{ name = 'Destroyed', from = 'Destroy', to = 'Success' },
|
||||
@@ -37,7 +37,7 @@ function PROCESS_CAS:New( Task, ProcessUnit, TargetSetUnit )
|
||||
{ name = 'Fail', from = 'Destroy', to = 'Failed' },
|
||||
},
|
||||
callbacks = {
|
||||
onAwait = self.OnAwait,
|
||||
onStart = self.OnStart,
|
||||
onHitTarget = self.OnHitTarget,
|
||||
onMoreTargets = self.OnMoreTargets,
|
||||
onDestroyed = self.OnDestroyed,
|
||||
@@ -60,10 +60,10 @@ end
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_CAS:OnAwait( Fsm, Event, From, To )
|
||||
function PROCESS_CAS:OnStart( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
|
||||
|
||||
self:NextEvent( Fsm.Await )
|
||||
self:NextEvent( Fsm.Start )
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a PROCESS
|
||||
@@ -134,7 +134,8 @@ end
|
||||
-- @param Event#EVENTDATA Event
|
||||
function PROCESS_CAS:EventDead( Event )
|
||||
|
||||
if Event.IniUnit then
|
||||
if Event.IniDCSUnit then
|
||||
self.TargetSetUnit:Remove( Event.IniDCSUnitName )
|
||||
self:NextEvent( self.Fsm.HitTarget, Event )
|
||||
end
|
||||
end
|
||||
|
||||
180
Moose Development/Moose/Process_Destroy.lua
Normal file
180
Moose Development/Moose/Process_Destroy.lua
Normal file
@@ -0,0 +1,180 @@
|
||||
--- @module Process_Destroy
|
||||
|
||||
--- PROCESS_DESTROY class
|
||||
-- @type PROCESS_DESTROY
|
||||
-- @field Unit#UNIT ProcessUnit
|
||||
-- @field Set#SET_UNIT TargetSetUnit
|
||||
-- @extends Process#PROCESS
|
||||
PROCESS_DESTROY = {
|
||||
ClassName = "PROCESS_DESTROY",
|
||||
Fsm = {},
|
||||
TargetSetUnit = nil,
|
||||
}
|
||||
|
||||
|
||||
--- Creates a new DESTROY process.
|
||||
-- @param #PROCESS_DESTROY self
|
||||
-- @param Task#TASK Task
|
||||
-- @param Unit#UNIT ProcessUnit
|
||||
-- @param Set#SET_UNIT TargetSetUnit
|
||||
-- @return #PROCESS_DESTROY self
|
||||
function PROCESS_DESTROY:New( Task, ProcessName, ProcessUnit, TargetSetUnit )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, PROCESS:New( ProcessName, Task, ProcessUnit ) ) -- #PROCESS_DESTROY
|
||||
|
||||
self.TargetSetUnit = TargetSetUnit
|
||||
|
||||
self.DisplayInterval = 60
|
||||
self.DisplayCount = 30
|
||||
self.DisplayMessage = true
|
||||
self.DisplayTime = 10 -- 10 seconds is the default
|
||||
self.DisplayCategory = "HQ" -- Targets is the default display category
|
||||
|
||||
self.Fsm = STATEMACHINE_PROCESS:New( self, {
|
||||
initial = 'Assigned',
|
||||
events = {
|
||||
{ name = 'Start', from = 'Assigned', to = 'Waiting' },
|
||||
{ name = 'Start', from = 'Waiting', to = 'Waiting' },
|
||||
{ name = 'HitTarget', from = 'Waiting', to = 'Destroy' },
|
||||
{ name = 'MoreTargets', from = 'Destroy', to = 'Waiting' },
|
||||
{ name = 'Destroyed', from = 'Destroy', to = 'Success' },
|
||||
{ name = 'Fail', from = 'Assigned', to = 'Failed' },
|
||||
{ name = 'Fail', from = 'Waiting', to = 'Failed' },
|
||||
{ name = 'Fail', from = 'Destroy', to = 'Failed' },
|
||||
},
|
||||
callbacks = {
|
||||
onStart = self.OnStart,
|
||||
onWaiting = self.OnWaiting,
|
||||
onHitTarget = self.OnHitTarget,
|
||||
onMoreTargets = self.OnMoreTargets,
|
||||
onDestroyed = self.OnDestroyed,
|
||||
onKilled = self.OnKilled,
|
||||
},
|
||||
endstates = { 'Success', 'Failed' }
|
||||
} )
|
||||
|
||||
|
||||
_EVENTDISPATCHER:OnDead( self.EventDead, self )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Process Events
|
||||
|
||||
--- StateMachine callback function for a PROCESS
|
||||
-- @param #PROCESS_DESTROY self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_DESTROY:OnStart( Fsm, Event, From, To )
|
||||
|
||||
self:NextEvent( Fsm.Start )
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a PROCESS
|
||||
-- @param #PROCESS_DESTROY self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_DESTROY:OnWaiting( Fsm, Event, From, To )
|
||||
|
||||
local TaskGroup = self.ProcessUnit:GetGroup()
|
||||
if self.DisplayCount >= self.DisplayInterval then
|
||||
MESSAGE:New( "Your group with assigned " .. self.Task:GetName() .. " task has " .. self.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed.", 5, "HQ" ):ToGroup( TaskGroup )
|
||||
self.DisplayCount = 1
|
||||
else
|
||||
self.DisplayCount = self.DisplayCount + 1
|
||||
end
|
||||
|
||||
return true -- Process always the event.
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- StateMachine callback function for a PROCESS
|
||||
-- @param #PROCESS_DESTROY self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Event#EVENTDATA Event
|
||||
function PROCESS_DESTROY:OnHitTarget( Fsm, Event, From, To, Event )
|
||||
|
||||
self.TargetSetUnit:Flush()
|
||||
|
||||
if self.TargetSetUnit:FindUnit( Event.IniUnitName ) then
|
||||
self.TargetSetUnit:RemoveUnitsByName( Event.IniUnitName )
|
||||
end
|
||||
|
||||
local TaskGroup = self.ProcessUnit:GetGroup()
|
||||
MESSAGE:New( "You hit a target. Your group with assigned " .. self.Task:GetName() .. " task has " .. self.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed.", 15, "HQ" ):ToGroup( TaskGroup )
|
||||
|
||||
if self.TargetSetUnit:Count() > 0 then
|
||||
self:NextEvent( Fsm.MoreTargets )
|
||||
else
|
||||
self:NextEvent( Fsm.Destroyed )
|
||||
end
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a PROCESS
|
||||
-- @param #PROCESS_DESTROY self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_DESTROY:OnMoreTargets( Fsm, Event, From, To )
|
||||
|
||||
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a PROCESS
|
||||
-- @param #PROCESS_DESTROY self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Event#EVENTDATA DCSEvent
|
||||
function PROCESS_DESTROY:OnKilled( Fsm, Event, From, To )
|
||||
|
||||
self:NextEvent( Fsm.Restart )
|
||||
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a PROCESS
|
||||
-- @param #PROCESS_DESTROY self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_DESTROY:OnRestart( Fsm, Event, From, To )
|
||||
|
||||
self:NextEvent( Fsm.Menu )
|
||||
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a PROCESS
|
||||
-- @param #PROCESS_DESTROY self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_DESTROY:OnDestroyed( Fsm, Event, From, To )
|
||||
|
||||
end
|
||||
|
||||
--- DCS Events
|
||||
|
||||
--- @param #PROCESS_DESTROY self
|
||||
-- @param Event#EVENTDATA Event
|
||||
function PROCESS_DESTROY:EventDead( Event )
|
||||
|
||||
if Event.IniDCSUnit then
|
||||
self.TargetSetUnit:Remove( Event.IniDCSUnitName )
|
||||
self:NextEvent( self.Fsm.HitTarget, Event )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -26,12 +26,12 @@ function PROCESS_ROUTE:New( Task, ProcessUnit, TargetZone )
|
||||
self.DisplayCount = 30
|
||||
self.DisplayMessage = true
|
||||
self.DisplayTime = 10 -- 10 seconds is the default
|
||||
self.DisplayCategory = "Route" -- Route is the default display category
|
||||
self.DisplayCategory = "HQ" -- Route is the default display category
|
||||
|
||||
self.Fsm = STATEMACHINE_PROCESS:New( self, {
|
||||
initial = 'UnArrived',
|
||||
events = {
|
||||
{ name = 'Route', from = 'UnArrived', to = 'Arrived' },
|
||||
{ name = 'Start', from = 'UnArrived', to = 'UnArrived' },
|
||||
{ name = 'Fail', from = 'UnArrived', to = 'Failed' },
|
||||
},
|
||||
callbacks = {
|
||||
@@ -56,27 +56,31 @@ end
|
||||
-- @param #string To
|
||||
function PROCESS_ROUTE:OnLeaveUnArrived( Fsm, Event, From, To )
|
||||
|
||||
local IsInZone = self.ProcessUnit:IsInZone( self.TargetZone )
|
||||
|
||||
if self.DisplayCount >= self.DisplayInterval then
|
||||
if not IsInZone then
|
||||
local ZoneVec2 = self.TargetZone:GetVec2()
|
||||
local ZonePointVec2 = POINT_VEC2:New( ZoneVec2.x, ZoneVec2.y )
|
||||
local TaskUnitVec2 = self.ProcessUnit:GetVec2()
|
||||
local TaskUnitPointVec2 = POINT_VEC2:New( TaskUnitVec2.x, TaskUnitVec2.y )
|
||||
local RouteText = TaskUnitPointVec2:GetBRText( ZonePointVec2 )
|
||||
MESSAGE:New( RouteText, self.DisplayTime, self.DisplayCategory ):ToGroup( self.ProcessUnit:GetGroup() )
|
||||
if self.ProcessUnit:IsAlive() then
|
||||
local IsInZone = self.ProcessUnit:IsInZone( self.TargetZone )
|
||||
|
||||
if self.DisplayCount >= self.DisplayInterval then
|
||||
if not IsInZone then
|
||||
local ZoneVec2 = self.TargetZone:GetVec2()
|
||||
local ZonePointVec2 = POINT_VEC2:New( ZoneVec2.x, ZoneVec2.y )
|
||||
local TaskUnitVec2 = self.ProcessUnit:GetVec2()
|
||||
local TaskUnitPointVec2 = POINT_VEC2:New( TaskUnitVec2.x, TaskUnitVec2.y )
|
||||
local RouteText = self.ProcessUnit:GetCallSign() .. ": Route to " .. TaskUnitPointVec2:GetBRText( ZonePointVec2 ) .. " km to target."
|
||||
MESSAGE:New( RouteText, self.DisplayTime, self.DisplayCategory ):ToGroup( self.ProcessUnit:GetGroup() )
|
||||
end
|
||||
self.DisplayCount = 1
|
||||
else
|
||||
self.DisplayCount = self.DisplayCount + 1
|
||||
end
|
||||
self.DisplayCount = 1
|
||||
else
|
||||
self.DisplayCount = self.DisplayCount + 1
|
||||
|
||||
--if not IsInZone then
|
||||
self:NextEvent( Fsm.Start )
|
||||
--end
|
||||
|
||||
return IsInZone -- if false, then the event will not be executed...
|
||||
end
|
||||
|
||||
if not IsInZone then
|
||||
self:NextEvent( Fsm.Route )
|
||||
end
|
||||
|
||||
return IsInZone -- if false, then the event will not be executed...
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
|
||||
106
Moose Development/Moose/Process_Smoke.lua
Normal file
106
Moose Development/Moose/Process_Smoke.lua
Normal file
@@ -0,0 +1,106 @@
|
||||
--- @module Process_Smoke
|
||||
|
||||
do -- PROCESS_SMOKE_TARGETS
|
||||
|
||||
--- PROCESS_SMOKE_TARGETS class
|
||||
-- @type PROCESS_SMOKE_TARGETS
|
||||
-- @field Task#TASK_BASE Task
|
||||
-- @field Unit#UNIT ProcessUnit
|
||||
-- @field Set#SET_UNIT TargetSetUnit
|
||||
-- @field Zone#ZONE_BASE TargetZone
|
||||
-- @extends Task2#TASK2
|
||||
PROCESS_SMOKE_TARGETS = {
|
||||
ClassName = "PROCESS_SMOKE_TARGETS",
|
||||
}
|
||||
|
||||
|
||||
--- Creates a new task assignment state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
|
||||
-- @param #PROCESS_SMOKE_TARGETS self
|
||||
-- @param Task#TASK Task
|
||||
-- @param Unit#UNIT Unit
|
||||
-- @return #PROCESS_SMOKE_TARGETS self
|
||||
function PROCESS_SMOKE_TARGETS:New( Task, ProcessUnit, TargetSetUnit, TargetZone )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, PROCESS:New( "ASSIGN_MENU_ACCEPT", Task, ProcessUnit ) ) -- #PROCESS_SMOKE_TARGETS
|
||||
|
||||
self.TargetSetUnit = TargetSetUnit
|
||||
self.TargetZone = TargetZone
|
||||
|
||||
self.Fsm = STATEMACHINE_PROCESS:New( self, {
|
||||
initial = 'None',
|
||||
events = {
|
||||
{ name = 'Start', from = 'None', to = 'AwaitSmoke' },
|
||||
{ name = 'Next', from = 'AwaitSmoke', to = 'Smoking' },
|
||||
{ name = 'Next', from = 'Smoking', to = 'AwaitSmoke' },
|
||||
{ name = 'Fail', from = 'Smoking', to = 'Failed' },
|
||||
{ name = 'Fail', from = 'AwaitSmoke', to = 'Failed' },
|
||||
{ name = 'Fail', from = 'None', to = 'Failed' },
|
||||
},
|
||||
callbacks = {
|
||||
onStart = self.OnStart,
|
||||
onNext = self.OnNext,
|
||||
onSmoking = self.OnSmoking,
|
||||
},
|
||||
endstates = {
|
||||
},
|
||||
} )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #PROCESS_SMOKE_TARGETS self
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_SMOKE_TARGETS:OnStart( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
|
||||
|
||||
self:E("Set smoke menu")
|
||||
|
||||
local ProcessGroup = self.ProcessUnit:GetGroup()
|
||||
local MissionMenu = self.Task.Mission:GetMissionMenu( ProcessGroup )
|
||||
|
||||
local function MenuSmoke( MenuParam )
|
||||
self:E( MenuParam )
|
||||
local self = MenuParam.self
|
||||
local SmokeColor = MenuParam.SmokeColor
|
||||
self.SmokeColor = SmokeColor
|
||||
self:NextEvent( self.Fsm.Next )
|
||||
end
|
||||
|
||||
self.Menu = MENU_GROUP:New( ProcessGroup, "Target acquisition", MissionMenu )
|
||||
self.MenuSmokeBlue = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop blue smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Blue } )
|
||||
self.MenuSmokeGreen = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop green smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Green } )
|
||||
self.MenuSmokeOrange = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop Orange smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Orange } )
|
||||
self.MenuSmokeRed = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop Red smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.Red } )
|
||||
self.MenuSmokeWhite = MENU_GROUP_COMMAND:New( ProcessGroup, "Drop White smoke on targets", self.Menu, MenuSmoke, { self = self, SmokeColor = SMOKECOLOR.White } )
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK2
|
||||
-- @param #PROCESS_SMOKE_TARGETS self
|
||||
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function PROCESS_SMOKE_TARGETS:OnSmoking( Fsm, Event, From, To )
|
||||
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
|
||||
|
||||
self.TargetSetUnit:ForEachUnit(
|
||||
--- @param Unit#UNIT SmokeUnit
|
||||
function( SmokeUnit )
|
||||
if math.random( 1, ( 100 * self.TargetSetUnit:Count() ) / 4 ) <= 100 then
|
||||
SCHEDULER:New( self,
|
||||
function()
|
||||
SmokeUnit:Smoke( self.SmokeColor, 150 )
|
||||
end, {}, math.random( 10, 60 )
|
||||
)
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -59,6 +59,8 @@ function SCORING:New( GameName )
|
||||
self.SchedulerId = SCHEDULER:New( self, self._FollowPlayersScheduled, {}, 0, 5 )
|
||||
|
||||
self:ScoreMenu()
|
||||
|
||||
self:OpenCSV( GameName)
|
||||
|
||||
return self
|
||||
|
||||
@@ -287,7 +289,7 @@ function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score )
|
||||
self.Players[PlayerName].Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
|
||||
|
||||
MESSAGE:New( "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " ..
|
||||
Score .. " points!",
|
||||
Score .. " task score!",
|
||||
30 ):ToAll()
|
||||
|
||||
self:ScoreCSV( PlayerName, "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() )
|
||||
@@ -295,17 +297,28 @@ end
|
||||
|
||||
|
||||
--- Registers Mission Scores for possible multiple players that contributed in the Mission.
|
||||
function SCORING:_AddMissionScore( MissionName, Score )
|
||||
self:F( { MissionName, Score } )
|
||||
-- @param #SCORING self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Unit#UNIT PlayerUnit
|
||||
-- @param #string Text
|
||||
-- @param #number Score
|
||||
function SCORING:_AddMissionScore( Mission, Text, Score )
|
||||
|
||||
local MissionName = Mission:GetName()
|
||||
|
||||
self:F( { Mission, Text, Score } )
|
||||
|
||||
for PlayerName, PlayerData in pairs( self.Players ) do
|
||||
|
||||
if PlayerData.Mission[MissionName] then
|
||||
|
||||
PlayerData.Score = PlayerData.Score + Score
|
||||
PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score
|
||||
MESSAGE:New( "Player '" .. PlayerName .. "' has finished Mission '" .. MissionName .. "'. " ..
|
||||
Score .. " Score points added.",
|
||||
20 ):ToAll()
|
||||
|
||||
MESSAGE:New( "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " ..
|
||||
Score .. " mission score!",
|
||||
60 ):ToAll()
|
||||
|
||||
self:ScoreCSV( PlayerName, "MISSION_" .. MissionName:gsub( ' ', '_' ), 1, Score )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -308,7 +308,7 @@ end
|
||||
-- @param #SET_BASE self
|
||||
-- @param #string ObjectName
|
||||
function SET_BASE:Remove( ObjectName )
|
||||
self:F2( ObjectName )
|
||||
self:E( ObjectName )
|
||||
|
||||
local t = self.Set[ObjectName]
|
||||
|
||||
@@ -339,6 +339,8 @@ function SET_BASE:Remove( ObjectName )
|
||||
self.Set[ObjectName] = nil
|
||||
end
|
||||
|
||||
self:Flush()
|
||||
|
||||
end
|
||||
|
||||
--- Retrieves the amount of objects in the @{Set#SET_BASE} and derived classes.
|
||||
@@ -349,6 +351,8 @@ function SET_BASE:Count()
|
||||
return self.List.Count
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Copies the Filter criteria from a given Set (for rebuilding a new Set based on an existing Set).
|
||||
-- @param #SET_BASE self
|
||||
-- @param #SET_BASE BaseSet
|
||||
@@ -380,6 +384,20 @@ function SET_BASE:SetIteratorIntervals( YieldInterval, TimeInterval )
|
||||
end
|
||||
|
||||
|
||||
--- Filters for the defined collection.
|
||||
-- @param #SET_BASE self
|
||||
-- @return #SET_BASE self
|
||||
function SET_BASE:FilterOnce()
|
||||
|
||||
for ObjectName, Object in pairs( self.Database ) do
|
||||
|
||||
if self:IsIncludeObject( Object ) then
|
||||
self:Add( ObjectName, Object )
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Starts the filtering for the defined collection.
|
||||
-- @param #SET_BASE self
|
||||
@@ -399,13 +417,25 @@ function SET_BASE:_FilterStart()
|
||||
_EVENTDISPATCHER:OnCrash( self._EventOnDeadOrCrash, self )
|
||||
|
||||
-- Follow alive players and clients
|
||||
-- _EVENTDISPATCHER:OnPlayerEnterUnit( self._EventOnPlayerEnterUnit, self )
|
||||
-- _EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventOnPlayerLeaveUnit, self )
|
||||
_EVENTDISPATCHER:OnPlayerEnterUnit( self._EventOnPlayerEnterUnit, self )
|
||||
_EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventOnPlayerLeaveUnit, self )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stops the filtering for the defined collection.
|
||||
-- @param #SET_BASE self
|
||||
-- @return #SET_BASE self
|
||||
function SET_BASE:FilterStop()
|
||||
|
||||
_EVENTDISPATCHER:OnBirthRemove( self )
|
||||
_EVENTDISPATCHER:OnDeadRemove( self )
|
||||
_EVENTDISPATCHER:OnCrashRemove( self )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Iterate the SET_BASE while identifying the nearest object from a @{Point#POINT_VEC2}.
|
||||
-- @param #SET_BASE self
|
||||
-- @param Point#POINT_VEC2 PointVec2 A @{Point#POINT_VEC2} object from where to evaluate the closest object in the set.
|
||||
@@ -469,6 +499,7 @@ function SET_BASE:_EventOnBirth( Event )
|
||||
self:T3( ObjectName, Object )
|
||||
if self:IsIncludeObject( Object ) then
|
||||
self:Add( ObjectName, Object )
|
||||
self:Flush()
|
||||
--self:_EventOnPlayerEnterUnit( Event )
|
||||
end
|
||||
end
|
||||
@@ -478,49 +509,59 @@ end
|
||||
-- @param #SET_BASE self
|
||||
-- @param Event#EVENTDATA Event
|
||||
function SET_BASE:_EventOnDeadOrCrash( Event )
|
||||
self:F3( { Event } )
|
||||
self:E( { Event } )
|
||||
self:Flush()
|
||||
|
||||
if Event.IniDCSUnit then
|
||||
local ObjectName, Object = self:FindInDatabase( Event )
|
||||
if ObjectName and Object then
|
||||
self:E({ObjectName, Object})
|
||||
if ObjectName and Object ~= nil then
|
||||
self:Remove( ObjectName )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
----- Handles the OnPlayerEnterUnit event to fill the active players table (with the unit filter applied).
|
||||
---- @param #SET_BASE self
|
||||
---- @param Event#EVENTDATA Event
|
||||
--function SET_BASE:_EventOnPlayerEnterUnit( Event )
|
||||
-- self:F3( { Event } )
|
||||
--
|
||||
-- if Event.IniDCSUnit then
|
||||
-- if self:IsIncludeObject( Event.IniDCSUnit ) then
|
||||
-- if not self.PlayersAlive[Event.IniDCSUnitName] then
|
||||
-- self:E( { "Add player for unit:", Event.IniDCSUnitName, Event.IniDCSUnit:getPlayerName() } )
|
||||
-- self.PlayersAlive[Event.IniDCSUnitName] = Event.IniDCSUnit:getPlayerName()
|
||||
-- self.ClientsAlive[Event.IniDCSUnitName] = _DATABASE.Clients[ Event.IniDCSUnitName ]
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
--end
|
||||
--
|
||||
----- Handles the OnPlayerLeaveUnit event to clean the active players table.
|
||||
---- @param #SET_BASE self
|
||||
---- @param Event#EVENTDATA Event
|
||||
--function SET_BASE:_EventOnPlayerLeaveUnit( Event )
|
||||
-- self:F3( { Event } )
|
||||
--
|
||||
-- if Event.IniDCSUnit then
|
||||
-- if self:IsIncludeObject( Event.IniDCSUnit ) then
|
||||
-- if self.PlayersAlive[Event.IniDCSUnitName] then
|
||||
-- self:E( { "Cleaning player for unit:", Event.IniDCSUnitName, Event.IniDCSUnit:getPlayerName() } )
|
||||
-- self.PlayersAlive[Event.IniDCSUnitName] = nil
|
||||
-- self.ClientsAlive[Event.IniDCSUnitName] = nil
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
--end
|
||||
--- Handles the OnPlayerEnterUnit event to fill the active players table (with the unit filter applied).
|
||||
-- @param #SET_BASE self
|
||||
-- @param Event#EVENTDATA Event
|
||||
function SET_BASE:_EventOnPlayerEnterUnit( Event )
|
||||
self:F3( { Event } )
|
||||
|
||||
if Event.IniDCSUnit then
|
||||
local ObjectName, Object = self:AddInDatabase( Event )
|
||||
self:T3( ObjectName, Object )
|
||||
if self:IsIncludeObject( Object ) then
|
||||
self:Add( ObjectName, Object )
|
||||
--self:_EventOnPlayerEnterUnit( Event )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Handles the OnPlayerLeaveUnit event to clean the active players table.
|
||||
-- @param #SET_BASE self
|
||||
-- @param Event#EVENTDATA Event
|
||||
function SET_BASE:_EventOnPlayerLeaveUnit( Event )
|
||||
self:F3( { Event } )
|
||||
|
||||
local ObjectName = Event.IniDCSUnit
|
||||
if Event.IniDCSUnit then
|
||||
if Event.IniDCSGroup then
|
||||
local GroupUnits = Event.IniDCSGroup:getUnits()
|
||||
local PlayerCount = 0
|
||||
for _, DCSUnit in pairs( GroupUnits ) do
|
||||
if DCSUnit ~= Event.IniDCSUnit then
|
||||
if DCSUnit:getPlayer() ~= nil then
|
||||
PlayerCount = PlayerCount + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
self:E(PlayerCount)
|
||||
if PlayerCount == 0 then
|
||||
self:Remove( Event.IniDCSGroupName )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Iterators
|
||||
|
||||
@@ -812,6 +853,8 @@ function SET_GROUP:FilterStart()
|
||||
self:_FilterStart()
|
||||
end
|
||||
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1046,10 +1089,6 @@ function SET_UNIT:New()
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.UNITS ) )
|
||||
|
||||
_EVENTDISPATCHER:OnBirth( self._EventOnBirth, self )
|
||||
_EVENTDISPATCHER:OnDead( self._EventOnDeadOrCrash, self )
|
||||
_EVENTDISPATCHER:OnCrash( self._EventOnDeadOrCrash, self )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1221,6 +1260,15 @@ function SET_UNIT:FilterHasRadar( RadarTypes )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Builds a set of SEADable units.
|
||||
-- @param #SET_UNIT self
|
||||
-- @return #SET_UNIT self
|
||||
function SET_UNIT:FilterHasSEAD()
|
||||
|
||||
self.Filter.SEAD = true
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Starts the filtering.
|
||||
@@ -1259,9 +1307,10 @@ end
|
||||
-- @return #string The name of the UNIT
|
||||
-- @return #table The UNIT
|
||||
function SET_UNIT:FindInDatabase( Event )
|
||||
self:F3( { Event } )
|
||||
self:E( { Event.IniDCSUnitName, self.Set[Event.IniDCSUnitName], Event } )
|
||||
|
||||
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
|
||||
|
||||
return Event.IniDCSUnitName, self.Set[Event.IniDCSUnitName]
|
||||
end
|
||||
|
||||
--- Iterate the SET_UNIT and call an interator function for each **alive** UNIT, providing the UNIT and optional parameters.
|
||||
@@ -1320,6 +1369,38 @@ function SET_UNIT:ForEachUnitNotInZone( ZoneObject, IteratorFunction, ... )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Returns a comma separated string of the unit types with a count in the @{Set}.
|
||||
-- @param #SET_UNIT self
|
||||
-- @return #string The unit types string
|
||||
function SET_UNIT:GetUnitTypesText()
|
||||
self:F2()
|
||||
|
||||
local MT = {} -- Message Text
|
||||
local UnitTypes = {}
|
||||
|
||||
self:Flush()
|
||||
|
||||
for UnitID, UnitData in pairs( self:GetSet() ) do
|
||||
local TextUnit = UnitData -- Unit#UNIT
|
||||
if TextUnit:IsAlive() then
|
||||
local UnitType = TextUnit:GetTypeName()
|
||||
|
||||
if not UnitTypes[UnitType] then
|
||||
UnitTypes[UnitType] = 1
|
||||
else
|
||||
UnitTypes[UnitType] = UnitTypes[UnitType] + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for UnitTypeID, UnitType in pairs( UnitTypes ) do
|
||||
MT[#MT+1] = UnitType .. " of " .. UnitTypeID
|
||||
end
|
||||
|
||||
return table.concat( MT, ", " )
|
||||
end
|
||||
|
||||
|
||||
--- Returns if the @{Set} has targets having a radar (of a given type).
|
||||
-- @param #SET_UNIT self
|
||||
-- @param DCSUnit#Unit.RadarType RadarType
|
||||
@@ -1336,7 +1417,7 @@ function SET_UNIT:HasRadar( RadarType )
|
||||
else
|
||||
HasSensors = UnitSensorTest:HasSensors( Unit.SensorType.RADAR )
|
||||
end
|
||||
self:E(HasSensors)
|
||||
self:T3(HasSensors)
|
||||
if HasSensors then
|
||||
RadarCount = RadarCount + 1
|
||||
end
|
||||
@@ -1345,6 +1426,29 @@ function SET_UNIT:HasRadar( RadarType )
|
||||
return RadarCount
|
||||
end
|
||||
|
||||
--- Returns if the @{Set} has targets that can be SEADed.
|
||||
-- @param #SET_UNIT self
|
||||
-- @return #number The amount of SEADable units in the Set
|
||||
function SET_UNIT:HasSEAD()
|
||||
self:F2()
|
||||
|
||||
local SEADCount = 0
|
||||
for UnitID, UnitData in pairs( self:GetSet()) do
|
||||
local UnitSEAD = UnitData -- Unit#UNIT
|
||||
if UnitSEAD:IsAlive() then
|
||||
local UnitSEADAttributes = UnitSEAD:GetDesc().attributes
|
||||
|
||||
local HasSEAD = UnitSEAD:HasSEAD()
|
||||
|
||||
self:T3(HasSEAD)
|
||||
if HasSEAD then
|
||||
SEADCount = SEADCount + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return SEADCount
|
||||
end
|
||||
|
||||
--- Returns if the @{Set} has ground targets.
|
||||
-- @param #SET_UNIT self
|
||||
@@ -1363,6 +1467,23 @@ function SET_UNIT:HasGroundUnits()
|
||||
return GroundUnitCount
|
||||
end
|
||||
|
||||
--- Returns if the @{Set} has friendly ground units.
|
||||
-- @param #SET_UNIT self
|
||||
-- @return #number The amount of ground targets in the Set.
|
||||
function SET_UNIT:HasFriendlyUnits( FriendlyCoalition )
|
||||
self:F2()
|
||||
|
||||
local FriendlyUnitCount = 0
|
||||
for UnitID, UnitData in pairs( self:GetSet()) do
|
||||
local UnitTest = UnitData -- Unit#UNIT
|
||||
if UnitTest:IsFriendly( FriendlyCoalition ) then
|
||||
FriendlyUnitCount = FriendlyUnitCount + 1
|
||||
end
|
||||
end
|
||||
|
||||
return FriendlyUnitCount
|
||||
end
|
||||
|
||||
|
||||
|
||||
----- Iterate the SET_UNIT and call an interator function for each **alive** player, providing the Unit of the player and optional parameters.
|
||||
@@ -1457,10 +1578,10 @@ function SET_UNIT:IsIncludeObject( MUnit )
|
||||
if self.Filter.RadarTypes then
|
||||
local MUnitRadar = false
|
||||
for RadarTypeID, RadarType in pairs( self.Filter.RadarTypes ) do
|
||||
self:E( { "Radar:", RadarType } )
|
||||
self:T3( { "Radar:", RadarType } )
|
||||
if MUnit:HasSensors( Unit.SensorType.RADAR, RadarType ) == true then
|
||||
if MUnit:GetRadar() == true then -- This call is necessary to evaluate the SEAD capability.
|
||||
self:E( "RADAR Found" )
|
||||
self:T3( "RADAR Found" )
|
||||
end
|
||||
MUnitRadar = true
|
||||
end
|
||||
@@ -1468,6 +1589,15 @@ function SET_UNIT:IsIncludeObject( MUnit )
|
||||
MUnitInclude = MUnitInclude and MUnitRadar
|
||||
end
|
||||
|
||||
if self.Filter.SEAD then
|
||||
local MUnitSEAD = false
|
||||
if MUnit:HasSEAD() == true then
|
||||
self:T3( "SEAD Found" )
|
||||
MUnitSEAD = true
|
||||
end
|
||||
MUnitInclude = MUnitInclude and MUnitSEAD
|
||||
end
|
||||
|
||||
self:T2( MUnitInclude )
|
||||
return MUnitInclude
|
||||
end
|
||||
|
||||
@@ -92,7 +92,7 @@ function STATEMACHINE:_create_transition(name)
|
||||
self:E( { name = name } )
|
||||
return function(self, ...)
|
||||
local can, to = self:can(name)
|
||||
self:E( { name, can, to } )
|
||||
self:T( { name, can, to } )
|
||||
|
||||
if can then
|
||||
local from = self.current
|
||||
@@ -113,11 +113,12 @@ function STATEMACHINE:_create_transition(name)
|
||||
sub.fsm.fsmparent = self
|
||||
sub.fsm.returnevents = sub.returnevents
|
||||
sub.fsm[sub.event]( sub.fsm )
|
||||
execute = false
|
||||
execute = true
|
||||
end
|
||||
|
||||
local fsmparent, event = self:_isendstate( to )
|
||||
if fsmparent and event then
|
||||
self:E( { "end state: ", fsmparent, event } )
|
||||
self:_call_handler(self["onenter" .. to] or self["on" .. to], params)
|
||||
self:_call_handler(self["onafter" .. name] or self["on" .. name], params)
|
||||
self:_call_handler(self["onstatechange"], params)
|
||||
@@ -126,6 +127,7 @@ function STATEMACHINE:_create_transition(name)
|
||||
end
|
||||
|
||||
if execute then
|
||||
self:E( { "execute: " .. to, name } )
|
||||
self:_call_handler(self["onenter" .. to] or self["on" .. to], params)
|
||||
self:_call_handler(self["onafter" .. name] or self["on" .. name], params)
|
||||
self:_call_handler(self["onstatechange"], params)
|
||||
@@ -161,6 +163,8 @@ function STATEMACHINE:_isendstate( state )
|
||||
local to = event and event.map[fromstate] or event.map['*']
|
||||
if to and to == state then
|
||||
return fsmparent, eventname
|
||||
else
|
||||
self:E( { "could not find parent event name for state", fromstate, to } )
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -253,7 +257,7 @@ STATEMACHINE_TASK = {
|
||||
--- Creates a new STATEMACHINE_TASK object.
|
||||
-- @param #STATEMACHINE_TASK self
|
||||
-- @return #STATEMACHINE_TASK
|
||||
function STATEMACHINE_TASK:New( Task, options )
|
||||
function STATEMACHINE_TASK:New( Task, TaskUnit, options )
|
||||
|
||||
local FsmTask = routines.utils.deepCopy( self ) -- Create a new self instance
|
||||
local Parent = STATEMACHINE:New(options)
|
||||
@@ -262,13 +266,18 @@ function STATEMACHINE_TASK:New( Task, options )
|
||||
FsmTask.__index = FsmTask
|
||||
|
||||
FsmTask["onstatechange"] = Task.OnStateChange
|
||||
FsmTask["onAssigned"] = Task.OnAssigned
|
||||
FsmTask["onSuccess"] = Task.OnSuccess
|
||||
FsmTask["onFailed"] = Task.OnFailed
|
||||
|
||||
FsmTask.Task = Task
|
||||
FsmTask.TaskUnit = TaskUnit
|
||||
|
||||
return FsmTask
|
||||
end
|
||||
|
||||
function STATEMACHINE_TASK:_call_handler( handler, params )
|
||||
if handler then
|
||||
return handler( self.Task, unpack( params ) )
|
||||
return handler( self.Task, self.TaskUnit, unpack( params ) )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,10 +1,60 @@
|
||||
--- @module Task
|
||||
--- This module contains the TASK_BASE class.
|
||||
--
|
||||
-- 1) @{#TASK_BASE} class, extends @{Base#BASE}
|
||||
-- ============================================
|
||||
-- 1.1) The @{#TASK_BASE} class implements the methods for task orchestration within MOOSE.
|
||||
-- ----------------------------------------------------------------------------------------
|
||||
-- The class provides a couple of methods to:
|
||||
--
|
||||
-- * @{#TASK_BASE.AssignToGroup}():Assign a task to a group (of players).
|
||||
-- * @{#TASK_BASE.AddProcess}():Add a @{Process} to a task.
|
||||
-- * @{#TASK_BASE.RemoveProcesses}():Remove a running @{Process} from a running task.
|
||||
-- * @{#TASK_BASE.AddStateMachine}():Add a @{StateMachine} to a task.
|
||||
-- * @{#TASK_BASE.RemoveStateMachines}():Remove @{StateMachine}s from a task.
|
||||
-- * @{#TASK_BASE.HasStateMachine}():Enquire if the task has a @{StateMachine}
|
||||
-- * @{#TASK_BASE.AssignToUnit}(): Assign a task to a unit. (Needs to be implemented in the derived classes from @{#TASK_BASE}.
|
||||
-- * @{#TASK_BASE.UnAssignFromUnit}(): Unassign the task from a unit.
|
||||
--
|
||||
-- 1.2) Set and enquire task status (beyond the task state machine processing).
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- A task needs to implement as a minimum the following task states:
|
||||
--
|
||||
-- * **Success**: Expresses the successful execution and finalization of the task.
|
||||
-- * **Failed**: Expresses the failure of a task.
|
||||
-- * **Planned**: Expresses that the task is created, but not yet in execution and is not assigned yet.
|
||||
-- * **Assigned**: Expresses that the task is assigned to a Group of players, and that the task is in execution mode.
|
||||
--
|
||||
-- A task may also implement the following task states:
|
||||
--
|
||||
-- * **Rejected**: Expresses that the task is rejected by a player, who was requested to accept the task.
|
||||
-- * **Cancelled**: Expresses that the task is cancelled by HQ or through a logical situation where a cancellation of the task is required.
|
||||
--
|
||||
-- A task can implement more statusses than the ones outlined above. Please consult the documentation of the specific tasks to understand the different status modelled.
|
||||
--
|
||||
-- The status of tasks can be set by the methods **State** followed by the task status. An example is `StateAssigned()`.
|
||||
-- The status of tasks can be enquired by the methods **IsState** followed by the task status name. An example is `if IsStateAssigned() then`.
|
||||
--
|
||||
-- 1.3) Add scoring when reaching a certain task status:
|
||||
-- -----------------------------------------------------
|
||||
-- Upon reaching a certain task status in a task, additional scoring can be given. If the Mission has a scoring system attached, the scores will be added to the mission scoring.
|
||||
-- Use the method @{#TASK_BASE.AddScore}() to add scores when a status is reached.
|
||||
--
|
||||
-- 1.4) Task briefing:
|
||||
-- -------------------
|
||||
-- A task briefing can be given that is shown to the player when he is assigned to the task.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Authors: FlightControl - Design and Programming
|
||||
--
|
||||
-- @module Task
|
||||
|
||||
--- The TASK_BASE class
|
||||
-- @type TASK_BASE
|
||||
-- @field Scheduler#SCHEDULER TaskScheduler
|
||||
-- @field Mission#MISSION Mission
|
||||
-- @field StateMachine#STATEMACHINE Fsm
|
||||
-- @field Set#SET_GROUP SetGroup The Set of Groups assigned to the Task
|
||||
-- @extends Base#BASE
|
||||
TASK_BASE = {
|
||||
ClassName = "TASK_BASE",
|
||||
@@ -12,35 +62,67 @@ TASK_BASE = {
|
||||
Processes = {},
|
||||
Players = nil,
|
||||
Scores = {},
|
||||
Menu = {},
|
||||
SetGroup = nil,
|
||||
}
|
||||
|
||||
|
||||
--- Instantiates a new TASK_BASE. Should never be used. Interface Class.
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Mission#MISSION The mission wherein the Task is registered.
|
||||
-- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned.
|
||||
-- @param #string TaskName The name of the Task
|
||||
-- @param #string TaskType The type of the Task
|
||||
-- @param #string TaskCategory The category of the Task (A2G, A2A, Transport, ... )
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:New( Mission, TaskName, TaskType, TaskCategory )
|
||||
function TASK_BASE:New( Mission, SetGroup, TaskName, TaskType, TaskCategory )
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
self:F()
|
||||
self:E( "New TASK " .. TaskName )
|
||||
|
||||
self.Processes = {}
|
||||
self.Fsm = {}
|
||||
self.Mission = Mission
|
||||
self.TaskName = TaskName
|
||||
self.TaskType = TaskType
|
||||
self.TaskCategory = TaskCategory
|
||||
self.TaskID = 0
|
||||
self.TaskBriefing = "You are assigned to the task: " .. self.TaskName .. "."
|
||||
|
||||
self.Mission = Mission
|
||||
self.SetGroup = SetGroup
|
||||
|
||||
self:SetCategory( TaskCategory )
|
||||
self:SetType( TaskType )
|
||||
self:SetName( TaskName )
|
||||
self:SetID( Mission:GetNextTaskID( self ) ) -- The Mission orchestrates the task sequences ..
|
||||
|
||||
self.TaskBriefing = "You are assigned to the task: " .. self.TaskName .. "."
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Cleans all references of a TASK_BASE.
|
||||
-- @param #TASK_BASE self
|
||||
-- @return #nil
|
||||
function TASK_BASE:CleanUp()
|
||||
|
||||
_EVENTDISPATCHER:OnPlayerLeaveRemove( self )
|
||||
_EVENTDISPATCHER:OnDeadRemove( self )
|
||||
_EVENTDISPATCHER:OnCrashRemove( self )
|
||||
_EVENTDISPATCHER:OnPilotDeadRemove( self )
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Assign the @{Task}to a @{Group}.
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Group#GROUP TaskGroup
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:AssignToGroup( TaskGroup )
|
||||
self:F2( TaskGroup:GetName() )
|
||||
|
||||
local TaskGroupName = TaskGroup:GetName()
|
||||
|
||||
TaskGroup:SetState( TaskGroup, "Assigned", self )
|
||||
|
||||
self:RemoveMenuForGroup( TaskGroup )
|
||||
self:SetAssignedMenuForGroup( TaskGroup )
|
||||
|
||||
local TaskUnits = TaskGroup:GetUnits()
|
||||
for UnitID, UnitData in pairs( TaskUnits ) do
|
||||
local TaskUnit = UnitData -- Unit#UNIT
|
||||
@@ -49,77 +131,58 @@ function TASK_BASE:AssignToGroup( TaskGroup )
|
||||
self:AssignToUnit( TaskUnit )
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Add Process to @{Task} with key @{Unit}
|
||||
--- Send the briefng message of the @{Task} to the assigned @{Group}s.
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:AddProcess( TaskUnit, Process )
|
||||
local TaskUnitName = TaskUnit:GetName()
|
||||
self.Processes[TaskUnitName] = self.Processes[TaskUnitName] or {}
|
||||
self.Processes[TaskUnitName][#self.Processes[TaskUnitName]+1] = Process
|
||||
return Process
|
||||
end
|
||||
function TASK_BASE:SendBriefingToAssignedGroups()
|
||||
self:F2()
|
||||
|
||||
for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||
|
||||
--- Remove Processes from @{Task} with key @{Unit}
|
||||
-- @param #TASK_BASE self
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:RemoveProcesses( TaskUnit, FailProcesses )
|
||||
local TaskUnitName = TaskUnit:GetName()
|
||||
for _, ProcessData in pairs( self.Processes[TaskUnitName] ) do
|
||||
local Process = ProcessData -- Process#PROCESS
|
||||
if FailProcesses then
|
||||
Process.Fsm:Fail()
|
||||
if self:IsAssignedToGroup( TaskGroup ) then
|
||||
TaskGroup:Message( self.TaskBriefing, 60 )
|
||||
end
|
||||
Process:StopEvents()
|
||||
Process = nil
|
||||
self.Processes[TaskUnitName][_] = nil
|
||||
self:E( self.Processes[TaskUnitName][_] )
|
||||
end
|
||||
self.Processes[TaskUnitName] = nil
|
||||
end
|
||||
|
||||
--- Add a FiniteStateMachine to @{Task} with key @{Unit}
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:AddStateMachine( TaskUnit, Fsm )
|
||||
local TaskUnitName = TaskUnit:GetName()
|
||||
self.Fsm[TaskUnitName] = self.Fsm[TaskUnitName] or {}
|
||||
self.Fsm[TaskUnitName][#self.Fsm[TaskUnitName]+1] = Fsm
|
||||
return Fsm
|
||||
end
|
||||
|
||||
--- Remove FiniteStateMachines from @{Task} with key @{Unit}
|
||||
--- Assign the @{Task} from the @{Group}s.
|
||||
-- @param #TASK_BASE self
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:RemoveStateMachines( TaskUnit )
|
||||
local TaskUnitName = TaskUnit:GetName()
|
||||
for _, Fsm in pairs( self.Fsm[TaskUnitName] ) do
|
||||
Fsm = nil
|
||||
self.Fsm[TaskUnitName][_] = nil
|
||||
self:E( self.Fsm[TaskUnitName][_] )
|
||||
function TASK_BASE:UnAssignFromGroups()
|
||||
self:F2()
|
||||
|
||||
for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||
|
||||
TaskGroup:SetState( TaskGroup, "Assigned", nil )
|
||||
local TaskUnits = TaskGroup:GetUnits()
|
||||
for UnitID, UnitData in pairs( TaskUnits ) do
|
||||
local TaskUnit = UnitData -- Unit#UNIT
|
||||
local PlayerName = TaskUnit:GetPlayerName()
|
||||
if PlayerName ~= nil or PlayerName ~= "" then
|
||||
self:UnAssignFromUnit( TaskUnit )
|
||||
end
|
||||
end
|
||||
end
|
||||
self.Fsm[TaskUnitName] = nil
|
||||
end
|
||||
|
||||
--- Checks if there is a FiniteStateMachine assigned to @{Unit} for @{Task}
|
||||
--- Returns if the @{Task} is assigned to the Group.
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:HasStateMachine( TaskUnit )
|
||||
local TaskUnitName = TaskUnit:GetName()
|
||||
self:F( { TaskUnitName, self.Fsm[TaskUnitName] ~= nil } )
|
||||
return ( self.Fsm[TaskUnitName] ~= nil )
|
||||
-- @param Group#GROUP TaskGroup
|
||||
-- @return #boolean
|
||||
function TASK_BASE:IsAssignedToGroup( TaskGroup )
|
||||
|
||||
local TaskGroupName = TaskGroup:GetName()
|
||||
|
||||
if self:IsStateAssigned() then
|
||||
if TaskGroup:GetState( TaskGroup, "Assigned" ) == self then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Assign the @{Task}to an alive @{Unit}.
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
@@ -134,17 +197,291 @@ end
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:UnAssignFromUnit( TaskUnit, FailProcesses )
|
||||
self:F( TaskUnit:GetName() )
|
||||
function TASK_BASE:UnAssignFromUnit( TaskUnitName )
|
||||
self:F( TaskUnitName )
|
||||
|
||||
if self:HasStateMachine( TaskUnit ) == true then
|
||||
self:RemoveStateMachines( TaskUnit )
|
||||
self:RemoveProcesses( TaskUnit, FailProcesses )
|
||||
if self:HasStateMachine( TaskUnitName ) == true then
|
||||
self:RemoveStateMachines( TaskUnitName )
|
||||
self:RemoveProcesses( TaskUnitName )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the menu options of the @{Task} to all the groups in the SetGroup.
|
||||
-- @param #TASK_BASE self
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:SetPlannedMenu()
|
||||
|
||||
local MenuText = self:GetPlannedMenuText()
|
||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||
if not self:IsAssignedToGroup( TaskGroup ) then
|
||||
self:SetPlannedMenuForGroup( TaskGroup, MenuText )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Set the menu options of the @{Task} to all the groups in the SetGroup.
|
||||
-- @param #TASK_BASE self
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:SetAssignedMenu()
|
||||
|
||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||
if self:IsAssignedToGroup( TaskGroup ) then
|
||||
self:SetAssignedMenuForGroup( TaskGroup )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove the menu options of the @{Task} to all the groups in the SetGroup.
|
||||
-- @param #TASK_BASE self
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:RemoveMenu()
|
||||
|
||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||
self:RemoveMenuForGroup( TaskGroup )
|
||||
end
|
||||
end
|
||||
|
||||
--- Set the planned menu option of the @{Task}.
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Group#GROUP TaskGroup
|
||||
-- @param #string MenuText The menu text.
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:SetPlannedMenuForGroup( TaskGroup, MenuText )
|
||||
self:E( TaskGroup:GetName() )
|
||||
|
||||
local TaskMission = self.Mission:GetName()
|
||||
local TaskCategory = self:GetCategory()
|
||||
local TaskType = self:GetType()
|
||||
|
||||
local Mission = self.Mission
|
||||
|
||||
Mission.MenuMission = Mission.MenuMission or {}
|
||||
local MenuMission = Mission.MenuMission
|
||||
|
||||
Mission.MenuCategory = Mission.MenuCategory or {}
|
||||
local MenuCategory = Mission.MenuCategory
|
||||
|
||||
Mission.MenuType = Mission.MenuType or {}
|
||||
local MenuType = Mission.MenuType
|
||||
|
||||
self.Menu = self.Menu or {}
|
||||
local Menu = self.Menu
|
||||
|
||||
local TaskGroupName = TaskGroup:GetName()
|
||||
MenuMission[TaskGroupName] = MenuMission[TaskGroupName] or MENU_GROUP:New( TaskGroup, TaskMission, nil )
|
||||
|
||||
MenuCategory[TaskGroupName] = MenuCategory[TaskGroupName] or {}
|
||||
MenuCategory[TaskGroupName][TaskCategory] = MenuCategory[TaskGroupName][TaskCategory] or MENU_GROUP:New( TaskGroup, TaskCategory, MenuMission[TaskGroupName] )
|
||||
|
||||
MenuType[TaskGroupName] = MenuType[TaskGroupName] or {}
|
||||
MenuType[TaskGroupName][TaskType] = MenuType[TaskGroupName][TaskType] or MENU_GROUP:New( TaskGroup, TaskType, MenuCategory[TaskGroupName][TaskCategory] )
|
||||
|
||||
if Menu[TaskGroupName] then
|
||||
Menu[TaskGroupName]:Remove()
|
||||
end
|
||||
Menu[TaskGroupName] = MENU_GROUP_COMMAND:New( TaskGroup, MenuText, MenuType[TaskGroupName][TaskType], self.MenuAssignToGroup, { self = self, TaskGroup = TaskGroup } )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the assigned menu options of the @{Task}.
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Group#GROUP TaskGroup
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:SetAssignedMenuForGroup( TaskGroup )
|
||||
self:E( TaskGroup:GetName() )
|
||||
|
||||
local TaskMission = self.Mission:GetName()
|
||||
|
||||
local Mission = self.Mission
|
||||
|
||||
Mission.MenuMission = Mission.MenuMission or {}
|
||||
local MenuMission = Mission.MenuMission
|
||||
|
||||
self.MenuStatus = self.MenuStatus or {}
|
||||
local MenuStatus = self.MenuStatus
|
||||
|
||||
|
||||
self.MenuAbort = self.MenuAbort or {}
|
||||
local MenuAbort = self.MenuAbort
|
||||
|
||||
local TaskGroupName = TaskGroup:GetName()
|
||||
MenuMission[TaskGroupName] = MenuMission[TaskGroupName] or MENU_GROUP:New( TaskGroup, TaskMission, nil )
|
||||
MenuStatus[TaskGroupName] = MENU_GROUP_COMMAND:New( TaskGroup, "Task Status", MenuMission[TaskGroupName], self.MenuTaskStatus, { self = self, TaskGroup = TaskGroup } )
|
||||
MenuAbort[TaskGroupName] = MENU_GROUP_COMMAND:New( TaskGroup, "Abort Task", MenuMission[TaskGroupName], self.MenuTaskAbort, { self = self, TaskGroup = TaskGroup } )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Remove the menu option of the @{Task} for a @{Group}.
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Group#GROUP TaskGroup
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:RemoveMenuForGroup( TaskGroup )
|
||||
|
||||
local TaskGroupName = TaskGroup:GetName()
|
||||
|
||||
local Mission = self.Mission
|
||||
local MenuMission = Mission.MenuMission
|
||||
local MenuCategory = Mission.MenuCategory
|
||||
local MenuType = Mission.MenuType
|
||||
local MenuStatus = self.MenuStatus
|
||||
local MenuAbort = self.MenuAbort
|
||||
local Menu = self.Menu
|
||||
|
||||
Menu = Menu or {}
|
||||
if Menu[TaskGroupName] then
|
||||
Menu[TaskGroupName]:Remove()
|
||||
Menu[TaskGroupName] = nil
|
||||
end
|
||||
|
||||
MenuType = MenuType or {}
|
||||
if MenuType[TaskGroupName] then
|
||||
for _, Menu in pairs( MenuType[TaskGroupName] ) do
|
||||
Menu:Remove()
|
||||
end
|
||||
MenuType[TaskGroupName] = nil
|
||||
end
|
||||
|
||||
MenuCategory = MenuCategory or {}
|
||||
if MenuCategory[TaskGroupName] then
|
||||
for _, Menu in pairs( MenuCategory[TaskGroupName] ) do
|
||||
Menu:Remove()
|
||||
end
|
||||
MenuCategory[TaskGroupName] = nil
|
||||
end
|
||||
|
||||
MenuStatus = MenuStatus or {}
|
||||
if MenuStatus[TaskGroupName] then
|
||||
MenuStatus[TaskGroupName]:Remove()
|
||||
MenuStatus[TaskGroupName] = nil
|
||||
end
|
||||
|
||||
MenuAbort = MenuAbort or {}
|
||||
if MenuAbort[TaskGroupName] then
|
||||
MenuAbort[TaskGroupName]:Remove()
|
||||
MenuAbort[TaskGroupName] = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function TASK_BASE.MenuAssignToGroup( MenuParam )
|
||||
|
||||
local self = MenuParam.self
|
||||
local TaskGroup = MenuParam.TaskGroup
|
||||
|
||||
self:AssignToGroup( TaskGroup )
|
||||
end
|
||||
|
||||
function TASK_BASE.MenuTaskStatus( MenuParam )
|
||||
|
||||
local self = MenuParam.self
|
||||
local TaskGroup = MenuParam.TaskGroup
|
||||
|
||||
--self:AssignToGroup( TaskGroup )
|
||||
end
|
||||
|
||||
function TASK_BASE.MenuTaskAbort( MenuParam )
|
||||
|
||||
local self = MenuParam.self
|
||||
local TaskGroup = MenuParam.TaskGroup
|
||||
|
||||
--self:AssignToGroup( TaskGroup )
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Returns the @{Task} name.
|
||||
-- @param #TASK_BASE self
|
||||
-- @return #string TaskName
|
||||
function TASK_BASE:GetTaskName()
|
||||
return self.TaskName
|
||||
end
|
||||
|
||||
|
||||
--- Add Process to @{Task} with key @{Unit}.
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:AddProcess( TaskUnit, Process )
|
||||
local TaskUnitName = TaskUnit:GetName()
|
||||
self.Processes = self.Processes or {}
|
||||
self.Processes[TaskUnitName] = self.Processes[TaskUnitName] or {}
|
||||
self.Processes[TaskUnitName][#self.Processes[TaskUnitName]+1] = Process
|
||||
return Process
|
||||
end
|
||||
|
||||
|
||||
--- Remove Processes from @{Task} with key @{Unit}
|
||||
-- @param #TASK_BASE self
|
||||
-- @param #string TaskUnitName
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:RemoveProcesses( TaskUnitName )
|
||||
|
||||
for ProcessID, ProcessData in pairs( self.Processes[TaskUnitName] ) do
|
||||
local Process = ProcessData -- Process#PROCESS
|
||||
Process:StopEvents()
|
||||
Process = nil
|
||||
self.Processes[TaskUnitName][ProcessID] = nil
|
||||
self:E( self.Processes[TaskUnitName][ProcessID] )
|
||||
end
|
||||
self.Processes[TaskUnitName] = nil
|
||||
end
|
||||
|
||||
--- Fail processes from @{Task} with key @{Unit}
|
||||
-- @param #TASK_BASE self
|
||||
-- @param #string TaskUnitName
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:FailProcesses( TaskUnitName )
|
||||
|
||||
for ProcessID, ProcessData in pairs( self.Processes[TaskUnitName] ) do
|
||||
local Process = ProcessData -- Process#PROCESS
|
||||
self:E( { "Failing process: ", Process } )
|
||||
Process.Fsm:Fail()
|
||||
end
|
||||
end
|
||||
|
||||
--- Add a FiniteStateMachine to @{Task} with key @{Unit}
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:AddStateMachine( TaskUnit, Fsm )
|
||||
local TaskUnitName = TaskUnit:GetName()
|
||||
self.Fsm[TaskUnitName] = self.Fsm[TaskUnitName] or {}
|
||||
self.Fsm[TaskUnitName][#self.Fsm[TaskUnitName]+1] = Fsm
|
||||
return Fsm
|
||||
end
|
||||
|
||||
--- Remove FiniteStateMachines from @{Task} with key @{Unit}
|
||||
-- @param #TASK_BASE self
|
||||
-- @param #string TaskUnitName
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:RemoveStateMachines( TaskUnitName )
|
||||
|
||||
for _, Fsm in pairs( self.Fsm[TaskUnitName] ) do
|
||||
Fsm = nil
|
||||
self.Fsm[TaskUnitName][_] = nil
|
||||
self:E( self.Fsm[TaskUnitName][_] )
|
||||
end
|
||||
self.Fsm[TaskUnitName] = nil
|
||||
end
|
||||
|
||||
--- Checks if there is a FiniteStateMachine assigned to @{Unit} for @{Task}
|
||||
-- @param #TASK_BASE self
|
||||
-- @param #string TaskUnitName
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:HasStateMachine( TaskUnitName )
|
||||
|
||||
self:F( { TaskUnitName, self.Fsm[TaskUnitName] ~= nil } )
|
||||
return ( self.Fsm[TaskUnitName] ~= nil )
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- Register a potential new assignment for a new spawned @{Unit}.
|
||||
-- Tasks only get assigned if there are players in it.
|
||||
-- @param #TASK_BASE self
|
||||
@@ -158,8 +495,11 @@ function TASK_BASE:_EventAssignUnit( Event )
|
||||
local TaskPlayerName = TaskUnit:GetPlayerName()
|
||||
if TaskPlayerName ~= nil then
|
||||
if not self:HasStateMachine( TaskUnit ) then
|
||||
self.TaskUnit = TaskUnit
|
||||
self:AssignToUnit( TaskUnit )
|
||||
-- Check if the task was assigned to the group, if it was assigned to the group, assign to the unit just spawned and initiate the processes.
|
||||
local TaskGroup = TaskUnit:GetGroup()
|
||||
if self:IsAssignedToGroup( TaskGroup ) then
|
||||
self:AssignToUnit( TaskUnit )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -167,17 +507,58 @@ function TASK_BASE:_EventAssignUnit( Event )
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Catches the "player leave unit" event for a @{Unit} ....
|
||||
-- When a player is an air unit, and leaves the unit:
|
||||
--
|
||||
-- * and he is not at an airbase runway on the ground, he will fail its task.
|
||||
-- * and he is on an airbase and on the ground, the process for him will just continue to work, he can switch airplanes, and take-off again.
|
||||
-- This is important to model the change from plane types for a player during mission assignment.
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Event#EVENTDATA Event
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:_EventPlayerLeaveUnit( Event )
|
||||
self:F( Event )
|
||||
if Event.IniUnit then
|
||||
local TaskUnit = Event.IniUnit
|
||||
local TaskUnitName = Event.IniUnitName
|
||||
|
||||
-- Check if for this unit in the task there is a process ongoing.
|
||||
if self:HasStateMachine( TaskUnitName ) then
|
||||
if TaskUnit:IsAir() then
|
||||
if TaskUnit:IsAboveRunway() then
|
||||
-- do nothing
|
||||
else
|
||||
self:E( "IsNotAboveRunway" )
|
||||
-- Player left airplane during an assigned task and was not at an airbase.
|
||||
self:FailProcesses( TaskUnitName )
|
||||
self:UnAssignFromUnit( TaskUnitName )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
--- UnAssigns a @{Unit} that is left by a player, crashed, dead, ....
|
||||
-- There are only assignments if there are players in it.
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Event#EVENTDATA Event
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:_EventUnAssignUnit( Event )
|
||||
function TASK_BASE:_EventDead( Event )
|
||||
self:F( Event )
|
||||
if Event.IniUnit then
|
||||
local TaskUnit = Event.IniUnit
|
||||
self:F( TaskUnit:GetName() )
|
||||
self:UnAssignFromUnit( TaskUnit, true )
|
||||
local TaskUnitName = Event.IniUnitName
|
||||
|
||||
-- Check if for this unit in the task there is a process ongoing.
|
||||
if self:HasStateMachine( TaskUnitName ) then
|
||||
self:FailProcesses( TaskUnitName )
|
||||
self:UnAssignFromUnit( TaskUnitName )
|
||||
end
|
||||
|
||||
local TaskGroup = Event.IniUnit:GetGroup()
|
||||
TaskGroup:SetState( TaskGroup, "Assigned", nil )
|
||||
end
|
||||
return nil
|
||||
end
|
||||
@@ -189,6 +570,19 @@ function TASK_BASE:GetScoring()
|
||||
return self.Mission:GetScoring()
|
||||
end
|
||||
|
||||
|
||||
--- Gets the Task Index, which is a combination of the Task category, the Task type, the Task name.
|
||||
-- @param #TASK_BASE self
|
||||
-- @return #string The Task ID
|
||||
function TASK_BASE:GetTaskIndex()
|
||||
|
||||
local TaskCategory = self:GetCategory()
|
||||
local TaskType = self:GetType()
|
||||
local TaskName = self:GetName()
|
||||
|
||||
return TaskCategory .. "." ..TaskType .. "." .. TaskName
|
||||
end
|
||||
|
||||
--- Sets the Name of the Task
|
||||
-- @param #TASK_BASE self
|
||||
-- @param #string TaskName
|
||||
@@ -250,6 +644,7 @@ end
|
||||
-- @param #TASK_BASE self
|
||||
function TASK_BASE:StateSuccess()
|
||||
self:SetState( self, "State", "Success" )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Is the @{Task} status **Success**.
|
||||
@@ -262,6 +657,7 @@ end
|
||||
-- @param #TASK_BASE self
|
||||
function TASK_BASE:StateFailed()
|
||||
self:SetState( self, "State", "Failed" )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Is the @{Task} status **Failed**.
|
||||
@@ -274,6 +670,7 @@ end
|
||||
-- @param #TASK_BASE self
|
||||
function TASK_BASE:StatePlanned()
|
||||
self:SetState( self, "State", "Planned" )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Is the @{Task} status **Planned**.
|
||||
@@ -286,6 +683,7 @@ end
|
||||
-- @param #TASK_BASE self
|
||||
function TASK_BASE:StateAssigned()
|
||||
self:SetState( self, "State", "Assigned" )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Is the @{Task} status **Assigned**.
|
||||
@@ -298,6 +696,7 @@ end
|
||||
-- @param #TASK_BASE self
|
||||
function TASK_BASE:StateHold()
|
||||
self:SetState( self, "State", "Hold" )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Is the @{Task} status **Hold**.
|
||||
@@ -310,6 +709,7 @@ end
|
||||
-- @param #TASK_BASE self
|
||||
function TASK_BASE:StateReplanned()
|
||||
self:SetState( self, "State", "Replanned" )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Is the @{Task} status **Replanned**.
|
||||
@@ -327,12 +727,14 @@ end
|
||||
--- Sets a @{Task} briefing.
|
||||
-- @param #TASK_BASE self
|
||||
-- @param #string TaskBriefing
|
||||
-- @return self
|
||||
-- @return #TASK_BASE self
|
||||
function TASK_BASE:SetBriefing( TaskBriefing )
|
||||
self.TaskBriefing = TaskBriefing
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Adds a score for the TASK to be achieved.
|
||||
-- @param #TASK_BASE self
|
||||
-- @param #string TaskStatus is the status of the TASK when the score needs to be given.
|
||||
@@ -348,23 +750,94 @@ function TASK_BASE:AddScore( TaskStatus, ScoreText, Score )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- StateMachine callback function for a TASK
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Event#EVENTDATA Event
|
||||
function TASK_BASE:OnStateChange( Fsm, Event, From, To )
|
||||
function TASK_BASE:OnAssigned( TaskUnit, Fsm, Event, From, To )
|
||||
|
||||
MESSAGE:New( "Task " .. self.TaskName .. " : " .. Event .. " changed to state " .. To, 15 ):ToAll()
|
||||
self:E("Assigned")
|
||||
|
||||
local TaskGroup = TaskUnit:GetGroup()
|
||||
|
||||
TaskGroup:Message( self.TaskBriefing, 20 )
|
||||
|
||||
self:RemoveMenuForGroup( TaskGroup )
|
||||
self:SetAssignedMenuForGroup( TaskGroup )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- StateMachine callback function for a TASK
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Event#EVENTDATA Event
|
||||
function TASK_BASE:OnSuccess( TaskUnit, Fsm, Event, From, To )
|
||||
|
||||
self:E("Success")
|
||||
|
||||
self:UnAssignFromGroups()
|
||||
|
||||
local TaskGroup = TaskUnit:GetGroup()
|
||||
self.Mission:SetPlannedMenu()
|
||||
|
||||
self:StateSuccess()
|
||||
|
||||
-- The task has become successful, the event catchers can be cleaned.
|
||||
self:CleanUp()
|
||||
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Event#EVENTDATA Event
|
||||
function TASK_BASE:OnFailed( TaskUnit, Fsm, Event, From, To )
|
||||
|
||||
self:E( { "Failed for unit ", TaskUnit:GetName(), TaskUnit:GetPlayerName() } )
|
||||
|
||||
-- A task cannot be "failed", so a task will always be there waiting for players to join.
|
||||
-- When the player leaves its unit, we will need to check whether he was on the ground or not at an airbase.
|
||||
-- When the player crashes, we will need to check whether in the group there are other players still active. It not, we reset the task from Assigned to Planned, otherwise, we just leave as Assigned.
|
||||
|
||||
self:UnAssignFromGroups()
|
||||
self:StatePlanned()
|
||||
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK
|
||||
-- @param #TASK_BASE self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Event#EVENTDATA Event
|
||||
function TASK_BASE:OnStateChange( TaskUnit, Fsm, Event, From, To )
|
||||
|
||||
if self:IsTrace() then
|
||||
MESSAGE:New( "Task " .. self.TaskName .. " : " .. Event .. " changed to state " .. To, 15 ):ToAll()
|
||||
end
|
||||
|
||||
self:E( { Event, From, To } )
|
||||
self:SetState( self, "State", To )
|
||||
|
||||
if self.Scores[To] then
|
||||
local Scoring = self:GetScoring()
|
||||
if Scoring then
|
||||
Scoring:_AddMissionTaskScore( self.Mission, self.TaskUnit, self.Scores[To].ScoreText, self.Scores[To].Score )
|
||||
Scoring:_AddMissionScore( self.Mission, self.Scores[To].ScoreText, self.Scores[To].Score )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
145
Moose Development/Moose/Task_BAI.lua
Normal file
145
Moose Development/Moose/Task_BAI.lua
Normal file
@@ -0,0 +1,145 @@
|
||||
--- This module contains the TASK_BAI classes.
|
||||
--
|
||||
-- 1) @{#TASK_BAI} class, extends @{Task#TASK_BASE}
|
||||
-- =================================================
|
||||
-- The @{#TASK_BAI} class defines a new BAI task of a @{Set} of Target Units, located at a Target Zone, based on the tasking capabilities defined in @{Task#TASK_BASE}.
|
||||
-- The TASK_BAI is processed through a @{Statemachine#STATEMACHINE_TASK}, and has the following statuses:
|
||||
--
|
||||
-- * **None**: Start of the process
|
||||
-- * **Planned**: The SEAD task is planned. Upon Planned, the sub-process @{Process_Assign#PROCESS_ASSIGN_ACCEPT} is started to accept the task.
|
||||
-- * **Assigned**: The SEAD task is assigned to a @{Group#GROUP}. Upon Assigned, the sub-process @{Process_Route#PROCESS_ROUTE} is started to route the active Units in the Group to the attack zone.
|
||||
-- * **Success**: The SEAD task is successfully completed. Upon Success, the sub-process @{Process_SEAD#PROCESS_SEAD} is started to follow-up successful SEADing of the targets assigned in the task.
|
||||
-- * **Failed**: The SEAD task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Authors: FlightControl - Design and Programming
|
||||
--
|
||||
-- @module Task_BAI
|
||||
|
||||
|
||||
do -- TASK_BAI
|
||||
|
||||
--- The TASK_BAI class
|
||||
-- @type TASK_BAI
|
||||
-- @extends Task#TASK_BASE
|
||||
TASK_BAI = {
|
||||
ClassName = "TASK_BAI",
|
||||
}
|
||||
|
||||
--- Instantiates a new TASK_BAI.
|
||||
-- @param #TASK_BAI self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned.
|
||||
-- @param #string TaskName The name of the Task.
|
||||
-- @param Set#SET_UNIT UnitSetTargets
|
||||
-- @param Zone#ZONE_BASE TargetZone
|
||||
-- @return #TASK_BAI self
|
||||
function TASK_BAI:New( Mission, SetGroup, TaskName, TargetSetUnit, TargetZone )
|
||||
local self = BASE:Inherit( self, TASK_BASE:New( Mission, SetGroup, TaskName, "BAI", "A2G" ) )
|
||||
self:F()
|
||||
|
||||
self.TargetSetUnit = TargetSetUnit
|
||||
self.TargetZone = TargetZone
|
||||
|
||||
_EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventPlayerLeaveUnit, self )
|
||||
_EVENTDISPATCHER:OnDead( self._EventDead, self )
|
||||
_EVENTDISPATCHER:OnCrash( self._EventDead, self )
|
||||
_EVENTDISPATCHER:OnPilotDead( self._EventDead, self )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Removes a TASK_BAI.
|
||||
-- @param #TASK_BAI self
|
||||
-- @return #nil
|
||||
function TASK_BAI:CleanUp()
|
||||
|
||||
self:GetParent( self ):CleanUp()
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Assign the @{Task} to a @{Unit}.
|
||||
-- @param #TASK_BAI self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @return #TASK_BAI self
|
||||
function TASK_BAI:AssignToUnit( TaskUnit )
|
||||
self:F( TaskUnit:GetName() )
|
||||
|
||||
local ProcessAssign = self:AddProcess( TaskUnit, PROCESS_ASSIGN_ACCEPT:New( self, TaskUnit, self.TaskBriefing ) )
|
||||
local ProcessRoute = self:AddProcess( TaskUnit, PROCESS_ROUTE:New( self, TaskUnit, self.TargetZone ) )
|
||||
local ProcessSEAD = self:AddProcess( TaskUnit, PROCESS_DESTROY:New( self, "BAI", TaskUnit, self.TargetSetUnit ) )
|
||||
local ProcessSmoke = self:AddProcess( TaskUnit, PROCESS_SMOKE_TARGETS:New( self, TaskUnit, self.TargetSetUnit, self.TargetZone ) )
|
||||
|
||||
local Process = self:AddStateMachine( TaskUnit, STATEMACHINE_TASK:New( self, TaskUnit, {
|
||||
initial = 'None',
|
||||
events = {
|
||||
{ name = 'Next', from = 'None', to = 'Planned' },
|
||||
{ name = 'Next', from = 'Planned', to = 'Assigned' },
|
||||
{ name = 'Reject', from = 'Planned', to = 'Rejected' },
|
||||
{ name = 'Next', from = 'Assigned', to = 'Success' },
|
||||
{ name = 'Fail', from = 'Assigned', to = 'Failed' },
|
||||
{ name = 'Fail', from = 'Arrived', to = 'Failed' }
|
||||
},
|
||||
callbacks = {
|
||||
onNext = self.OnNext,
|
||||
onRemove = self.OnRemove,
|
||||
},
|
||||
subs = {
|
||||
Assign = { onstateparent = 'Planned', oneventparent = 'Next', fsm = ProcessAssign.Fsm, event = 'Start', returnevents = { 'Next', 'Reject' } },
|
||||
Route = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessRoute.Fsm, event = 'Start' },
|
||||
Sead = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessSEAD.Fsm, event = 'Start', returnevents = { 'Next' } },
|
||||
Smoke = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessSmoke.Fsm, event = 'Start', }
|
||||
}
|
||||
} ) )
|
||||
|
||||
ProcessRoute:AddScore( "Failed", "failed to destroy a ground unit", -100 )
|
||||
ProcessSEAD:AddScore( "Destroy", "destroyed a ground unit", 25 )
|
||||
ProcessSEAD:AddScore( "Failed", "failed to destroy a ground unit", -100 )
|
||||
|
||||
Process:Next()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK
|
||||
-- @param #TASK_BAI self
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Event#EVENTDATA Event
|
||||
function TASK_BAI:OnNext( Fsm, Event, From, To, Event )
|
||||
|
||||
self:SetState( self, "State", To )
|
||||
|
||||
end
|
||||
|
||||
--- @param #TASK_BAI self
|
||||
function TASK_BAI:GetPlannedMenuText()
|
||||
return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )"
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_BAI self
|
||||
function TASK_BAI:_Schedule()
|
||||
self:F2()
|
||||
|
||||
self.TaskScheduler = SCHEDULER:New( self, _Scheduler, {}, 15, 15 )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_BAI self
|
||||
function TASK_BAI._Scheduler()
|
||||
self:F2()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -1,105 +1,145 @@
|
||||
--- @module Task_CAS
|
||||
--- This module contains the TASK_CAS classes.
|
||||
--
|
||||
-- 1) @{#TASK_CAS} class, extends @{Task#TASK_BASE}
|
||||
-- =================================================
|
||||
-- The @{#TASK_CAS} class defines a new CAS task of a @{Set} of Target Units, located at a Target Zone, based on the tasking capabilities defined in @{Task#TASK_BASE}.
|
||||
-- The TASK_CAS is processed through a @{Statemachine#STATEMACHINE_TASK}, and has the following statuses:
|
||||
--
|
||||
-- * **None**: Start of the process
|
||||
-- * **Planned**: The SEAD task is planned. Upon Planned, the sub-process @{Process_Assign#PROCESS_ASSIGN_ACCEPT} is started to accept the task.
|
||||
-- * **Assigned**: The SEAD task is assigned to a @{Group#GROUP}. Upon Assigned, the sub-process @{Process_Route#PROCESS_ROUTE} is started to route the active Units in the Group to the attack zone.
|
||||
-- * **Success**: The SEAD task is successfully completed. Upon Success, the sub-process @{Process_SEAD#PROCESS_SEAD} is started to follow-up successful SEADing of the targets assigned in the task.
|
||||
-- * **Failed**: The SEAD task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Authors: FlightControl - Design and Programming
|
||||
--
|
||||
-- @module Task_CAS
|
||||
|
||||
--- The TASK_CAS class
|
||||
-- @type TASK_CAS
|
||||
-- @extends Task#TASK_BASE
|
||||
TASK_CAS = {
|
||||
ClassName = "TASK_CAS",
|
||||
}
|
||||
|
||||
--- Instantiates a new TASK_CAS.
|
||||
-- @param #TASK_CAS self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Set#SET_UNIT UnitSetTargets
|
||||
-- @param Zone#ZONE_BASE TargetZone
|
||||
-- @return #TASK_CAS self
|
||||
function TASK_CAS:New( Mission, MenuText, TargetSetUnit, TargetZone )
|
||||
local self = BASE:Inherit( self, TASK_BASE:New( Mission, MenuText, "CAS", "A2G" ) )
|
||||
self:F()
|
||||
do -- TASK_CAS
|
||||
|
||||
self.TargetSetUnit = TargetSetUnit
|
||||
self.TargetZone = TargetZone
|
||||
|
||||
_EVENTDISPATCHER:OnBirth( self._EventAssignUnit, self )
|
||||
_EVENTDISPATCHER:OnPlayerEnterUnit(self._EventAssignUnit, self )
|
||||
_EVENTDISPATCHER:OnPlayerLeaveUnit(self._EventUnAssignUnit, self )
|
||||
_EVENTDISPATCHER:OnCrash(self._EventUnAssignUnit, self )
|
||||
_EVENTDISPATCHER:OnDead(self._EventUnAssignUnit, self )
|
||||
_EVENTDISPATCHER:OnPilotDead(self._EventUnAssignUnit, self )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Assign the @{Task} to a @{Unit}.
|
||||
-- @param #TASK_CAS self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @return #TASK_CAS self
|
||||
function TASK_CAS:AssignToUnit( TaskUnit )
|
||||
self:F( TaskUnit:GetName() )
|
||||
|
||||
local ProcessAssign = self:AddProcess( TaskUnit, PROCESS_ASSIGN:New( self, TaskUnit, self.TaskBriefing ) )
|
||||
local ProcessRoute = self:AddProcess( TaskUnit, PROCESS_ROUTE:New( self, TaskUnit, self.TargetZone ) )
|
||||
local ProcessSEAD = self:AddProcess( TaskUnit, PROCESS_SEAD:New( self, TaskUnit, self.TargetSetUnit ) )
|
||||
--- The TASK_CAS class
|
||||
-- @type TASK_CAS
|
||||
-- @extends Task#TASK_BASE
|
||||
TASK_CAS = {
|
||||
ClassName = "TASK_CAS",
|
||||
}
|
||||
|
||||
local Process = self:AddStateMachine( TaskUnit, STATEMACHINE_TASK:New( self, {
|
||||
initial = 'None',
|
||||
events = {
|
||||
{ name = 'Next', from = 'None', to = 'Planned' },
|
||||
{ name = 'Next', from = 'Planned', to = 'Assigned' },
|
||||
{ name = 'Reject', from = 'Planned', to = 'Rejected' },
|
||||
{ name = 'Next', from = 'Assigned', to = 'Success' },
|
||||
{ name = 'Fail', from = 'Assigned', to = 'Failed' },
|
||||
{ name = 'Fail', from = 'Arrived', to = 'Failed' }
|
||||
},
|
||||
callbacks = {
|
||||
onNext = self.OnNext,
|
||||
onRemove = self.OnRemove,
|
||||
},
|
||||
subs = {
|
||||
Assign = { onstateparent = 'Planned', oneventparent = 'Next', fsm = ProcessAssign.Fsm, event = 'Menu', returnevents = { 'Next', 'Reject' } },
|
||||
Route = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessRoute.Fsm, event = 'Route' },
|
||||
Sead = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessSEAD.Fsm, event = 'Await', returnevents = { 'Next' } }
|
||||
}
|
||||
} ) )
|
||||
--- Instantiates a new TASK_CAS.
|
||||
-- @param #TASK_CAS self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned.
|
||||
-- @param #string TaskName The name of the Task.
|
||||
-- @param Set#SET_UNIT UnitSetTargets
|
||||
-- @param Zone#ZONE_BASE TargetZone
|
||||
-- @return #TASK_CAS self
|
||||
function TASK_CAS:New( Mission, SetGroup, TaskName, TargetSetUnit, TargetZone )
|
||||
local self = BASE:Inherit( self, TASK_BASE:New( Mission, SetGroup, TaskName, "CAS", "A2G" ) )
|
||||
self:F()
|
||||
|
||||
ProcessRoute:AddScore( "Failed", "failed to destroy a ground unit", -100 )
|
||||
ProcessSEAD:AddScore( "Destroy", "destroyed a ground unit", 25 )
|
||||
ProcessSEAD:AddScore( "Failed", "failed to destroy a ground unit", -100 )
|
||||
self.TargetSetUnit = TargetSetUnit
|
||||
self.TargetZone = TargetZone
|
||||
|
||||
_EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventPlayerLeaveUnit, self )
|
||||
_EVENTDISPATCHER:OnDead( self._EventDead, self )
|
||||
_EVENTDISPATCHER:OnCrash( self._EventDead, self )
|
||||
_EVENTDISPATCHER:OnPilotDead( self._EventDead, self )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
Process:Next()
|
||||
--- Removes a TASK_CAS.
|
||||
-- @param #TASK_CAS self
|
||||
-- @return #nil
|
||||
function TASK_CAS:CleanUp()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK
|
||||
-- @param #TASK_CAS self
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Event#EVENTDATA Event
|
||||
function TASK_CAS:OnNext( Fsm, Event, From, To, Event )
|
||||
|
||||
self:SetState( self, "State", To )
|
||||
|
||||
end
|
||||
|
||||
--- @param #TASK_CAS self
|
||||
function TASK_CAS:_Schedule()
|
||||
self:F2()
|
||||
|
||||
self.TaskScheduler = SCHEDULER:New( self, _Scheduler, {}, 15, 15 )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_CAS self
|
||||
function TASK_CAS._Scheduler()
|
||||
self:F2()
|
||||
|
||||
return true
|
||||
self:GetParent( self ):CleanUp()
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Assign the @{Task} to a @{Unit}.
|
||||
-- @param #TASK_CAS self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @return #TASK_CAS self
|
||||
function TASK_CAS:AssignToUnit( TaskUnit )
|
||||
self:F( TaskUnit:GetName() )
|
||||
|
||||
local ProcessAssign = self:AddProcess( TaskUnit, PROCESS_ASSIGN_ACCEPT:New( self, TaskUnit, self.TaskBriefing ) )
|
||||
local ProcessRoute = self:AddProcess( TaskUnit, PROCESS_ROUTE:New( self, TaskUnit, self.TargetZone ) )
|
||||
local ProcessSEAD = self:AddProcess( TaskUnit, PROCESS_DESTROY:New( self, "CAS", TaskUnit, self.TargetSetUnit ) )
|
||||
local ProcessSmoke = self:AddProcess( TaskUnit, PROCESS_SMOKE_TARGETS:New( self, TaskUnit, self.TargetSetUnit, self.TargetZone ) )
|
||||
|
||||
local Process = self:AddStateMachine( TaskUnit, STATEMACHINE_TASK:New( self, TaskUnit, {
|
||||
initial = 'None',
|
||||
events = {
|
||||
{ name = 'Next', from = 'None', to = 'Planned' },
|
||||
{ name = 'Next', from = 'Planned', to = 'Assigned' },
|
||||
{ name = 'Reject', from = 'Planned', to = 'Rejected' },
|
||||
{ name = 'Next', from = 'Assigned', to = 'Success' },
|
||||
{ name = 'Fail', from = 'Assigned', to = 'Failed' },
|
||||
{ name = 'Fail', from = 'Arrived', to = 'Failed' }
|
||||
},
|
||||
callbacks = {
|
||||
onNext = self.OnNext,
|
||||
onRemove = self.OnRemove,
|
||||
},
|
||||
subs = {
|
||||
Assign = { onstateparent = 'Planned', oneventparent = 'Next', fsm = ProcessAssign.Fsm, event = 'Start', returnevents = { 'Next', 'Reject' } },
|
||||
Route = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessRoute.Fsm, event = 'Start' },
|
||||
Sead = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessSEAD.Fsm, event = 'Start', returnevents = { 'Next' } },
|
||||
Smoke = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessSmoke.Fsm, event = 'Start', }
|
||||
}
|
||||
} ) )
|
||||
|
||||
ProcessRoute:AddScore( "Failed", "failed to destroy a ground unit", -100 )
|
||||
ProcessSEAD:AddScore( "Destroy", "destroyed a ground unit", 25 )
|
||||
ProcessSEAD:AddScore( "Failed", "failed to destroy a ground unit", -100 )
|
||||
|
||||
Process:Next()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK
|
||||
-- @param #TASK_CAS self
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Event#EVENTDATA Event
|
||||
function TASK_CAS:OnNext( Fsm, Event, From, To, Event )
|
||||
|
||||
self:SetState( self, "State", To )
|
||||
|
||||
end
|
||||
|
||||
--- @param #TASK_CAS self
|
||||
function TASK_CAS:GetPlannedMenuText()
|
||||
return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )"
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_CAS self
|
||||
function TASK_CAS:_Schedule()
|
||||
self:F2()
|
||||
|
||||
self.TaskScheduler = SCHEDULER:New( self, _Scheduler, {}, 15, 15 )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_CAS self
|
||||
function TASK_CAS._Scheduler()
|
||||
self:F2()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,109 +1,145 @@
|
||||
--- @module Task_SEAD
|
||||
--- This module contains the TASK_SEAD classes.
|
||||
--
|
||||
-- 1) @{#TASK_SEAD} class, extends @{Task#TASK_BASE}
|
||||
-- =================================================
|
||||
-- The @{#TASK_SEAD} class defines a new SEAD task of a @{Set} of Target Units, located at a Target Zone, based on the tasking capabilities defined in @{Task#TASK_BASE}.
|
||||
-- The TASK_SEAD is processed through a @{Statemachine#STATEMACHINE_TASK}, and has the following statuses:
|
||||
--
|
||||
-- * **None**: Start of the process
|
||||
-- * **Planned**: The SEAD task is planned. Upon Planned, the sub-process @{Process_Assign#PROCESS_ASSIGN_ACCEPT} is started to accept the task.
|
||||
-- * **Assigned**: The SEAD task is assigned to a @{Group#GROUP}. Upon Assigned, the sub-process @{Process_Route#PROCESS_ROUTE} is started to route the active Units in the Group to the attack zone.
|
||||
-- * **Success**: The SEAD task is successfully completed. Upon Success, the sub-process @{Process_SEAD#PROCESS_SEAD} is started to follow-up successful SEADing of the targets assigned in the task.
|
||||
-- * **Failed**: The SEAD task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Authors: FlightControl - Design and Programming
|
||||
--
|
||||
-- @module Task_SEAD
|
||||
|
||||
--- The TASK_SEAD class
|
||||
-- @type TASK_SEAD
|
||||
-- @extends Task#TASK_BASE
|
||||
TASK_SEAD = {
|
||||
ClassName = "TASK_SEAD",
|
||||
}
|
||||
|
||||
--- Instantiates a new TASK_SEAD.
|
||||
-- @param #TASK_SEAD self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Set#SET_UNIT UnitSetTargets
|
||||
-- @param Zone#ZONE_BASE TargetZone
|
||||
-- @return #TASK_SEAD self
|
||||
function TASK_SEAD:New( Mission, MenuText, TargetSetUnit, TargetZone )
|
||||
local self = BASE:Inherit( self, TASK_BASE:New( Mission, MenuText, "SEAD", "A2G" ) )
|
||||
self:F()
|
||||
do -- TASK_SEAD
|
||||
|
||||
self.TargetSetUnit = TargetSetUnit
|
||||
self.TargetZone = TargetZone
|
||||
|
||||
_EVENTDISPATCHER:OnBirth( self._EventAssignUnit, self )
|
||||
_EVENTDISPATCHER:OnPlayerEnterUnit(self._EventAssignUnit, self )
|
||||
_EVENTDISPATCHER:OnPlayerLeaveUnit(self._EventUnAssignUnit, self )
|
||||
_EVENTDISPATCHER:OnCrash(self._EventUnAssignUnit, self )
|
||||
_EVENTDISPATCHER:OnDead(self._EventUnAssignUnit, self )
|
||||
_EVENTDISPATCHER:OnPilotDead(self._EventUnAssignUnit, self )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Assign the @{Task} to a @{Unit}.
|
||||
-- @param #TASK_SEAD self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @return #TASK_SEAD self
|
||||
function TASK_SEAD:AssignToUnit( TaskUnit )
|
||||
self:F( TaskUnit:GetName() )
|
||||
--- The TASK_SEAD class
|
||||
-- @type TASK_SEAD
|
||||
-- @field Set#SET_UNIT TargetSetUnit
|
||||
-- @extends Task#TASK_BASE
|
||||
TASK_SEAD = {
|
||||
ClassName = "TASK_SEAD",
|
||||
}
|
||||
|
||||
local ProcessAssign = self:AddProcess( TaskUnit, PROCESS_ASSIGN:New( self, TaskUnit, self.TaskBriefing ) )
|
||||
local ProcessRoute = self:AddProcess( TaskUnit, PROCESS_ROUTE:New( self, TaskUnit, self.TargetZone ) )
|
||||
local ProcessSEAD = self:AddProcess( TaskUnit, PROCESS_SEAD:New( self, TaskUnit, self.TargetSetUnit ) )
|
||||
--- Instantiates a new TASK_SEAD.
|
||||
-- @param #TASK_SEAD self
|
||||
-- @param Mission#MISSION Mission
|
||||
-- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned.
|
||||
-- @param #string TaskName The name of the Task.
|
||||
-- @param Set#SET_UNIT UnitSetTargets
|
||||
-- @param Zone#ZONE_BASE TargetZone
|
||||
-- @return #TASK_SEAD self
|
||||
function TASK_SEAD:New( Mission, SetGroup, TaskName, TargetSetUnit, TargetZone )
|
||||
local self = BASE:Inherit( self, TASK_BASE:New( Mission, SetGroup, TaskName, "SEAD", "A2G" ) )
|
||||
self:F()
|
||||
|
||||
local Process = self:AddStateMachine( TaskUnit, STATEMACHINE_TASK:New( self, {
|
||||
initial = 'None',
|
||||
events = {
|
||||
{ name = 'Next', from = 'None', to = 'Planned' },
|
||||
{ name = 'Next', from = 'Planned', to = 'Assigned' },
|
||||
{ name = 'Reject', from = 'Planned', to = 'Rejected' },
|
||||
{ name = 'Next', from = 'Assigned', to = 'Success' },
|
||||
{ name = 'Fail', from = 'Assigned', to = 'Failed' },
|
||||
{ name = 'Fail', from = 'Arrived', to = 'Failed' }
|
||||
},
|
||||
callbacks = {
|
||||
onNext = self.OnNext,
|
||||
onRemove = self.OnRemove,
|
||||
},
|
||||
subs = {
|
||||
Assign = { onstateparent = 'Planned', oneventparent = 'Next', fsm = ProcessAssign.Fsm, event = 'Menu', returnevents = { 'Next', 'Reject' } },
|
||||
Route = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessRoute.Fsm, event = 'Route' },
|
||||
Sead = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessSEAD.Fsm, event = 'Await', returnevents = { 'Next' } }
|
||||
}
|
||||
} ) )
|
||||
self.TargetSetUnit = TargetSetUnit
|
||||
self.TargetZone = TargetZone
|
||||
|
||||
_EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventPlayerLeaveUnit, self )
|
||||
_EVENTDISPATCHER:OnDead( self._EventDead, self )
|
||||
_EVENTDISPATCHER:OnCrash( self._EventDead, self )
|
||||
_EVENTDISPATCHER:OnPilotDead( self._EventDead, self )
|
||||
|
||||
ProcessRoute:AddScore( "Failed", "failed to destroy a radar", -100 )
|
||||
ProcessSEAD:AddScore( "Destroy", "destroyed a radar", 25 )
|
||||
ProcessSEAD:AddScore( "Failed", "failed to destroy a radar", -100 )
|
||||
self:AddScore( "Success", "Destroyed all target radars", 250 )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Removes a TASK_SEAD.
|
||||
-- @param #TASK_SEAD self
|
||||
-- @return #nil
|
||||
function TASK_SEAD:CleanUp()
|
||||
|
||||
self:GetParent(self):CleanUp()
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
Process:Next()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK
|
||||
-- @param #TASK_SEAD self
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Event#EVENTDATA Event
|
||||
function TASK_SEAD:OnNext( Fsm, Event, From, To )
|
||||
|
||||
self:SetState( self, "State", To )
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- @param #TASK_SEAD self
|
||||
function TASK_SEAD:_Schedule()
|
||||
self:F2()
|
||||
|
||||
self.TaskScheduler = SCHEDULER:New( self, _Scheduler, {}, 15, 15 )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_SEAD self
|
||||
function TASK_SEAD._Scheduler()
|
||||
self:F2()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- Assign the @{Task} to a @{Unit}.
|
||||
-- @param #TASK_SEAD self
|
||||
-- @param Unit#UNIT TaskUnit
|
||||
-- @return #TASK_SEAD self
|
||||
function TASK_SEAD:AssignToUnit( TaskUnit )
|
||||
self:F( TaskUnit:GetName() )
|
||||
|
||||
local ProcessAssign = self:AddProcess( TaskUnit, PROCESS_ASSIGN_ACCEPT:New( self, TaskUnit, self.TaskBriefing ) )
|
||||
local ProcessRoute = self:AddProcess( TaskUnit, PROCESS_ROUTE:New( self, TaskUnit, self.TargetZone ) )
|
||||
local ProcessSEAD = self:AddProcess( TaskUnit, PROCESS_DESTROY:New( self, "SEAD", TaskUnit, self.TargetSetUnit ) )
|
||||
local ProcessSmoke = self:AddProcess( TaskUnit, PROCESS_SMOKE_TARGETS:New( self, TaskUnit, self.TargetSetUnit, self.TargetZone ) )
|
||||
|
||||
local Process = self:AddStateMachine( TaskUnit, STATEMACHINE_TASK:New( self, TaskUnit, {
|
||||
initial = 'None',
|
||||
events = {
|
||||
{ name = 'Next', from = 'None', to = 'Planned' },
|
||||
{ name = 'Next', from = 'Planned', to = 'Assigned' },
|
||||
{ name = 'Reject', from = 'Planned', to = 'Rejected' },
|
||||
{ name = 'Next', from = 'Assigned', to = 'Success' },
|
||||
{ name = 'Fail', from = 'Assigned', to = 'Failed' },
|
||||
{ name = 'Fail', from = 'Arrived', to = 'Failed' }
|
||||
},
|
||||
callbacks = {
|
||||
onNext = self.OnNext,
|
||||
onRemove = self.OnRemove,
|
||||
},
|
||||
subs = {
|
||||
Assign = { onstateparent = 'Planned', oneventparent = 'Next', fsm = ProcessAssign.Fsm, event = 'Start', returnevents = { 'Next', 'Reject' } },
|
||||
Route = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessRoute.Fsm, event = 'Start' },
|
||||
Sead = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessSEAD.Fsm, event = 'Start', returnevents = { 'Next' } },
|
||||
Smoke = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessSmoke.Fsm, event = 'Start', }
|
||||
}
|
||||
} ) )
|
||||
|
||||
ProcessRoute:AddScore( "Failed", "failed to destroy a radar", -100 )
|
||||
ProcessSEAD:AddScore( "Destroy", "destroyed a radar", 25 )
|
||||
ProcessSEAD:AddScore( "Failed", "failed to destroy a radar", -100 )
|
||||
self:AddScore( "Success", "Destroyed all target radars", 250 )
|
||||
|
||||
Process:Next()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- StateMachine callback function for a TASK
|
||||
-- @param #TASK_SEAD self
|
||||
-- @param StateMachine#STATEMACHINE_TASK Fsm
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Event#EVENTDATA Event
|
||||
function TASK_SEAD:OnNext( Fsm, Event, From, To )
|
||||
|
||||
self:SetState( self, "State", To )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_SEAD self
|
||||
function TASK_SEAD:GetPlannedMenuText()
|
||||
return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )"
|
||||
end
|
||||
|
||||
--- @param #TASK_SEAD self
|
||||
function TASK_SEAD:_Schedule()
|
||||
self:F2()
|
||||
|
||||
self.TaskScheduler = SCHEDULER:New( self, _Scheduler, {}, 15, 15 )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_SEAD self
|
||||
function TASK_SEAD._Scheduler()
|
||||
self:F2()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,459 +0,0 @@
|
||||
--- The TASK Classes define major end-to-end activities within a MISSION. The TASK Class is the Master Class to orchestrate these activities. From this class, many concrete TASK classes are inherited.
|
||||
-- @module TASK
|
||||
|
||||
--- The TASK class
|
||||
-- @type TASK
|
||||
-- @extends Base#BASE
|
||||
TASK = {
|
||||
|
||||
-- Defines the different signal types with a Task.
|
||||
SIGNAL = {
|
||||
COLOR = {
|
||||
RED = { ID = 1, COLOR = trigger.smokeColor.Red, TEXT = "A red" },
|
||||
GREEN = { ID = 2, COLOR = trigger.smokeColor.Green, TEXT = "A green" },
|
||||
BLUE = { ID = 3, COLOR = trigger.smokeColor.Blue, TEXT = "A blue" },
|
||||
WHITE = { ID = 4, COLOR = trigger.smokeColor.White, TEXT = "A white" },
|
||||
ORANGE = { ID = 5, COLOR = trigger.smokeColor.Orange, TEXT = "An orange" }
|
||||
},
|
||||
TYPE = {
|
||||
SMOKE = { ID = 1, TEXT = "smoke" },
|
||||
FLARE = { ID = 2, TEXT = "flare" }
|
||||
}
|
||||
},
|
||||
ClassName = "TASK",
|
||||
Mission = {}, -- Owning mission of the Task
|
||||
Name = '',
|
||||
Stages = {},
|
||||
Stage = {},
|
||||
Cargos = {
|
||||
InitCargos = {},
|
||||
LoadCargos = {}
|
||||
},
|
||||
LandingZones = {
|
||||
LandingZoneNames = {},
|
||||
LandingZones = {}
|
||||
},
|
||||
ActiveStage = 0,
|
||||
TaskDone = false,
|
||||
TaskFailed = false,
|
||||
GoalTasks = {}
|
||||
}
|
||||
|
||||
--- Instantiates a new TASK Base. Should never be used. Interface Class.
|
||||
-- @return TASK
|
||||
function TASK:New()
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
self:F()
|
||||
|
||||
-- assign Task default values during construction
|
||||
self.TaskBriefing = "Task: No Task."
|
||||
self.Time = timer.getTime()
|
||||
self.ExecuteStage = _TransportExecuteStage.NONE
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function TASK:SetStage( StageSequenceIncrement )
|
||||
self:F( { StageSequenceIncrement } )
|
||||
|
||||
local Valid = false
|
||||
if StageSequenceIncrement ~= 0 then
|
||||
self.ActiveStage = self.ActiveStage + StageSequenceIncrement
|
||||
if 1 <= self.ActiveStage and self.ActiveStage <= #self.Stages then
|
||||
self.Stage = self.Stages[self.ActiveStage]
|
||||
self:T( { self.Stage.Name } )
|
||||
self.Frequency = self.Stage.Frequency
|
||||
Valid = true
|
||||
else
|
||||
Valid = false
|
||||
env.info( "TASK:SetStage() self.ActiveStage is smaller or larger than self.Stages array. self.ActiveStage = " .. self.ActiveStage )
|
||||
end
|
||||
end
|
||||
self.Time = timer.getTime()
|
||||
return Valid
|
||||
end
|
||||
|
||||
function TASK:Init()
|
||||
self:F()
|
||||
self.ActiveStage = 0
|
||||
self:SetStage(1)
|
||||
self.TaskDone = false
|
||||
self.TaskFailed = false
|
||||
end
|
||||
|
||||
|
||||
--- Get progress of a TASK.
|
||||
-- @return string GoalsText
|
||||
function TASK:GetGoalProgress()
|
||||
self:F2()
|
||||
|
||||
local GoalsText = ""
|
||||
for GoalVerb, GoalVerbData in pairs( self.GoalTasks ) do
|
||||
local Goals = self:GetGoalCompletion( GoalVerb )
|
||||
if Goals and Goals ~= "" then
|
||||
Goals = '(' .. Goals .. ')'
|
||||
else
|
||||
Goals = '( - )'
|
||||
end
|
||||
GoalsText = GoalsText .. GoalVerb .. ': ' .. self:GetGoalCount(GoalVerb) .. ' goals ' .. Goals .. ' of ' .. self:GetGoalTotal(GoalVerb) .. ' goals completed (' .. self:GetGoalPercentage(GoalVerb) .. '%); '
|
||||
end
|
||||
|
||||
if GoalsText == "" then
|
||||
GoalsText = "( - )"
|
||||
end
|
||||
|
||||
return GoalsText
|
||||
end
|
||||
|
||||
--- Show progress of a TASK.
|
||||
-- @param MISSION Mission Group structure describing the Mission.
|
||||
-- @param CLIENT Client Group structure describing the Client.
|
||||
function TASK:ShowGoalProgress( Mission, Client )
|
||||
self:F2()
|
||||
|
||||
local GoalsText = ""
|
||||
for GoalVerb, GoalVerbData in pairs( self.GoalTasks ) do
|
||||
if Mission:IsCompleted() then
|
||||
else
|
||||
local Goals = self:GetGoalCompletion( GoalVerb )
|
||||
if Goals and Goals ~= "" then
|
||||
else
|
||||
Goals = "-"
|
||||
end
|
||||
GoalsText = GoalsText .. self:GetGoalProgress()
|
||||
end
|
||||
end
|
||||
|
||||
if Mission.MissionReportFlash or Mission.MissionReportShow then
|
||||
Client:Message( GoalsText, 10, "Mission Command: Task Status", 30, "Task status" )
|
||||
end
|
||||
end
|
||||
|
||||
--- Sets a TASK to status Done.
|
||||
function TASK:Done()
|
||||
self:F2()
|
||||
self.TaskDone = true
|
||||
end
|
||||
|
||||
--- Returns if a TASK is done.
|
||||
-- @return bool
|
||||
function TASK:IsDone()
|
||||
self:F2( self.TaskDone )
|
||||
return self.TaskDone
|
||||
end
|
||||
|
||||
--- Sets a TASK to status failed.
|
||||
function TASK:Failed()
|
||||
self:F()
|
||||
self.TaskFailed = true
|
||||
end
|
||||
|
||||
--- Returns if a TASk has failed.
|
||||
-- @return bool
|
||||
function TASK:IsFailed()
|
||||
self:F2( self.TaskFailed )
|
||||
return self.TaskFailed
|
||||
end
|
||||
|
||||
function TASK:Reset( Mission, Client )
|
||||
self:F2()
|
||||
self.ExecuteStage = _TransportExecuteStage.NONE
|
||||
end
|
||||
|
||||
--- Returns the Goals of a TASK
|
||||
-- @return @table Goals
|
||||
function TASK:GetGoals()
|
||||
return self.GoalTasks
|
||||
end
|
||||
|
||||
--- Returns if a TASK has Goal(s).
|
||||
-- @param #TASK self
|
||||
-- @param #string GoalVerb is the name of the Goal of the TASK.
|
||||
-- @return bool
|
||||
function TASK:Goal( GoalVerb )
|
||||
self:F2( { GoalVerb } )
|
||||
if not GoalVerb then
|
||||
GoalVerb = self.GoalVerb
|
||||
end
|
||||
self:T2( {self.GoalTasks[GoalVerb] } )
|
||||
if self.GoalTasks[GoalVerb] and self.GoalTasks[GoalVerb].GoalTotal > 0 then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--- Sets the total Goals to be achieved of the Goal Name
|
||||
-- @param number GoalTotal is the number of times the GoalVerb needs to be achieved.
|
||||
-- @param ?string GoalVerb is the name of the Goal of the TASK. If the GoalVerb is not given, then the default TASK Goals will be used.
|
||||
function TASK:SetGoalTotal( GoalTotal, GoalVerb )
|
||||
self:F2( { GoalTotal, GoalVerb } )
|
||||
|
||||
if not GoalVerb then
|
||||
GoalVerb = self.GoalVerb
|
||||
end
|
||||
self.GoalTasks[GoalVerb] = {}
|
||||
self.GoalTasks[GoalVerb].Goals = {}
|
||||
self.GoalTasks[GoalVerb].GoalTotal = GoalTotal
|
||||
self.GoalTasks[GoalVerb].GoalCount = 0
|
||||
return self
|
||||
end
|
||||
|
||||
--- Gets the total of Goals to be achieved within the TASK of the GoalVerb.
|
||||
-- @param ?string GoalVerb is the name of the Goal of the TASK. If the GoalVerb is not given, then the default TASK Goals will be used.
|
||||
function TASK:GetGoalTotal( GoalVerb )
|
||||
self:F2( { GoalVerb } )
|
||||
if not GoalVerb then
|
||||
GoalVerb = self.GoalVerb
|
||||
end
|
||||
if self:Goal( GoalVerb ) then
|
||||
return self.GoalTasks[GoalVerb].GoalTotal
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
--- Sets the total of Goals currently achieved within the TASK of the GoalVerb.
|
||||
-- @param number GoalCount is the total number of Goals achieved within the TASK.
|
||||
-- @param ?string GoalVerb is the name of the Goal of the TASK. If the GoalVerb is not given, then the default TASK Goals will be used.
|
||||
-- @return TASK
|
||||
function TASK:SetGoalCount( GoalCount, GoalVerb )
|
||||
self:F2()
|
||||
if not GoalVerb then
|
||||
GoalVerb = self.GoalVerb
|
||||
end
|
||||
if self:Goal( GoalVerb) then
|
||||
self.GoalTasks[GoalVerb].GoalCount = GoalCount
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Increments the total of Goals currently achieved within the TASK of the GoalVerb, with the given GoalCountIncrease.
|
||||
-- @param number GoalCountIncrease is the number of new Goals achieved within the TASK.
|
||||
-- @param ?string GoalVerb is the name of the Goal of the TASK. If the GoalVerb is not given, then the default TASK Goals will be used.
|
||||
-- @return TASK
|
||||
function TASK:IncreaseGoalCount( GoalCountIncrease, GoalVerb )
|
||||
self:F2( { GoalCountIncrease, GoalVerb } )
|
||||
if not GoalVerb then
|
||||
GoalVerb = self.GoalVerb
|
||||
end
|
||||
if self:Goal( GoalVerb) then
|
||||
self.GoalTasks[GoalVerb].GoalCount = self.GoalTasks[GoalVerb].GoalCount + GoalCountIncrease
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Gets the total of Goals currently achieved within the TASK of the GoalVerb.
|
||||
-- @param ?string GoalVerb is the name of the Goal of the TASK. If the GoalVerb is not given, then the default TASK Goals will be used.
|
||||
-- @return TASK
|
||||
function TASK:GetGoalCount( GoalVerb )
|
||||
self:F2()
|
||||
if not GoalVerb then
|
||||
GoalVerb = self.GoalVerb
|
||||
end
|
||||
if self:Goal( GoalVerb ) then
|
||||
return self.GoalTasks[GoalVerb].GoalCount
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
--- Gets the percentage of Goals currently achieved within the TASK of the GoalVerb.
|
||||
-- @param ?string GoalVerb is the name of the Goal of the TASK. If the GoalVerb is not given, then the default TASK Goals will be used.
|
||||
-- @return TASK
|
||||
function TASK:GetGoalPercentage( GoalVerb )
|
||||
self:F2()
|
||||
if not GoalVerb then
|
||||
GoalVerb = self.GoalVerb
|
||||
end
|
||||
if self:Goal( GoalVerb ) then
|
||||
return math.floor( self:GetGoalCount( GoalVerb ) / self:GetGoalTotal( GoalVerb ) * 100 + .5 )
|
||||
else
|
||||
return 100
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns if all the Goals of the TASK were achieved.
|
||||
-- @return bool
|
||||
function TASK:IsGoalReached()
|
||||
self:F2()
|
||||
|
||||
local GoalReached = true
|
||||
|
||||
for GoalVerb, Goals in pairs( self.GoalTasks ) do
|
||||
self:T2( { "GoalVerb", GoalVerb } )
|
||||
if self:Goal( GoalVerb ) then
|
||||
local GoalToDo = self:GetGoalTotal( GoalVerb ) - self:GetGoalCount( GoalVerb )
|
||||
self:T2( "GoalToDo = " .. GoalToDo )
|
||||
if GoalToDo <= 0 then
|
||||
else
|
||||
GoalReached = false
|
||||
break
|
||||
end
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
self:T( { GoalReached, self.GoalTasks } )
|
||||
return GoalReached
|
||||
end
|
||||
|
||||
--- Adds an Additional Goal for the TASK to be achieved.
|
||||
-- @param string GoalVerb is the name of the Goal of the TASK.
|
||||
-- @param string GoalTask is a text describing the Goal of the TASK to be achieved.
|
||||
-- @param number GoalIncrease is a number by which the Goal achievement is increasing.
|
||||
function TASK:AddGoalCompletion( GoalVerb, GoalTask, GoalIncrease )
|
||||
self:F2( { GoalVerb, GoalTask, GoalIncrease } )
|
||||
|
||||
if self:Goal( GoalVerb ) then
|
||||
self.GoalTasks[GoalVerb].Goals[#self.GoalTasks[GoalVerb].Goals+1] = GoalTask
|
||||
self.GoalTasks[GoalVerb].GoalCount = self.GoalTasks[GoalVerb].GoalCount + GoalIncrease
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Returns if the additional Goal for the TASK was completed.
|
||||
-- @param ?string GoalVerb is the name of the Goal of the TASK. If the GoalVerb is not given, then the default TASK Goals will be used.
|
||||
-- @return string Goals
|
||||
function TASK:GetGoalCompletion( GoalVerb )
|
||||
self:F2( { GoalVerb } )
|
||||
|
||||
if self:Goal( GoalVerb ) then
|
||||
local Goals = ""
|
||||
for GoalID, GoalName in pairs( self.GoalTasks[GoalVerb].Goals ) do Goals = Goals .. GoalName .. " + " end
|
||||
return Goals:gsub(" + $", ""), self.GoalTasks[GoalVerb].GoalCount
|
||||
end
|
||||
end
|
||||
|
||||
function TASK.MenuAction( Parameter )
|
||||
Parameter.ReferenceTask.ExecuteStage = _TransportExecuteStage.EXECUTING
|
||||
Parameter.ReferenceTask.Cargo = Parameter.CargoTask
|
||||
end
|
||||
|
||||
function TASK:StageExecute()
|
||||
self:F()
|
||||
|
||||
local Execute = false
|
||||
|
||||
if self.Frequency == STAGE.FREQUENCY.REPEAT then
|
||||
Execute = true
|
||||
elseif self.Frequency == STAGE.FREQUENCY.NONE then
|
||||
Execute = false
|
||||
elseif self.Frequency >= 0 then
|
||||
Execute = true
|
||||
self.Frequency = self.Frequency - 1
|
||||
end
|
||||
|
||||
return Execute
|
||||
|
||||
end
|
||||
|
||||
--- Work function to set signal events within a TASK.
|
||||
function TASK:AddSignal( SignalUnitNames, SignalType, SignalColor, SignalHeight )
|
||||
self:F()
|
||||
|
||||
local Valid = true
|
||||
|
||||
if Valid then
|
||||
if type( SignalUnitNames ) == "table" then
|
||||
self.LandingZoneSignalUnitNames = SignalUnitNames
|
||||
else
|
||||
self.LandingZoneSignalUnitNames = { SignalUnitNames }
|
||||
end
|
||||
self.LandingZoneSignalType = SignalType
|
||||
self.LandingZoneSignalColor = SignalColor
|
||||
self.Signalled = false
|
||||
if SignalHeight ~= nil then
|
||||
self.LandingZoneSignalHeight = SignalHeight
|
||||
else
|
||||
self.LandingZoneSignalHeight = 0
|
||||
end
|
||||
|
||||
if self.TaskBriefing then
|
||||
self.TaskBriefing = self.TaskBriefing .. " " .. SignalColor.TEXT .. " " .. SignalType.TEXT .. " will be fired when entering the landing zone."
|
||||
end
|
||||
end
|
||||
|
||||
return Valid
|
||||
end
|
||||
|
||||
--- When the CLIENT is approaching the landing zone, a RED SMOKE will be fired by an optional SignalUnitNames.
|
||||
-- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone.
|
||||
-- @param number SignalHeight Altitude that the Signal should be fired...
|
||||
function TASK:AddSmokeRed( SignalUnitNames, SignalHeight )
|
||||
self:F()
|
||||
self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.SMOKE, TASK.SIGNAL.COLOR.RED, SignalHeight )
|
||||
end
|
||||
|
||||
--- When the CLIENT is approaching the landing zone, a GREEN SMOKE will be fired by an optional SignalUnitNames.
|
||||
-- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone.
|
||||
-- @param number SignalHeight Altitude that the Signal should be fired...
|
||||
function TASK:AddSmokeGreen( SignalUnitNames, SignalHeight )
|
||||
self:F()
|
||||
self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.SMOKE, TASK.SIGNAL.COLOR.GREEN, SignalHeight )
|
||||
end
|
||||
|
||||
--- When the CLIENT is approaching the landing zone, a BLUE SMOKE will be fired by an optional SignalUnitNames.
|
||||
-- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone.
|
||||
-- @param number SignalHeight Altitude that the Signal should be fired...
|
||||
function TASK:AddSmokeBlue( SignalUnitNames, SignalHeight )
|
||||
self:F()
|
||||
self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.SMOKE, TASK.SIGNAL.COLOR.BLUE, SignalHeight )
|
||||
end
|
||||
|
||||
--- When the CLIENT is approaching the landing zone, a WHITE SMOKE will be fired by an optional SignalUnitNames.
|
||||
-- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone.
|
||||
-- @param number SignalHeight Altitude that the Signal should be fired...
|
||||
function TASK:AddSmokeWhite( SignalUnitNames, SignalHeight )
|
||||
self:F()
|
||||
self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.SMOKE, TASK.SIGNAL.COLOR.WHITE, SignalHeight )
|
||||
end
|
||||
|
||||
--- When the CLIENT is approaching the landing zone, an ORANGE SMOKE will be fired by an optional SignalUnitNames.
|
||||
-- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone.
|
||||
-- @param number SignalHeight Altitude that the Signal should be fired...
|
||||
function TASK:AddSmokeOrange( SignalUnitNames, SignalHeight )
|
||||
self:F()
|
||||
self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.SMOKE, TASK.SIGNAL.COLOR.ORANGE, SignalHeight )
|
||||
end
|
||||
|
||||
--- When the CLIENT is approaching the landing zone, a RED FLARE will be fired by an optional SignalUnitNames.
|
||||
-- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone.
|
||||
-- @param number SignalHeight Altitude that the Signal should be fired...
|
||||
function TASK:AddFlareRed( SignalUnitNames, SignalHeight )
|
||||
self:F()
|
||||
self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.FLARE, TASK.SIGNAL.COLOR.RED, SignalHeight )
|
||||
end
|
||||
|
||||
--- When the CLIENT is approaching the landing zone, a GREEN FLARE will be fired by an optional SignalUnitNames.
|
||||
-- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone.
|
||||
-- @param number SignalHeight Altitude that the Signal should be fired...
|
||||
function TASK:AddFlareGreen( SignalUnitNames, SignalHeight )
|
||||
self:F()
|
||||
self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.FLARE, TASK.SIGNAL.COLOR.GREEN, SignalHeight )
|
||||
end
|
||||
|
||||
--- When the CLIENT is approaching the landing zone, a BLUE FLARE will be fired by an optional SignalUnitNames.
|
||||
-- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone.
|
||||
-- @param number SignalHeight Altitude that the Signal should be fired...
|
||||
function TASK:AddFlareBlue( SignalUnitNames, SignalHeight )
|
||||
self:F()
|
||||
self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.FLARE, TASK.SIGNAL.COLOR.BLUE, SignalHeight )
|
||||
end
|
||||
|
||||
--- When the CLIENT is approaching the landing zone, a WHITE FLARE will be fired by an optional SignalUnitNames.
|
||||
-- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone.
|
||||
-- @param number SignalHeight Altitude that the Signal should be fired...
|
||||
function TASK:AddFlareWhite( SignalUnitNames, SignalHeight )
|
||||
self:F()
|
||||
self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.FLARE, TASK.SIGNAL.COLOR.WHITE, SignalHeight )
|
||||
end
|
||||
|
||||
--- When the CLIENT is approaching the landing zone, an ORANGE FLARE will be fired by an optional SignalUnitNames.
|
||||
-- @param table|string SignalUnitNames Name of the Group that will fire the signal. If this parameter is NIL, the signal will be fired from the center of the landing zone.
|
||||
-- @param number SignalHeight Altitude that the Signal should be fired...
|
||||
function TASK:AddFlareOrange( SignalUnitNames, SignalHeight )
|
||||
self:F()
|
||||
self:AddSignal( SignalUnitNames, TASK.SIGNAL.TYPE.FLARE, TASK.SIGNAL.COLOR.ORANGE, SignalHeight )
|
||||
end
|
||||
@@ -49,7 +49,7 @@
|
||||
-- -----------------------------
|
||||
-- The UNIT class provides methods to obtain the current point or position of the DCS Unit.
|
||||
-- The @{#UNIT.GetPointVec2}(), @{#UNIT.GetPointVec3}() will obtain the current **location** of the DCS Unit in a Vec2 (2D) or a **point** in a Vec3 (3D) vector respectively.
|
||||
-- If you want to obtain the complete **3D position** including oriëntation and direction vectors, consult the @{#UNIT.GetPositionVec3}() method respectively.
|
||||
-- If you want to obtain the complete **3D position** including ori<EFBFBD>ntation and direction vectors, consult the @{#UNIT.GetPositionVec3}() method respectively.
|
||||
--
|
||||
-- 1.5) Test if alive
|
||||
-- ------------------
|
||||
@@ -352,7 +352,6 @@ function UNIT:HasSensors( ... )
|
||||
local DCSUnit = self:GetDCSObject()
|
||||
|
||||
if DCSUnit then
|
||||
self:E( arg )
|
||||
local HasSensors = DCSUnit:hasSensors( unpack( arg ) )
|
||||
return HasSensors
|
||||
end
|
||||
@@ -360,6 +359,29 @@ function UNIT:HasSensors( ... )
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns if the unit is SEADable.
|
||||
-- @param Unit#UNIT self
|
||||
-- @return #boolean returns true if the unit is SEADable.
|
||||
-- @return #nil The DCS Unit is not existing or alive.
|
||||
function UNIT:HasSEAD()
|
||||
self:F2()
|
||||
|
||||
local DCSUnit = self:GetDCSObject()
|
||||
|
||||
if DCSUnit then
|
||||
local UnitSEADAttributes = DCSUnit:getDesc().attributes
|
||||
|
||||
local HasSEAD = false
|
||||
if UnitSEADAttributes["RADAR_BAND1_FOR_ARM"] and UnitSEADAttributes["RADAR_BAND1_FOR_ARM"] == true or
|
||||
UnitSEADAttributes["RADAR_BAND2_FOR_ARM"] and UnitSEADAttributes["RADAR_BAND2_FOR_ARM"] == true then
|
||||
HasSEAD = true
|
||||
end
|
||||
return HasSEAD
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns two values:
|
||||
--
|
||||
-- * First value indicates if at least one of the unit's radar(s) is on.
|
||||
@@ -432,7 +454,47 @@ function UNIT:GetLife0()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns the Unit's A2G threat level on a scale from 1 to 10 ...
|
||||
-- The following threat levels are foreseen:
|
||||
--
|
||||
-- * Threat level 0: Unit is unarmed.
|
||||
-- * Threat level 1: Unit is infantry.
|
||||
-- * Threat level 2: Unit is an infantry vehicle.
|
||||
-- * Threat level 3: Unit is ground artillery.
|
||||
-- * Threat level 4: Unit is a tank.
|
||||
-- * Threat level 5: Unit is a modern tank or ifv with ATGM.
|
||||
-- * Threat level 6: Unit is a AAA.
|
||||
-- * Threat level 7: Unit is a SAM or manpad, IR guided.
|
||||
-- * Threat level 8: Unit is a Short Range SAM, radar guided.
|
||||
-- * Threat level 9: Unit is a Medium Range SAM, radar guided.
|
||||
-- * Threat level 10: Unit is a Long Range SAM, radar guided.
|
||||
function UNIT:GetThreatLevel()
|
||||
|
||||
local Attributes = self:GetDesc().attributes
|
||||
local ThreatLevel = 0
|
||||
|
||||
self:T2( Attributes )
|
||||
|
||||
if Attributes["LR SAM"] then ThreatLevel = 10
|
||||
elseif Attributes["MR SAM"] then ThreatLevel = 9
|
||||
elseif Attributes["SR SAM"] and
|
||||
not Attributes["IR Guided SAM"] then ThreatLevel = 8
|
||||
elseif ( Attributes["SR SAM"] or Attributes["MANPADS"] ) and
|
||||
Attributes["IR Guided SAM"] then ThreatLevel = 7
|
||||
elseif Attributes["AAA"] then ThreatLevel = 6
|
||||
elseif Attributes["Modern Tanks"] then ThreatLevel = 5
|
||||
elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and
|
||||
Attributes["ATGM"] then ThreatLevel = 4
|
||||
elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and
|
||||
not Attributes["ATGM"] then ThreatLevel = 3
|
||||
elseif Attributes["Old Tanks"] or Attributes["APC"] then ThreatLevel = 2
|
||||
elseif Attributes["Infantry"] then ThreatLevel = 1
|
||||
end
|
||||
|
||||
self:T2( ThreatLevel )
|
||||
return ThreatLevel
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Is functions
|
||||
@@ -449,9 +511,9 @@ function UNIT:IsInZone( Zone )
|
||||
|
||||
self:T( { IsInZone } )
|
||||
return IsInZone
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Returns true if the unit is not within a @{Zone}.
|
||||
@@ -533,14 +595,22 @@ end
|
||||
-- @param #UNIT self
|
||||
function UNIT:FlareRed()
|
||||
self:F2()
|
||||
trigger.action.signalFlare( self:GetPointVec3(), trigger.flareColor.Red, 0 )
|
||||
local Vec3 = self:GetPointVec3()
|
||||
if Vec3 then
|
||||
trigger.action.signalFlare( Vec3, trigger.flareColor.Red, 0 )
|
||||
end
|
||||
end
|
||||
|
||||
--- Smoke the UNIT.
|
||||
-- @param #UNIT self
|
||||
function UNIT:Smoke( SmokeColor )
|
||||
function UNIT:Smoke( SmokeColor, Range )
|
||||
self:F2()
|
||||
trigger.action.smoke( self:GetPointVec3(), SmokeColor )
|
||||
if Range then
|
||||
trigger.action.smoke( self:GetRandomPointVec3( Range ), SmokeColor )
|
||||
else
|
||||
trigger.action.smoke( self:GetPointVec3(), SmokeColor )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Smoke the UNIT Green.
|
||||
@@ -624,6 +694,27 @@ function UNIT:IsGround()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns if the unit is a friendly unit.
|
||||
-- @param #UNIT self
|
||||
-- @return #boolean IsFriendly evaluation result.
|
||||
function UNIT:IsFriendly( FriendlyCoalition )
|
||||
self:F2()
|
||||
|
||||
local DCSUnit = self:GetDCSObject()
|
||||
|
||||
if DCSUnit then
|
||||
local UnitCoalition = DCSUnit:getCoalition()
|
||||
self:T3( { UnitCoalition, FriendlyCoalition } )
|
||||
|
||||
local IsFriendlyResult = ( UnitCoalition == FriendlyCoalition )
|
||||
|
||||
self:E( IsFriendlyResult )
|
||||
return IsFriendlyResult
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns if the unit is of a ship category.
|
||||
-- If the unit is a ship, this method will return true, otherwise false.
|
||||
-- @param #UNIT self
|
||||
|
||||
@@ -1,4 +1,21 @@
|
||||
|
||||
--- @type SMOKECOLOR
|
||||
-- @field Green
|
||||
-- @field Red
|
||||
-- @field White
|
||||
-- @field Orange
|
||||
-- @field Blue
|
||||
|
||||
SMOKECOLOR = trigger.smokeColor -- #SMOKECOLOR
|
||||
|
||||
--- @type FLARECOLOR
|
||||
-- @field Green
|
||||
-- @field Red
|
||||
-- @field White
|
||||
-- @field Yellow
|
||||
|
||||
FLARECOLOR = trigger.flareColor -- #FLARECOLOR
|
||||
|
||||
--- Utilities static class.
|
||||
-- @type UTILS
|
||||
UTILS = {}
|
||||
@@ -157,6 +174,95 @@ UTILS.KmphToMps = function(kmph)
|
||||
return kmph/3.6
|
||||
end
|
||||
|
||||
--[[acc:
|
||||
in DM: decimal point of minutes.
|
||||
In DMS: decimal point of seconds.
|
||||
position after the decimal of the least significant digit:
|
||||
So:
|
||||
42.32 - acc of 2.
|
||||
]]
|
||||
UTILS.tostringLL = function( lat, lon, acc, DMS)
|
||||
|
||||
local latHemi, lonHemi
|
||||
if lat > 0 then
|
||||
latHemi = 'N'
|
||||
else
|
||||
latHemi = 'S'
|
||||
end
|
||||
|
||||
if lon > 0 then
|
||||
lonHemi = 'E'
|
||||
else
|
||||
lonHemi = 'W'
|
||||
end
|
||||
|
||||
lat = math.abs(lat)
|
||||
lon = math.abs(lon)
|
||||
|
||||
local latDeg = math.floor(lat)
|
||||
local latMin = (lat - latDeg)*60
|
||||
|
||||
local lonDeg = math.floor(lon)
|
||||
local lonMin = (lon - lonDeg)*60
|
||||
|
||||
if DMS then -- degrees, minutes, and seconds.
|
||||
local oldLatMin = latMin
|
||||
latMin = math.floor(latMin)
|
||||
local latSec = UTILS.Round((oldLatMin - latMin)*60, acc)
|
||||
|
||||
local oldLonMin = lonMin
|
||||
lonMin = math.floor(lonMin)
|
||||
local lonSec = UTILS.Round((oldLonMin - lonMin)*60, acc)
|
||||
|
||||
if latSec == 60 then
|
||||
latSec = 0
|
||||
latMin = latMin + 1
|
||||
end
|
||||
|
||||
if lonSec == 60 then
|
||||
lonSec = 0
|
||||
lonMin = lonMin + 1
|
||||
end
|
||||
|
||||
local secFrmtStr -- create the formatting string for the seconds place
|
||||
if acc <= 0 then -- no decimal place.
|
||||
secFrmtStr = '%02d'
|
||||
else
|
||||
local width = 3 + acc -- 01.310 - that's a width of 6, for example.
|
||||
secFrmtStr = '%0' .. width .. '.' .. acc .. 'f'
|
||||
end
|
||||
|
||||
return string.format('%02d', latDeg) .. ' ' .. string.format('%02d', latMin) .. '\' ' .. string.format(secFrmtStr, latSec) .. '"' .. latHemi .. ' '
|
||||
.. string.format('%02d', lonDeg) .. ' ' .. string.format('%02d', lonMin) .. '\' ' .. string.format(secFrmtStr, lonSec) .. '"' .. lonHemi
|
||||
|
||||
else -- degrees, decimal minutes.
|
||||
latMin = UTILS.Round(latMin, acc)
|
||||
lonMin = UTILS.Round(lonMin, acc)
|
||||
|
||||
if latMin == 60 then
|
||||
latMin = 0
|
||||
latDeg = latDeg + 1
|
||||
end
|
||||
|
||||
if lonMin == 60 then
|
||||
lonMin = 0
|
||||
lonDeg = lonDeg + 1
|
||||
end
|
||||
|
||||
local minFrmtStr -- create the formatting string for the minutes place
|
||||
if acc <= 0 then -- no decimal place.
|
||||
minFrmtStr = '%02d'
|
||||
else
|
||||
local width = 3 + acc -- 01.310 - that's a width of 6, for example.
|
||||
minFrmtStr = '%0' .. width .. '.' .. acc .. 'f'
|
||||
end
|
||||
|
||||
return string.format('%02d', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' '
|
||||
.. string.format('%02d', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- From http://lua-users.org/wiki/SimpleRound
|
||||
-- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place
|
||||
|
||||
@@ -307,9 +307,11 @@ function ZONE_RADIUS:IsPointVec2InZone( Vec2 )
|
||||
self:F2( Vec2 )
|
||||
|
||||
local ZoneVec2 = self:GetVec2()
|
||||
|
||||
if (( Vec2.x - ZoneVec2.x )^2 + ( Vec2.y - ZoneVec2.y ) ^2 ) ^ 0.5 <= self:GetRadius() then
|
||||
return true
|
||||
|
||||
if ZoneVec2 then
|
||||
if (( Vec2.x - ZoneVec2.x )^2 + ( Vec2.y - ZoneVec2.y ) ^2 ) ^ 0.5 <= self:GetRadius() then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
@@ -396,6 +398,7 @@ function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius )
|
||||
self:F( { ZoneName, ZoneUNIT:GetVec2(), Radius } )
|
||||
|
||||
self.ZoneUNIT = ZoneUNIT
|
||||
self.LastVec2 = ZoneUNIT:GetVec2()
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -408,10 +411,16 @@ function ZONE_UNIT:GetVec2()
|
||||
self:F( self.ZoneName )
|
||||
|
||||
local ZoneVec2 = self.ZoneUNIT:GetVec2()
|
||||
if ZoneVec2 then
|
||||
self.LastVec2 = ZoneVec2
|
||||
return ZoneVec2
|
||||
else
|
||||
return self.LastVec2
|
||||
end
|
||||
|
||||
self:T( { ZoneVec2 } )
|
||||
|
||||
return ZoneVec2
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns a random location within the zone.
|
||||
@@ -422,6 +431,9 @@ function ZONE_UNIT:GetRandomVec2()
|
||||
|
||||
local Point = {}
|
||||
local PointVec2 = self.ZoneUNIT:GetPointVec2()
|
||||
if not PointVec2 then
|
||||
PointVec2 = self.LastVec2
|
||||
end
|
||||
|
||||
local angle = math.random() * math.pi*2;
|
||||
Point.x = PointVec2.x + math.cos( angle ) * math.random() * self:GetRadius();
|
||||
@@ -432,6 +444,24 @@ function ZONE_UNIT:GetRandomVec2()
|
||||
return Point
|
||||
end
|
||||
|
||||
--- Returns the point of the zone.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param DCSTypes#Distance Height The height to add to the land height where the center of the zone is located.
|
||||
-- @return DCSTypes#Vec3 The point of the zone.
|
||||
function ZONE_UNIT:GetPointVec3( Height )
|
||||
self:F2( self.ZoneName )
|
||||
|
||||
Height = Height or 0
|
||||
|
||||
local Vec2 = self:GetVec2()
|
||||
|
||||
local PointVec3 = { x = Vec2.x, y = land.getHeight( self:GetVec2() ) + Height, z = Vec2.y }
|
||||
|
||||
self:T2( { PointVec3 } )
|
||||
|
||||
return PointVec3
|
||||
end
|
||||
|
||||
--- The ZONE_GROUP class defined by a zone around a @{Group}, taking the average center point of all the units within the Group, with a radius.
|
||||
-- @type ZONE_GROUP
|
||||
-- @field Group#GROUP ZoneGROUP
|
||||
|
||||
Reference in New Issue
Block a user