Merge pull request #111 from FlightControl-Master/Detection

I am finally releasing the first alpha release of the DETECTION_DISPATCHER and DETECTION_AREAS classes!!! If you want to try out, have a look at the DETECTION_DISPATCHER test mission.
+ A lot of changes have been done at internal code also. MENU capabilities have been added, and also added a POINT_VEC3 and a POINT_VEC2 class to manage points better. There is still rework pending on points.

It can be that due to this release, you'll get errors in your previous missions, so please re-test them!
This commit is contained in:
Sven Van de Velde 2016-07-19 18:22:38 +02:00 committed by GitHub
commit 054da51d97
156 changed files with 28875 additions and 6205 deletions

View File

@ -0,0 +1,5 @@
-------------------------------------------------------------------------------
-- @module DCStrigger
trigger = {} --#timer

View File

@ -153,7 +153,7 @@ function AIBALANCER:_ClientAliveMonitorScheduler()
-- If there is no CLIENT within the self.ReturnTresholdRange, then the unit will return to the Airbase return method selected.
local PlayerInRange = { Value = false }
local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetPointVec2(), self.ReturnTresholdRange )
local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnTresholdRange )
self:E( RangeZone )
@ -183,7 +183,7 @@ function AIBALANCER:_ClientAliveMonitorScheduler()
else
-- Okay, we need to send this Group back to the nearest base of the Coalition of the AI.
--TODO: i need to rework the POINT_VEC2 thing.
local PointVec2 = POINT_VEC2:New( AIGroup:GetPointVec2().x, AIGroup:GetPointVec2().y )
local PointVec2 = POINT_VEC2:New( AIGroup:GetVec2().x, AIGroup:GetVec2().y )
local ClosestAirbase = self.ReturnAirbaseSet:FindNearestAirbaseFromPointVec2( PointVec2 )
self:T( ClosestAirbase.AirbaseName )
AIGroup:MessageToRed( "Returning to " .. ClosestAirbase:GetName().. " ...", 30 )

View File

@ -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.

View File

@ -55,8 +55,9 @@
--
-- ====
--
-- ### Author: FlightControl
--
-- @module Base
-- @author FlightControl
@ -115,7 +116,6 @@ function BASE:New()
self.__index = self
_ClassID = _ClassID + 1
self.ClassID = _ClassID
self.ClassNameAndID = string.format( '%s#%09d', self.ClassName, self.ClassID )
return self
end
@ -132,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
@ -141,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
@ -152,7 +151,7 @@ end
-- @param #BASE self
-- @return #string The ClassName + ClassID of the class instance.
function BASE:GetClassNameAndID()
return self.ClassNameAndID
return string.format( '%s#%09d', self.ClassName, self.ClassID )
end
--- Get the ClassName of the class instance.
@ -339,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
@ -354,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
@ -379,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
@ -391,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

View File

@ -600,7 +600,7 @@ function CONTROLLABLE:TaskOrbitCircle( Altitude, Speed )
local DCSControllable = self:GetDCSObject()
if DCSControllable then
local ControllablePoint = self:GetPointVec2()
local ControllablePoint = self:GetVec2()
return self:TaskOrbitCircleAtVec2( ControllablePoint, Altitude, Speed )
end
@ -777,7 +777,7 @@ function CONTROLLABLE:TaskLandAtZone( Zone, Duration, RandomPoint )
if RandomPoint then
Point = Zone:GetRandomVec2()
else
Point = Zone:GetPointVec2()
Point = Zone:GetVec2()
end
local DCSTask = self:TaskLandAtVec2( Point, Duration )
@ -1377,7 +1377,7 @@ end
function CONTROLLABLE:TaskRouteToVec2( Point, Speed )
self:F2( { Point, Speed } )
local ControllablePoint = self:GetUnit( 1 ):GetPointVec2()
local ControllablePoint = self:GetUnit( 1 ):GetVec2()
local PointFrom = {}
PointFrom.x = ControllablePoint.x
@ -1516,7 +1516,7 @@ function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation )
if DCSControllable then
local ControllablePoint = self:GetPointVec2()
local ControllablePoint = self:GetVec2()
local PointFrom = {}
PointFrom.x = ControllablePoint.x
@ -1532,7 +1532,7 @@ function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation )
if Randomize then
ZonePoint = Zone:GetRandomVec2()
else
ZonePoint = Zone:GetPointVec2()
ZonePoint = Zone:GetVec2()
end
PointTo.x = ZonePoint.x
@ -1614,7 +1614,7 @@ function CONTROLLABLE:RouteReturnToAirbase( ReturnAirbase, Speed )
if DCSControllable then
local ControllablePoint = self:GetPointVec2()
local ControllablePoint = self:GetVec2()
local ControllableVelocity = self:GetMaxVelocity()
local PointFrom = {}
@ -1626,7 +1626,7 @@ function CONTROLLABLE:RouteReturnToAirbase( ReturnAirbase, Speed )
local PointTo = {}
local AirbasePoint = ReturnAirbase:GetPointVec2()
local AirbasePoint = ReturnAirbase:GetVec2()
PointTo.x = AirbasePoint.x
PointTo.y = AirbasePoint.y

View File

@ -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

View File

@ -5,6 +5,7 @@
-- 1) @{Detection#DETECTION_BASE} class, extends @{Base#BASE}
-- ==========================================================
-- The @{Detection#DETECTION_BASE} class defines the core functions to administer detected objects.
-- The @{Detection#DETECTION_BASE} class will detect objects within the battle zone for a list of @{Group}s detecting targets following (a) detection method(s).
--
-- 1.1) DETECTION_BASE constructor
-- -------------------------------
@ -33,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 FAC group,
-- 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}().
@ -54,53 +55,59 @@
--
-- 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 FACGroup 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.DetectedSets DetectedSets A list of @{Set#SET_BASE}s containing the objects in each set that were detected. The base class will not build the detected sets, but will leave that to the derived classes.
-- @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",
DetectedSets = {},
DetectedObjects = {},
FACGroup = nil,
DetectionSetGroup = nil,
DetectionRange = nil,
DetectedObjects = {},
DetectionRun = 0,
DetectedObjectsIdentified = {},
}
--- @type DETECTION_BASE.DetectedSets
-- @list <Set#SET_BASE>
--- @type DETECTION_BASE.DetectedZones
-- @list <Zone#ZONE_BASE>
--- @type DETECTION_BASE.DetectedObjects
-- @list <#DETECTION_BASE.DetectedObject>
--- @type DETECTION_BASE.DetectedObject
-- @field #string Name
-- @field #boolean Visible
-- @field #string Type
-- @field #number Distance
-- @field #boolean Identified
--- DETECTION constructor.
-- @param #DETECTION_BASE self
-- @param Group#GROUP FACGroup 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( FACGroup, DetectionRange )
function DETECTION_BASE:New( DetectionSetGroup, DetectionRange )
-- Inherits from BASE
local self = BASE:Inherit( self, BASE:New() )
self.FACGroup = FACGroup
self.DetectionSetGroup = DetectionSetGroup
self.DetectionRange = DetectionRange
self:InitDetectVisual( false )
@ -172,13 +179,65 @@ function DETECTION_BASE:InitDetectDLINK( DetectDLINK )
self.DetectDLINK = DetectDLINK
end
--- Gets the FAC group.
--- Determines if a detected object has already been identified during detection processing.
-- @param #DETECTION_BASE self
-- @return Group#GROUP self
function DETECTION_BASE:GetFACGroup()
self:F2()
-- @param #DETECTION_BASE.DetectedObject DetectedObject
-- @return #boolean true if already identified.
function DETECTION_BASE:IsDetectedObjectIdentified( DetectedObject )
self:F3( DetectedObject.Name )
return self.FACGroup
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:F3( ObjectName )
if ObjectName then
local DetectedObject = self.DetectedObjects[ObjectName]
-- 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
end
--- Get the detected @{Set#SET_BASE}s.
@ -213,6 +272,14 @@ function DETECTION_BASE:GetDetectedSet( Index )
return nil
end
--- Get the detection Groups.
-- @param #DETECTION_BASE self
-- @return Group#GROUP
function DETECTION_BASE:GetDetectionSetGroup()
local DetectionSetGroup = self.DetectionSetGroup
return DetectionSetGroup
end
--- Make a DetectionSet table. This function will be overridden in the derived clsses.
-- @param #DETECTION_BASE self
@ -224,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.
@ -245,141 +313,195 @@ end
function DETECTION_BASE:_DetectionScheduler( SchedulerName )
self:F2( { SchedulerName } )
self.DetectedObjects = {}
self.DetectedSets = {}
self.DetectedZones = {}
self.DetectionRun = self.DetectionRun + 1
if self.FACGroup:IsAlive() then
local FACGroupName = self.FACGroup:GetName()
local FACDetectedTargets = self.FACGroup:GetDetectedTargets(
self.DetectVisual,
self.DetectOptical,
self.DetectRadar,
self.DetectIRST,
self.DetectRWR,
self.DetectDLINK
)
for FACDetectedTargetID, FACDetectedTarget in pairs( FACDetectedTargets ) do
local FACObject = FACDetectedTarget.object -- DCSObject#Object
self:T2( FACObject )
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 FACObject and FACObject:isExist() and FACObject.id_ < 50000000 then
local FACDetectedObjectName = FACObject:getName()
local FACDetectedObjectPositionVec3 = FACObject:getPoint()
local FACGroupPositionVec3 = self.FACGroup:GetPointVec3()
local Distance = ( ( FACDetectedObjectPositionVec3.x - FACGroupPositionVec3.x )^2 +
( FACDetectedObjectPositionVec3.y - FACGroupPositionVec3.y )^2 +
( FACDetectedObjectPositionVec3.z - FACGroupPositionVec3.z )^2
) ^ 0.5 / 1000
self:T( { FACGroupName, FACDetectedObjectName, Distance } )
if Distance <= self.DetectionRange then
if not self.DetectedObjects[FACDetectedObjectName] then
self.DetectedObjects[FACDetectedObjectName] = {}
end
self.DetectedObjects[FACDetectedObjectName].Name = FACDetectedObjectName
self.DetectedObjects[FACDetectedObjectName].Visible = FACDetectedTarget.visible
self.DetectedObjects[FACDetectedObjectName].Type = FACDetectedTarget.type
self.DetectedObjects[FACDetectedObjectName].Distance = FACDetectedTarget.distance
else
-- if beyond the DetectionRange then nullify...
if self.DetectedObjects[FACDetectedObjectName] then
self.DetectedObjects[FACDetectedObjectName] = 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
--- @type DETECTION_UNITGROUPS.DetectedSets
-- @list <Set#SET_UNIT>
--
--- @type DETECTION_UNITGROUPS.DetectedZones
-- @list <Zone#ZONE_UNIT>
--
--- DETECTION_UNITGROUPS class
-- @type DETECTION_UNITGROUPS
-- @param DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
-- @field #DETECTION_UNITGROUPS.DetectedSets DetectedSets A list of @{Set#SET_UNIT}s containing the units in each set that were detected within a DetectionZoneRange.
-- @field #DETECTION_UNITGROUPS.DetectedZones DetectedZones A list of @{Zone#ZONE_UNIT}s containing the zones of the reference detected units.
--- DETECTION_AREAS class
-- @type DETECTION_AREAS
-- @field DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
-- @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",
DetectedZones = {},
DETECTION_AREAS = {
ClassName = "DETECTION_AREAS",
DetectedAreas = { n = 0 },
DetectionZoneRange = nil,
}
--- @type DETECTION_AREAS.DetectedAreas
-- @list <#DETECTION_AREAS.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 FACGroup 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( FACGroup, 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( FACGroup, 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
--- Get the detected @{Zone#ZONE_UNIT}s.
-- @param #DETECTION_UNITGROUPS self
-- @return #DETECTION_UNITGROUPS.DetectedZones DetectedZones
function DETECTION_UNITGROUPS:GetDetectedZones()
local DetectedZones = self.DetectedZones
return DetectedZones
--- 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_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.Removed = false
DetectedArea.AreaID = DetectedAreas.n
return DetectedArea
end
--- Get the amount of @{Zone#ZONE_UNIT}s with detected units.
-- @param #DETECTION_UNITGROUPS self
-- @return #number Count
function DETECTION_UNITGROUPS:GetDetectedZoneCount()
local DetectedZoneCount = #self.DetectedZones
return DetectedZoneCount
--- 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_AREAS:RemoveDetectedArea( Index )
local DetectedAreas = self:GetDetectedAreas()
local DetectedAreaCount = self:GetDetectedAreaCount()
local DetectedArea = DetectedAreas[Index]
local DetectedAreaSet = DetectedArea.Set
DetectedArea[Index] = nil
return nil
end
--- Get a SET of detected objects using a given numeric index.
-- @param #DETECTION_UNITGROUPS self
--- 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_AREAS.DetectedAreas}.
-- @param #DETECTION_AREAS self
-- @return #number DetectedAreaCount
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_AREAS self
-- @param #number Index
-- @return Zone#ZONE_UNIT
function DETECTION_UNITGROUPS:GetDetectedZone( Index )
-- @return Set#SET_UNIT DetectedSet
function DETECTION_AREAS:GetDetectedSet( Index )
local DetectedZone = self.DetectedZones[Index]
local DetectedSetUnit = self.DetectedAreas[Index].Set
if DetectedSetUnit then
return DetectedSetUnit
end
return nil
end
--- Get the @{Zone#ZONE_UNIT} of a detection area using a given numeric index.
-- @param #DETECTION_AREAS self
-- @param #number Index
-- @return Zone#ZONE_UNIT DetectedZone
function DETECTION_AREAS:GetDetectedZone( Index )
local DetectedZone = self.DetectedAreas[Index].Zone
if DetectedZone then
return DetectedZone
end
@ -387,10 +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
@ -398,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
@ -408,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
@ -418,77 +637,310 @@ 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()
for DetectedUnitName, DetectedUnitData in pairs( self.DetectedObjects ) do
self:T( DetectedUnitData.Name )
local DetectedUnit = UNIT:FindByName( DetectedUnitData.Name ) -- Unit#UNIT
if DetectedUnit and DetectedUnit:IsAlive() then
self:T( DetectedUnit:GetName() )
if #self.DetectedSets == 0 then
self:T( { "Adding Unit Set #", 1 } )
self.DetectedZones[1] = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange )
self.DetectedSets[1] = SET_UNIT:New()
self.DetectedSets[1]:AddUnit( DetectedUnit )
-- 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_AREAS.DetectedArea
if DetectedArea then
local DetectedSet = DetectedArea.Set
local AreaExists = false -- This flag will determine of the detected area is still existing.
-- 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
else
local AddedToSet = false
for DetectedZoneIndex = 1, #self.DetectedZones do
self:T( "Detected Unit Set #" .. DetectedZoneIndex )
local DetectedUnitSet = self.DetectedSets[DetectedZoneIndex] -- Set#SET_BASE
local DetectedZone = self.DetectedZones[DetectedZoneIndex] -- Zone#ZONE_UNIT
if DetectedUnit:IsInZone( DetectedZone ) then
self:T( "Adding to Unit Set #" .. DetectedZoneIndex )
DetectedUnitSet:AddUnit( DetectedUnit )
AddedToSet = true
-- 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: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 )
-- 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
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
if AddedToSet == false then
local DetectedZoneIndex = #self.DetectedZones + 1
self:T( "Adding new zone #" .. DetectedZoneIndex )
self.DetectedZones[DetectedZoneIndex] = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange )
self.DetectedSets[DetectedZoneIndex] = SET_UNIT:New()
self.DetectedSets[DetectedZoneIndex]:AddUnit( DetectedUnit )
end
end
-- Now we've determined the center unit of the area, now we can iterate the units in the detected area.
-- 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 = nil
if DetectedUnit:IsAlive() then
--self:E(DetectedUnit:GetName())
DetectedObject = self:GetDetectedObject( DetectedUnit:GetName() )
end
if DetectedObject then
-- 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
-- There was no DetectedObject, remove DetectedUnit from the Set.
self:AddChangeUnit( DetectedArea, "RU", "destroyed target" )
DetectedSet:Remove( DetectedUnitName )
-- The DetectedObject has been identified, because it does not exist ...
-- self:IdentifyDetectedObject( DetectedObject )
end
end
else
self:RemoveDetectedArea( DetectedAreaID )
self:AddChangeArea( DetectedArea, "RA" )
end
end
end
-- Now all the tests should have been build, now make some smoke and flares...
-- We iterated through the existing detection areas and:
-- - We checked which units are still detected in each detection area. Those units were flagged as Identified.
-- - We recentered the detection area to new center units where it was needed.
--
-- Now we need to loop through the unidentified detected units and see where they belong:
-- - They can be added to a new detection area and become the new center unit.
-- - They can be added to a new detection area.
for DetectedUnitName, DetectedObjectData in pairs( self.DetectedObjects ) do
local DetectedObject = self:GetDetectedObject( DetectedUnitName )
if DetectedObject then
-- 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
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
for DetectedZoneIndex = 1, #self.DetectedZones do
local DetectedUnitSet = self.DetectedSets[DetectedZoneIndex] -- Set#SET_BASE
local DetectedZone = self.DetectedZones[DetectedZoneIndex] -- Zone#ZONE_UNIT
self:T( "Detected Set #" .. DetectedZoneIndex )
DetectedUnitSet:ForEachUnit(
-- 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_AREAS.DetectedArea
local DetectedSet = DetectedArea.Set
local DetectedZone = DetectedArea.Zone
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( 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

View File

@ -0,0 +1,504 @@
--- This module contains the DETECTION_MANAGER class and derived classes.
--
-- ===
--
-- 1) @{DetectionManager#DETECTION_MANAGER} class, extends @{Base#BASE}
-- ====================================================================
-- The @{DetectionManager#DETECTION_MANAGER} class defines the core functions to report detected objects to groups.
-- Reportings can be done in several manners, and it is up to the derived classes if DETECTION_MANAGER to model the reporting behaviour.
--
-- 1.1) DETECTION_MANAGER constructor:
-- -----------------------------------
-- * @{DetectionManager#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance.
--
-- 1.2) DETECTION_MANAGER reporting:
-- ---------------------------------
-- Derived DETECTION_MANAGER classes will reports detected units using the method @{DetectionManager#DETECTION_MANAGER.ReportDetected}(). This method implements polymorphic behaviour.
--
-- The time interval in seconds of the reporting can be changed using the methods @{DetectionManager#DETECTION_MANAGER.SetReportInterval}().
-- To control how long a reporting message is displayed, use @{DetectionManager#DETECTION_MANAGER.SetReportDisplayTime}().
-- Derived classes need to implement the method @{DetectionManager#DETECTION_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report.
--
-- Reporting can be started and stopped using the methods @{DetectionManager#DETECTION_MANAGER.StartReporting}() and @{DetectionManager#DETECTION_MANAGER.StopReporting}() respectively.
-- If an ad-hoc report is requested, use the method @{DetectionManager#DETECTION_MANAGER#ReportNow}().
--
-- The default reporting interval is every 60 seconds. The reporting messages are displayed 15 seconds.
--
-- ===
--
-- 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) DETECTION_REPORTING constructor:
-- -------------------------------
-- The @{DetectionManager#DETECTION_REPORTING.New}() method creates a new DETECTION_REPORTING instance.
--
-- ===
--
-- 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
do -- DETECTION MANAGER
--- 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
self.SetGroup = SetGroup
self.Detection = Detection
self:SetReportInterval( 30 )
self:SetReportDisplayTime( 25 )
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 } )
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
end
do -- DETECTION_REPORTING
--- 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 UnitTypes = {}
for DetectedUnitID, DetectedUnitData in pairs( DetectedSet:GetSet() ) do
local DetectedUnit = DetectedUnitData -- Unit#UNIT
if DetectedUnit:IsAlive() then
local UnitType = DetectedUnit: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
--- 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
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

View File

@ -674,7 +674,7 @@ function ESCORT._HoldPosition( MenuParam )
PointFrom.alt = GroupPoint.y
PointFrom.alt_type = AI.Task.AltitudeType.BARO
local OrbitPoint = OrbitUnit:GetPointVec2()
local OrbitPoint = OrbitUnit:GetVec2()
local PointTo = {}
PointTo.x = OrbitPoint.x
PointTo.y = OrbitPoint.y
@ -867,7 +867,7 @@ function ESCORT._AttackTarget( MenuParam )
SCHEDULER:New( EscortGroup,
EscortGroup.PushTask,
{ EscortGroup:TaskCombo(
{ EscortGroup:TaskFireAtPoint( AttackUnit:GetPointVec2(), 50 )
{ EscortGroup:TaskFireAtPoint( AttackUnit:GetVec2(), 50 )
}
)
}, 10
@ -907,7 +907,7 @@ function ESCORT._AssistTarget( MenuParam )
SCHEDULER:New( EscortGroupAttack,
EscortGroupAttack.PushTask,
{ EscortGroupAttack:TaskCombo(
{ EscortGroupAttack:TaskFireAtPoint( AttackUnit:GetPointVec2(), 50 )
{ EscortGroupAttack:TaskFireAtPoint( AttackUnit:GetVec2(), 50 )
}
)
}, 10

View File

@ -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,328 +159,533 @@ 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
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:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnBirthForUnit )
return self
end
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_BIRTH )
--- 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
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
--- 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 )
--- 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
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_BIRTH )
end
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 )
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()
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnCrashForUnit )
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_CRASH )
return self
end
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_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
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 )
--- 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 )
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnDeadForUnit )
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
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()
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:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_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_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
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 )
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_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 )
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_DEAD )
return self
end
return self
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 )
--- 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
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()
do -- OnPilotDead
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_SHOT )
--- 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_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 )
--- 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_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 )
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_PILOT_DEAD )
return self
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
--- 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 )
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_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 )
self:OnEventForTemplate( EventTemplate, EventFunction, EventSelf, self.OnLandForUnit )
return self
end
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 )
--- 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
self:OnEventForUnit( EventDCSUnitName, EventFunction, EventSelf, world.event.S_EVENT_LAND )
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
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 )
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
--- 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
do -- OnEngineShutDown
--- 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 )
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 )
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
function EVENT:onEvent( Event )
self:F2( { _EVENTCODES[Event.id], Event } )
if self and self.Events and self.Events[Event.id] then
if Event.initiator and Event.initiator:getCategory() == Object.Category.UNIT then
@ -502,16 +719,21 @@ function EVENT:onEvent( Event )
end
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
self:E( { "Calling event function for class ", ClassName } )
EventData.EventFunction( EventData.EventSelf, Event )
if ClassName == EventData.EventSelf:GetClassNameAndID() then
self:T( { "Calling event function for class ", ClassName } )
EventData.EventFunction( EventData.EventSelf, Event )
end
end
end
end
else
self:E( { _EVENTCODES[Event.id], Event } )
end
end

View File

@ -1,210 +0,0 @@
--- This module contains the FAC classes.
--
-- ===
--
-- 1) @{Fac#FAC_BASE} class, extends @{Base#BASE}
-- ==============================================
-- The @{Fac#FAC_BASE} class defines the core functions to report detected objects to clients.
-- Reportings can be done in several manners, and it is up to the derived classes if FAC_BASE to model the reporting behaviour.
--
-- 1.1) FAC_BASE constructor:
-- ----------------------------
-- * @{Fac#FAC_BASE.New}(): Create a new FAC_BASE instance.
--
-- 1.2) FAC_BASE reporting:
-- ------------------------
-- Derived FAC_BASE classes will reports detected units using the method @{Fac#FAC_BASE.ReportDetected}(). This method implements polymorphic behaviour.
--
-- The time interval in seconds of the reporting can be changed using the methods @{Fac#FAC_BASE.SetReportInterval}().
-- To control how long a reporting message is displayed, use @{Fac#FAC_BASE.SetReportDisplayTime}().
-- Derived classes need to implement the method @{Fac#FAC_BASE.GetReportDisplayTime}() to use the correct display time for displayed messages during a report.
--
-- Reporting can be started and stopped using the methods @{Fac#FAC_BASE.StartReporting}() and @{Fac#FAC_BASE.StopReporting}() respectively.
-- If an ad-hoc report is requested, use the method @{Fac#FAC_BASE#ReportNow}().
--
-- The default reporting interval is every 60 seconds. The reporting messages are displayed 15 seconds.
--
-- ===
--
-- 2) @{Fac#FAC_REPORTING} class, extends @{Fac#FAC_BASE}
-- ======================================================
-- The @{Fac#FAC_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{Fac#FAC_BASE} class.
--
-- 2.1) FAC_REPORTING constructor:
-- -------------------------------
-- The @{Fac#FAC_REPORTING.New}() method creates a new FAC_REPORTING instance.
--
-- ===
--
-- @module Fac
-- @author Mechanic, Prof_Hilactic, FlightControl : Concept & Testing
-- @author FlightControl : Design & Programming
--- FAC_BASE class.
-- @type FAC_BASE
-- @field Set#SET_CLIENT ClientSet The clients 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
FAC_BASE = {
ClassName = "FAC_BASE",
ClientSet = nil,
Detection = nil,
}
--- FAC constructor.
-- @param #FAC_BASE self
-- @param Set#SET_CLIENT ClientSet
-- @param Detection#DETECTION_BASE Detection
-- @return #FAC_BASE self
function FAC_BASE:New( ClientSet, Detection )
-- Inherits from BASE
local self = BASE:Inherit( self, BASE:New() ) -- Fac#FAC_BASE
self.ClientSet = ClientSet
self.Detection = Detection
self:SetReportInterval( 60 )
self:SetReportDisplayTime( 15 )
return self
end
--- Set the reporting time interval.
-- @param #FAC_BASE self
-- @param #number ReportInterval The interval in seconds when a report needs to be done.
-- @return #FAC_BASE self
function FAC_BASE:SetReportInterval( ReportInterval )
self:F2()
self._ReportInterval = ReportInterval
end
--- Set the reporting message display time.
-- @param #FAC_BASE self
-- @param #number ReportDisplayTime The display time in seconds when a report needs to be done.
-- @return #FAC_BASE self
function FAC_BASE:SetReportDisplayTime( ReportDisplayTime )
self:F2()
self._ReportDisplayTime = ReportDisplayTime
end
--- Get the reporting message display time.
-- @param #FAC_BASE self
-- @return #number ReportDisplayTime The display time in seconds when a report needs to be done.
function FAC_BASE:GetReportDisplayTime()
self:F2()
return self._ReportDisplayTime
end
--- Reports the detected items to the @{Set#SET_CLIENT}.
-- @param #FAC_BASE self
-- @param Set#SET_BASE DetectedSets The detected Sets created by the @{Detection#DETECTION_BASE} object.
-- @return #FAC_BASE self
function FAC_BASE:ReportDetected( DetectedSets )
self:F2()
end
--- Schedule the FAC reporting.
-- @param #FAC_BASE 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 #FAC_BASE self
function FAC_BASE:Schedule( DelayTime, ReportInterval )
self:F2()
self._ScheduleDelayTime = DelayTime
self:SetReportInterval( ReportInterval )
self.FacScheduler = SCHEDULER:New(self, self._FacScheduler, { self, "Fac" }, self._ScheduleDelayTime, self._ReportInterval )
return self
end
--- Report the detected @{Unit#UNIT}s detected within the @{DetectION#DETECTION_BASE} object to the @{Set#SET_CLIENT}s.
-- @param #FAC_BASE self
function FAC_BASE:_FacScheduler( SchedulerName )
self:F2( { SchedulerName } )
self.ClientSet:ForEachClient(
--- @param Client#CLIENT Client
function( Client )
if Client:IsAlive() then
local DetectedSets = self.Detection:GetDetectedSets()
return self:ReportDetected( Client, DetectedSets )
end
end
)
return true
end
-- FAC_REPORTING
--- FAC_REPORTING class.
-- @type FAC_REPORTING
-- @field Set#SET_CLIENT ClientSet The clients 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 #FAC_BASE
FAC_REPORTING = {
ClassName = "FAC_REPORTING",
}
--- FAC_REPORTING constructor.
-- @param #FAC_REPORTING self
-- @param Set#SET_CLIENT ClientSet
-- @param Detection#DETECTION_BASE Detection
-- @return #FAC_REPORTING self
function FAC_REPORTING:New( ClientSet, Detection )
-- Inherits from FAC_BASE
local self = BASE:Inherit( self, FAC_BASE:New( ClientSet, Detection ) ) -- #FAC_REPORTING
self:Schedule( 5, 60 )
return self
end
--- Reports the detected items to the @{Set#SET_CLIENT}.
-- @param #FAC_REPORTING self
-- @param Client#CLIENT Client The @{Client} object to where the report needs to go.
-- @param Set#SET_BASE DetectedSets The detected Sets 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:ReportDetected( Client, DetectedSets )
self:F2( Client )
local DetectedMsg = {}
for DetectedUnitSetID, DetectedUnitSet in pairs( DetectedSets ) do
local UnitSet = DetectedUnitSet -- Set#SET_UNIT
local MT = {} -- Message Text
local UnitTypes = {}
for DetectedUnitID, DetectedUnitData in pairs( UnitSet: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
local MessageText = table.concat( MT, ", " )
DetectedMsg[#DetectedMsg+1] = " - Group #" .. DetectedUnitSetID .. ": " .. MessageText
end
local FACGroup = self.Detection:GetFACGroup()
FACGroup:MessageToClient( "Reporting detected target groups:\n" .. table.concat( DetectedMsg, "\n" ), self:GetReportDisplayTime(), Client )
return true
end

View File

@ -476,12 +476,12 @@ end
--- Returns the current point (Vec2 vector) of the first DCS Unit in the DCS Group.
-- @param #GROUP self
-- @return DCSTypes#Vec2 Current Vec2 point of the first DCS Unit of the DCS Group.
function GROUP:GetPointVec2()
function GROUP:GetVec2()
self:F2( self.GroupName )
local UnitPoint = self:GetUnit(1)
UnitPoint:GetPointVec2()
local GroupPointVec2 = UnitPoint:GetPointVec2()
UnitPoint:GetVec2()
local GroupPointVec2 = UnitPoint:GetVec2()
self:T3( GroupPointVec2 )
return GroupPointVec2
end
@ -873,7 +873,7 @@ end
-- @param #string Message The message text
-- @param DCSTypes#Duration Duration The duration of the message.
-- @return Message#MESSAGE
function GROUP:Message( Message, Duration )
function GROUP:GetMessage( Message, Duration )
self:F2( { Message, Duration } )
local DCSGroup = self:GetDCSObject()
@ -894,7 +894,7 @@ function GROUP:MessageToAll( Message, Duration )
local DCSGroup = self:GetDCSObject()
if DCSGroup then
self:Message( Message, Duration ):ToAll()
self:GetMessage( Message, Duration ):ToAll()
end
return nil
@ -910,7 +910,7 @@ function GROUP:MessageToRed( Message, Duration )
local DCSGroup = self:GetDCSObject()
if DCSGroup then
self:Message( Message, Duration ):ToRed()
self:GetMessage( Message, Duration ):ToRed()
end
return nil
@ -926,7 +926,7 @@ function GROUP:MessageToBlue( Message, Duration )
local DCSGroup = self:GetDCSObject()
if DCSGroup then
self:Message( Message, Duration ):ToBlue()
self:GetMessage( Message, Duration ):ToBlue()
end
return nil
@ -943,7 +943,42 @@ function GROUP:MessageToClient( Message, Duration, Client )
local DCSGroup = self:GetDCSObject()
if DCSGroup then
self:Message( Message, Duration ):ToClient( Client )
self:GetMessage( Message, Duration ):ToClient( Client )
end
return nil
end
--- Send a message to a @{Group}.
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
-- @param #GROUP self
-- @param #string Message The message text
-- @param DCSTypes#Duration Duration The duration of the message.
-- @param Group#GROUP MessageGroup The GROUP object receiving the message.
function GROUP:MessageToGroup( Message, Duration, MsgGroup )
self:F2( { Message, Duration } )
local DCSGroup = self:GetDCSObject()
if DCSGroup then
if DCSGroup:isExist() then
self:GetMessage( Message, Duration ):ToGroup( MsgGroup )
end
end
return nil
end
--- Send a message to the players in the @{Group}.
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
-- @param #GROUP self
-- @param #string Message The message text
-- @param DCSTypes#Duration Duration The duration of the message.
function GROUP:Message( Message, Duration )
self:F2( { Message, Duration } )
local DCSGroup = self:GetDCSObject()
if DCSGroup then
self:GetMessage( Message, Duration ):ToGroup( self )
end
return nil

View File

@ -70,180 +70,365 @@ function SUBMENU:New( MenuText, ParentMenu )
return Child
end
-- This local variable is used to cache the menus registered under clients.
-- Menus don't dissapear when clients are destroyed and restarted.
-- So every menu for a client created must be tracked so that program logic accidentally does not create
-- the same menus twice during initialization logic.
-- These menu classes are handling this logic with this variable.
local _MENUCLIENTS = {}
do
--- The MENU_CLIENT class
-- @type MENU_CLIENT
-- @extends Menu#MENU
MENU_CLIENT = {
ClassName = "MENU_CLIENT"
}
--- Creates a new menu item for a group
-- @param self
-- @param Client#CLIENT MenuClient The Client owning the menu.
-- @param #string MenuText The text for the menu.
-- @param #table ParentMenu The parent menu.
-- @return #MENU_CLIENT self
function MENU_CLIENT:New( MenuClient, MenuText, ParentMenu )
-- Arrange meta tables
local MenuParentPath = {}
if ParentMenu ~= nil then
MenuParentPath = ParentMenu.MenuPath
end
local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) )
self:F( { MenuClient, MenuText, ParentMenu } )
self.MenuClient = MenuClient
self.MenuClientGroupID = MenuClient:GetClientGroupID()
self.MenuParentPath = MenuParentPath
self.MenuText = MenuText
self.ParentMenu = ParentMenu
-- This local variable is used to cache the menus registered under clients.
-- Menus don't dissapear when clients are destroyed and restarted.
-- So every menu for a client created must be tracked so that program logic accidentally does not create
-- the same menus twice during initialization logic.
-- These menu classes are handling this logic with this variable.
local _MENUCLIENTS = {}
self.Menus = {}
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
--- The MENU_CLIENT class
-- @type MENU_CLIENT
-- @extends Menu#MENU
MENU_CLIENT = {
ClassName = "MENU_CLIENT"
}
--- Creates a new menu item for a group
-- @param self
-- @param Client#CLIENT MenuClient The Client owning the menu.
-- @param #string MenuText The text for the menu.
-- @param #table ParentMenu The parent menu.
-- @return #MENU_CLIENT self
function MENU_CLIENT:New( MenuClient, MenuText, ParentMenu )
-- Arrange meta tables
local MenuParentPath = {}
if ParentMenu ~= nil then
MenuParentPath = ParentMenu.MenuPath
end
local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) )
self:F( { MenuClient, MenuText, ParentMenu } )
self.MenuClient = MenuClient
self.MenuClientGroupID = MenuClient:GetClientGroupID()
self.MenuParentPath = MenuParentPath
self.MenuText = MenuText
self.ParentMenu = ParentMenu
self.Menus = {}
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
self:T( { MenuClient:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText } )
local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText
if MenuPath[MenuPathID] then
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] )
end
self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath )
MenuPath[MenuPathID] = self.MenuPath
self:T( { MenuClient:GetClientGroupName(), self.MenuPath } )
if ParentMenu and ParentMenu.Menus then
ParentMenu.Menus[self.MenuPath] = self
end
return self
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
self:T( { MenuClient:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText } )
local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText
if MenuPath[MenuPathID] then
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] )
--- Removes the sub menus recursively of this MENU_CLIENT.
-- @param #MENU_CLIENT self
-- @return #MENU_CLIENT self
function MENU_CLIENT:RemoveSubMenus()
self:F( self.MenuPath )
for MenuID, Menu in pairs( self.Menus ) do
Menu:Remove()
end
end
--- Removes the sub menus recursively of this MENU_CLIENT.
-- @param #MENU_CLIENT self
-- @return #MENU_CLIENT self
function MENU_CLIENT:Remove()
self:F( self.MenuPath )
self:RemoveSubMenus()
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
end
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath )
self.ParentMenu.Menus[self.MenuPath] = nil
return nil
end
--- The MENU_CLIENT_COMMAND class
-- @type MENU_CLIENT_COMMAND
-- @extends Menu#MENU
MENU_CLIENT_COMMAND = {
ClassName = "MENU_CLIENT_COMMAND"
}
--- Creates a new radio command item for a group
-- @param self
-- @param Client#CLIENT MenuClient The Client owning the menu.
-- @param MenuText The text for the menu.
-- @param ParentMenu The parent menu.
-- @param CommandMenuFunction A function that is called when the menu key is pressed.
-- @param CommandMenuArgument An argument for the function.
-- @return Menu#MENU_CLIENT_COMMAND self
function MENU_CLIENT_COMMAND:New( MenuClient, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument )
-- Arrange meta tables
local MenuParentPath = {}
if ParentMenu ~= nil then
MenuParentPath = ParentMenu.MenuPath
end
local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) )
self.MenuClient = MenuClient
self.MenuClientGroupID = MenuClient:GetClientGroupID()
self.MenuParentPath = MenuParentPath
self.MenuText = MenuText
self.ParentMenu = ParentMenu
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
self:T( { MenuClient:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText, CommandMenuFunction, CommandMenuArgument } )
local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText
if MenuPath[MenuPathID] then
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] )
end
self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument )
MenuPath[MenuPathID] = self.MenuPath
self.CommandMenuFunction = CommandMenuFunction
self.CommandMenuArgument = CommandMenuArgument
ParentMenu.Menus[self.MenuPath] = self
return self
end
function MENU_CLIENT_COMMAND:Remove()
self:F( self.MenuPath )
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
end
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath )
self.ParentMenu.Menus[self.MenuPath] = nil
return nil
end
end
self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath )
MenuPath[MenuPathID] = self.MenuPath
--- MENU_GROUP
self:T( { MenuClient:GetClientGroupName(), self.MenuPath } )
do
-- This local variable is used to cache the menus registered under clients.
-- Menus don't dissapear when clients are destroyed and restarted.
-- So every menu for a client created must be tracked so that program logic accidentally does not create
-- the same menus twice during initialization logic.
-- These menu classes are handling this logic with this variable.
local _MENUGROUPS = {}
if ParentMenu and ParentMenu.Menus then
--- The MENU_GROUP class
-- @type MENU_GROUP
-- @extends Menu#MENU
MENU_GROUP = {
ClassName = "MENU_GROUP"
}
--- Creates a new menu item for a group
-- @param self
-- @param Group#GROUP MenuGroup The Group owning the menu.
-- @param #string MenuText The text for the menu.
-- @param #table ParentMenu The parent menu.
-- @return #MENU_GROUP self
function MENU_GROUP:New( MenuGroup, MenuText, ParentMenu )
-- Arrange meta tables
local MenuParentPath = {}
if ParentMenu ~= nil then
MenuParentPath = ParentMenu.MenuPath
end
local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) )
self:F( { MenuGroup, MenuText, ParentMenu } )
self.MenuGroup = MenuGroup
self.MenuGroupID = MenuGroup:GetID()
self.MenuParentPath = MenuParentPath
self.MenuText = MenuText
self.ParentMenu = ParentMenu
self.Menus = {}
if not _MENUGROUPS[self.MenuGroupID] then
_MENUGROUPS[self.MenuGroupID] = {}
end
local MenuPath = _MENUGROUPS[self.MenuGroupID]
self:T( { MenuGroup:GetName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText } )
local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText
if MenuPath[MenuPathID] then
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
self:T( { self.MenuGroupID, self.MenuPath } )
if ParentMenu and ParentMenu.Menus then
ParentMenu.Menus[self.MenuPath] = self
end
return self
end
--- Removes the sub menus recursively of this MENU_GROUP.
-- @param #MENU_GROUP self
-- @return #MENU_GROUP self
function MENU_GROUP:RemoveSubMenus()
self:F( self.MenuPath )
for MenuID, Menu in pairs( self.Menus ) do
Menu:Remove()
end
end
--- Removes the sub menus recursively of this MENU_GROUP.
-- @param #MENU_GROUP self
-- @return #MENU_GROUP self
function MENU_GROUP:Remove()
self:F( self.MenuPath )
self:RemoveSubMenus()
if not _MENUGROUPS[self.MenuGroupID] then
_MENUGROUPS[self.MenuGroupID] = {}
end
local MenuPath = _MENUGROUPS[self.MenuGroupID]
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
end
missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath )
if self.ParentMenu then
self.ParentMenu.Menus[self.MenuPath] = nil
end
return nil
end
--- The MENU_GROUP_COMMAND class
-- @type MENU_GROUP_COMMAND
-- @extends Menu#MENU
MENU_GROUP_COMMAND = {
ClassName = "MENU_GROUP_COMMAND"
}
--- Creates a new radio command item for a group
-- @param #MENU_GROUP_COMMAND self
-- @param Group#GROUP MenuGroup The Group owning the menu.
-- @param MenuText The text for the menu.
-- @param ParentMenu The parent menu.
-- @param CommandMenuFunction A function that is called when the menu key is pressed.
-- @param CommandMenuArgument An argument for the function.
-- @return Menu#MENU_GROUP_COMMAND self
function MENU_GROUP_COMMAND:New( MenuGroup, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument )
-- Arrange meta tables
local MenuParentPath = {}
if ParentMenu ~= nil then
MenuParentPath = ParentMenu.MenuPath
end
local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) )
self.MenuGroup = MenuGroup
self.MenuGroupID = MenuGroup:GetID()
self.MenuParentPath = MenuParentPath
self.MenuText = MenuText
self.ParentMenu = ParentMenu
if not _MENUGROUPS[self.MenuGroupID] then
_MENUGROUPS[self.MenuGroupID] = {}
end
local MenuPath = _MENUGROUPS[self.MenuGroupID]
self:T( { MenuGroup:GetName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText, CommandMenuFunction, CommandMenuArgument } )
local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText
if MenuPath[MenuPathID] then
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
self.CommandMenuFunction = CommandMenuFunction
self.CommandMenuArgument = CommandMenuArgument
ParentMenu.Menus[self.MenuPath] = self
return self
end
return self
end
function MENU_GROUP_COMMAND:Remove()
self:F( self.MenuPath )
if not _MENUGROUPS[self.MenuGroupID] then
_MENUGROUPS[self.MenuGroupID] = {}
end
local MenuPath = _MENUGROUPS[self.MenuGroupID]
--- Removes the sub menus recursively of this MENU_CLIENT.
-- @param #MENU_CLIENT self
-- @return #MENU_CLIENT self
function MENU_CLIENT:RemoveSubMenus()
self:F( self.MenuPath )
for MenuID, Menu in pairs( self.Menus ) do
Menu:Remove()
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
end
missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath )
self.ParentMenu.Menus[self.MenuPath] = nil
return nil
end
end
--- Removes the sub menus recursively of this MENU_CLIENT.
-- @param #MENU_CLIENT self
-- @return #MENU_CLIENT self
function MENU_CLIENT:Remove()
self:F( self.MenuPath )
self:RemoveSubMenus()
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
end
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath )
self.ParentMenu.Menus[self.MenuPath] = nil
return nil
end
--- The MENU_CLIENT_COMMAND class
-- @type MENU_CLIENT_COMMAND
-- @extends Menu#MENU
MENU_CLIENT_COMMAND = {
ClassName = "MENU_CLIENT_COMMAND"
}
--- Creates a new radio command item for a group
-- @param self
-- @param Client#CLIENT MenuClient The Client owning the menu.
-- @param MenuText The text for the menu.
-- @param ParentMenu The parent menu.
-- @param CommandMenuFunction A function that is called when the menu key is pressed.
-- @param CommandMenuArgument An argument for the function.
-- @return Menu#MENU_CLIENT_COMMAND self
function MENU_CLIENT_COMMAND:New( MenuClient, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument )
-- Arrange meta tables
local MenuParentPath = {}
if ParentMenu ~= nil then
MenuParentPath = ParentMenu.MenuPath
end
local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) )
self.MenuClient = MenuClient
self.MenuClientGroupID = MenuClient:GetClientGroupID()
self.MenuParentPath = MenuParentPath
self.MenuText = MenuText
self.ParentMenu = ParentMenu
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
self:T( { MenuClient:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText, CommandMenuFunction, CommandMenuArgument } )
local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText
if MenuPath[MenuPathID] then
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] )
end
self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument )
MenuPath[MenuPathID] = self.MenuPath
self.CommandMenuFunction = CommandMenuFunction
self.CommandMenuArgument = CommandMenuArgument
ParentMenu.Menus[self.MenuPath] = self
return self
end
function MENU_CLIENT_COMMAND:Remove()
self:F( self.MenuPath )
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
end
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath )
self.ParentMenu.Menus[self.MenuPath] = nil
return nil
end
--- The MENU_COALITION class
-- @type MENU_COALITION
-- @extends Menu#MENU
@ -253,11 +438,11 @@ MENU_COALITION = {
--- Creates a new coalition menu item
-- @param #MENU_COALITION self
-- @param DCSCoalition#coalition.side MenuCoalition The coalition owning the menu.
-- @param DCSCoalition#coalition.side Coalition The coalition owning the menu.
-- @param #string MenuText The text for the menu.
-- @param #table ParentMenu The parent menu.
-- @return #MENU_COALITION self
function MENU_COALITION:New( MenuCoalition, MenuText, ParentMenu )
function MENU_COALITION:New( Coalition, MenuText, ParentMenu )
-- Arrange meta tables
local MenuParentPath = {}
@ -266,9 +451,9 @@ function MENU_COALITION:New( MenuCoalition, MenuText, ParentMenu )
end
local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) )
self:F( { MenuCoalition, MenuText, ParentMenu } )
self:F( { Coalition, MenuText, ParentMenu } )
self.MenuCoalition = MenuCoalition
self.Coalition = Coalition
self.MenuParentPath = MenuParentPath
self.MenuText = MenuText
self.ParentMenu = ParentMenu
@ -277,7 +462,7 @@ function MENU_COALITION:New( MenuCoalition, MenuText, ParentMenu )
self:T( { MenuParentPath, MenuText } )
self.MenuPath = missionCommands.addSubMenuForCoalition( self.MenuCoalition, MenuText, MenuParentPath )
self.MenuPath = missionCommands.addSubMenuForCoalition( self.Coalition, MenuText, MenuParentPath )
self:T( { self.MenuPath } )

View File

@ -59,7 +59,7 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory )
self.MessageCategory = ""
end
self.MessageDuration = MessageDuration
self.MessageDuration = MessageDuration or 5
self.MessageTime = timer.getTime()
self.MessageText = MessageText
@ -102,6 +102,21 @@ function MESSAGE:ToClient( Client )
return self
end
--- Sends a MESSAGE to a Group.
-- @param #MESSAGE self
-- @param Group#GROUP Group is the Group.
-- @return #MESSAGE
function MESSAGE:ToGroup( Group )
self:F( Group.GroupName )
if Group then
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
end
return self
end
--- Sends a MESSAGE to the Blue coalition.
-- @param #MESSAGE self
-- @return #MESSAGE

View File

@ -6,13 +6,17 @@
-- @type MISSION
-- @extends Base#BASE
-- @field #MISSION.Clients _Clients
-- @field Menu#MENU_COALITION MissionMenu
-- @field #string MissionBriefing
MISSION = {
ClassName = "MISSION",
Name = "",
MissionStatus = "PENDING",
_Clients = {},
_Tasks = {},
Tasks = {},
TaskMenus = {},
TaskCategoryMenus = {},
TaskTypeMenus = {},
_ActiveTasks = {},
GoalFunction = nil,
MissionReportTrigger = 0,
@ -33,49 +37,177 @@ MISSION = {
function MISSION:Meta()
local self = BASE:Inherit( self, BASE:New() )
self:F()
return self
end
--- This is the main MISSION declaration method. Each Mission is like the master or a Mission orchestration between, Clients, Tasks, Stages etc.
-- @param string MissionName is the name of the mission. This name will be used to reference the status of each mission by the players.
-- @param string MissionPriority is a string indicating the "priority" of the Mission. f.e. "Primary", "Secondary" or "First", "Second". It is free format and up to the Mission designer to choose. There are no rules behind this field.
-- @param string MissionBriefing is a string indicating the mission briefing to be shown when a player joins a @{CLIENT}.
-- @param string MissionCoalition is a string indicating the coalition or party to which this mission belongs to. It is free format and can be chosen freely by the mission designer. Note that this field is not to be confused with the coalition concept of the ME. Examples of a Mission Coalition could be "NATO", "CCCP", "Intruders", "Terrorists"...
-- @return MISSION
-- @usage
-- -- Declare a few missions.
-- local Mission = MISSIONSCHEDULER.AddMission( 'Russia Transport Troops SA-6', 'Operational', 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', 'Russia' )
-- local Mission = MISSIONSCHEDULER.AddMission( 'Patriots', 'Primary', 'Our intelligence reports that 3 Patriot SAM defense batteries are located near Ruisi, Kvarhiti and Gori.', 'Russia' )
-- local Mission = MISSIONSCHEDULER.AddMission( 'Package Delivery', 'Operational', 'In order to be in full control of the situation, we need you to deliver a very important package at a secret location. Fly undetected through the NATO defenses and deliver the secret package. The secret agent is located at waypoint 4.', 'Russia' )
-- local Mission = MISSIONSCHEDULER.AddMission( 'Rescue General', 'Tactical', 'Our intelligence has received a remote signal behind Gori. We believe it is a very important Russian General that was captured by Georgia. Go out there and rescue him! Ensure you stay out of the battle zone, keep south. Waypoint 4 is the location of our Russian General.', 'Russia' )
-- local Mission = MISSIONSCHEDULER.AddMission( 'NATO Transport Troops', 'Operational', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.', 'NATO' )
-- local Mission = MISSIONSCHEDULER.AddMission( 'SA-6 SAMs', 'Primary', 'Our intelligence reports that 3 SA-6 SAM defense batteries are located near Didmukha, Khetagurov and Berula. Eliminate the Russian SAMs.', 'NATO' )
-- local Mission = MISSIONSCHEDULER.AddMission( 'NATO Sling Load', 'Operational', 'Fly to the cargo pickup zone at Dzegvi or Kaspi, and sling the cargo to Soganlug airbase.', 'NATO' )
-- local Mission = MISSIONSCHEDULER.AddMission( 'Rescue secret agent', 'Tactical', 'In order to be in full control of the situation, we need you to rescue a secret agent from the woods behind enemy lines. Avoid the Russian defenses and rescue the agent. Keep south until Khasuri, and keep your eyes open for any SAM presence. The agent is located at waypoint 4 on your kneeboard.', 'NATO' )
-- @param #MISSION self
-- @param #string MissionName is the name of the mission. This name will be used to reference the status of each mission by the players.
-- @param #string MissionPriority is a string indicating the "priority" of the Mission. f.e. "Primary", "Secondary" or "First", "Second". It is free format and up to the Mission designer to choose. There are no rules behind this field.
-- @param #string MissionBriefing is a string indicating the mission briefing to be shown when a player joins a @{CLIENT}.
-- @param DCSCoalitionObject#coalition MissionCoalition is a string indicating the coalition or party to which this mission belongs to. It is free format and can be chosen freely by the mission designer. Note that this field is not to be confused with the coalition concept of the ME. Examples of a Mission Coalition could be "NATO", "CCCP", "Intruders", "Terrorists"...
-- @return #MISSION self
function MISSION:New( MissionName, MissionPriority, MissionBriefing, MissionCoalition )
self = MISSION:Meta()
self:T({ MissionName, MissionPriority, MissionBriefing, MissionCoalition })
self:T( { MissionName, MissionPriority, MissionBriefing, MissionCoalition } )
local Valid = true
Valid = routines.ValidateString( MissionName, "MissionName", Valid )
Valid = routines.ValidateString( MissionPriority, "MissionPriority", Valid )
Valid = routines.ValidateString( MissionBriefing, "MissionBriefing", Valid )
Valid = routines.ValidateString( MissionCoalition, "MissionCoalition", Valid )
if Valid then
self.Name = MissionName
self.MissionPriority = MissionPriority
self.MissionBriefing = MissionBriefing
self.MissionCoalition = MissionCoalition
end
self.Name = MissionName
self.MissionPriority = MissionPriority
self.MissionBriefing = MissionBriefing
self.MissionCoalition = MissionCoalition
return self
end
--- Gets the mission name.
-- @param #MISSION self
-- @return #MISSION self
function MISSION:GetName()
return self.Name
end
--- Add a scoring to the mission.
-- @param #MISSION self
-- @return #MISSION self
function MISSION:AddScoring( Scoring )
self.Scoring = Scoring
return self
end
--- Get the scoring object of a mission.
-- @param #MISSION self
-- @return #SCORING Scoring
function MISSION:GetScoring()
return self.Scoring
end
--- Sets the Planned Task menu.
-- @param #MISSION self
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( TaskGroup )
local TaskGroupName = TaskGroup:GetName()
return self.MenuMission[TaskGroupName]
end
--- Clears the mission menu for the coalition.
-- @param #MISSION self
-- @return #MISSION self
function MISSION:ClearMissionMenu()
self.MissionMenu:Remove()
self.MissionMenu = nil
end
--- 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 } )
return self.Tasks[TaskName]
end
--- Register 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 Task#TASK_BASE The task added.
function MISSION:AddTask( Task )
local TaskName = Task:GetTaskName()
self:F( TaskName )
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
self.Tasks[TaskName] = Task
return Task
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
--- Returns if a Mission has completed.
-- @return bool
function MISSION:IsCompleted()
@ -264,66 +396,6 @@ function MISSION:FindClient( ClientName )
end
--- Register 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 Goal. The MISSION will not be completed until all Goals are reached.
-- @param TASK Task is the @{TASK} object. The object must have been instantiated with @{TASK:New} or any of its inherited @{TASK}s.
-- @param number TaskNumber is the sequence number of the TASK within the MISSION. This number does have to be chronological.
-- @return TASK
-- @usage
-- -- Define a few tasks for the Mission.
-- PickupZones = { "NATO Gold Pickup Zone", "NATO Titan Pickup Zone" }
-- PickupSignalUnits = { "NATO Gold Coordination Center", "NATO Titan Coordination Center" }
--
-- -- Assign the Pickup Task
-- local PickupTask = PICKUPTASK:New( PickupZones, CARGO_TYPE.ENGINEERS, CLIENT.ONBOARDSIDE.LEFT )
-- PickupTask:AddSmokeBlue( PickupSignalUnits )
-- PickupTask:SetGoalTotal( 3 )
-- Mission:AddTask( PickupTask, 1 )
--
-- -- Assign the Deploy Task
-- local PatriotActivationZones = { "US Patriot Battery 1 Activation", "US Patriot Battery 2 Activation", "US Patriot Battery 3 Activation" }
-- local PatriotActivationZonesSmokeUnits = { "US SAM Patriot - Battery 1 Control", "US SAM Patriot - Battery 2 Control", "US SAM Patriot - Battery 3 Control" }
-- local DeployTask = DEPLOYTASK:New( PatriotActivationZones, CARGO_TYPE.ENGINEERS )
-- --DeployTask:SetCargoTargetZoneName( 'US Troops Attack ' .. math.random(2) )
-- DeployTask:AddSmokeBlue( PatriotActivationZonesSmokeUnits )
-- DeployTask:SetGoalTotal( 3 )
-- DeployTask:SetGoalTotal( 3, "Patriots activated" )
-- Mission:AddTask( DeployTask, 2 )
function MISSION:AddTask( Task, TaskNumber )
self:F()
self._Tasks[TaskNumber] = Task
self._Tasks[TaskNumber]:EnableEvents()
self._Tasks[TaskNumber].ID = TaskNumber
return Task
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

View File

@ -1,6 +1,7 @@
--- The main include file for the MOOSE system.
Include.File( "Routines" )
Include.File( "Utils" )
Include.File( "Base" )
Include.File( "Object" )
Include.File( "Identifiable" )
@ -43,13 +44,27 @@ Include.File( "MissileTrainer" )
Include.File( "PatrolZone" )
Include.File( "AIBalancer" )
Include.File( "AirbasePolice" )
Include.File( "Detection" )
Include.File( "FAC" )
Include.File( "DetectionManager" )
Include.File( "StateMachine" )
Include.File( "Process" )
Include.File( "Process_Assign" )
Include.File( "Process_Route" )
Include.File( "Process_Smoke" )
Include.File( "Process_Destroy" )
Include.File( "Task" )
Include.File( "Task_SEAD" )
Include.File( "Task_CAS" )
Include.File( "Task_BAI" )
-- The order of the declarations is important here. Don't touch it.
--- Declare the event dispatcher based on the EVENT class
_EVENTDISPATCHER = EVENT:New() -- #EVENT
_EVENTDISPATCHER = EVENT:New() -- Event#EVENT
--- Declare the main database object, which is used internally by the MOOSE classes.
_DATABASE = DATABASE:New() -- Database#DATABASE

View File

@ -138,7 +138,7 @@ function PATROLZONE:NewPatrolRoute()
-- If not, make a waypoint within the to that the PatrolGroup will fly at maximum speed to that point.
-- --- Calculate the current route point.
-- local CurrentVec2 = self.PatrolGroup:GetPointVec2()
-- local CurrentVec2 = self.PatrolGroup:GetVec2()
-- local CurrentAltitude = self.PatrolGroup:GetUnit(1):GetAltitude()
-- local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
-- local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(

View File

@ -4,6 +4,9 @@
-- ===============================================
-- The @{Point#POINT_VEC3} class defines a 3D point in the simulator.
--
-- **Important Note:** Most of the functions in this section were taken from MIST, and reworked to OO concepts.
-- In order to keep the credibility of the the author, I want to emphasize that the of the MIST framework was created by Grimes, who you can find on the Eagle Dynamics Forums.
--
-- 1.1) POINT_VEC3 constructor
-- ---------------------------
--
@ -28,6 +31,7 @@
--- The POINT_VEC3 class
-- @type POINT_VEC3
-- @extends Base#BASE
-- @field DCSTypes#Vec3 PointVec3
-- @field #POINT_VEC3.SmokeColor SmokeColor
-- @field #POINT_VEC3.FlareColor FlareColor
-- @field #POINT_VEC3.RoutePointAltType RoutePointAltType
@ -48,6 +52,7 @@ POINT_VEC3 = {
White = trigger.flareColor.White,
Yellow = trigger.flareColor.Yellow
},
Metric = true,
RoutePointAltType = {
BARO = "BARO",
},
@ -114,6 +119,160 @@ function POINT_VEC3:New( x, y, z )
end
--- Return the coordinates of the POINT_VEC3 in Vec3 format.
-- @param #POINT_VEC3 self
-- @return DCSTypes#Vec3 The Vec3 coodinate.
function POINT_VEC3:GetVec3()
return self.PointVec3
end
--- Return the x coordinate of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @return #number The x coodinate.
function POINT_VEC3:GetX()
return self.PointVec3.x
end
--- Return the y coordinate of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @return #number The y coodinate.
function POINT_VEC3:GetY()
return self.PointVec3.y
end
--- Return the z coordinate of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @return #number The z coodinate.
function POINT_VEC3:GetZ()
return self.PointVec3.z
end
--- Return a direction vector Vec3 from POINT_VEC3 to the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @param #POINT_VEC3 TargetPointVec3 The target PointVec3.
-- @return DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format.
function POINT_VEC3:GetDirectionVec3( TargetPointVec3 )
return { x = TargetPointVec3:GetX() - self:GetX(), y = TargetPointVec3:GetY() - self:GetY(), z = TargetPointVec3:GetZ() - self:GetZ() }
end
--- Get a correction in radians of the real magnetic north of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @return #number CorrectionRadians The correction in radians.
function POINT_VEC3:GetNorthCorrectionRadians()
local TargetVec3 = self:GetVec3()
local lat, lon = coord.LOtoLL(TargetVec3)
local north_posit = coord.LLtoLO(lat + 1, lon)
return math.atan2( north_posit.z - TargetVec3.z, north_posit.x - TargetVec3.x )
end
--- Return a direction in radians from the POINT_VEC3 using a direction vector in Vec3 format.
-- @param #POINT_VEC3 self
-- @param DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format.
-- @return #number DirectionRadians The direction in radians.
function POINT_VEC3:GetDirectionRadians( DirectionVec3 )
local DirectionRadians = math.atan2( DirectionVec3.z, DirectionVec3.x )
--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
return DirectionRadians
end
--- Return the 2D distance in meters between the target POINT_VEC3 and the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @param #POINT_VEC3 TargetPointVec3 The target PointVec3.
-- @return DCSTypes#Distance Distance The distance in meters.
function POINT_VEC3:Get2DDistance( TargetPointVec3 )
local TargetVec3 = TargetPointVec3:GetVec3()
local SourceVec3 = self:GetVec3()
return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5
end
--- Return the 3D distance in meters between the target POINT_VEC3 and the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @param #POINT_VEC3 TargetPointVec3 The target PointVec3.
-- @return DCSTypes#Distance Distance The distance in meters.
function POINT_VEC3:Get3DDistance( TargetPointVec3 )
local TargetVec3 = TargetPointVec3:GetVec3()
local SourceVec3 = self:GetVec3()
return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.y - SourceVec3.y ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5
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:ToStringBR( AngleRadians, Distance )
AngleRadians = UTILS.Round( UTILS.ToDegree( AngleRadians ), 0 )
if self:IsMetric() then
Distance = UTILS.Round( Distance / 1000, 2 )
else
Distance = UTILS.Round( UTILS.MetersToNM( Distance ), 2 )
end
local s = string.format( '%03d', AngleRadians ) .. ' for ' .. Distance
s = s .. self:GetAltitudeText() -- When the POINT is a VEC2, there will be no altitude shown.
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.
function POINT_VEC3:GetAltitudeText()
if self:IsMetric() then
return ' at ' .. UTILS.Round( self:GetY(), 0 )
else
return ' at ' .. UTILS.Round( UTILS.MetersToFeet( self:GetY() ), 0 )
end
end
--- Return a BR string from a POINT_VEC3 to the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @param #POINT_VEC3 TargetPointVec3 The target PointVec3.
-- @return #string The BR text.
function POINT_VEC3:GetBRText( TargetPointVec3 )
local DirectionVec3 = self:GetDirectionVec3( TargetPointVec3 )
local AngleRadians = self:GetDirectionRadians( DirectionVec3 )
local Distance = self:Get2DDistance( TargetPointVec3 )
return self:ToStringBR( AngleRadians, Distance )
end
--- Sets the POINT_VEC3 metric or NM.
-- @param #POINT_VEC3 self
-- @param #boolean Metric true means metric, false means NM.
function POINT_VEC3:SetMetric( Metric )
self.Metric = Metric
end
--- Gets if the POINT_VEC3 is metric or NM.
-- @param #POINT_VEC3 self
-- @return #boolean Metric true means metric, false means NM.
function POINT_VEC3:IsMetric()
return self.Metric
end
--- Build an air type route point.
-- @param #POINT_VEC3 self
-- @param #POINT_VEC3.RoutePointAltType AltType The altitude type.
@ -299,3 +458,10 @@ function POINT_VEC2:DistanceFromVec2( Vec2Reference )
end
--- Return no text for the altitude of the POINT_VEC2.
-- @param #POINT_VEC2 self
-- @return #string Empty string.
function POINT_VEC2:GetAltitudeText()
return ''
end

View File

@ -71,7 +71,7 @@ end
-- @param Positionable#POSITIONABLE self
-- @return DCSTypes#Vec2 The 2D point vector of the DCS Positionable.
-- @return #nil The DCS Positionable is not existing or alive.
function POSITIONABLE:GetPointVec2()
function POSITIONABLE:GetVec2()
self:F2( self.PositionableName )
local DCSPositionable = self:GetDCSObject()
@ -91,6 +91,30 @@ function POSITIONABLE:GetPointVec2()
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.
@ -137,7 +161,7 @@ function POSITIONABLE:IsAboveRunway()
if DCSPositionable then
local PointVec2 = self:GetPointVec2()
local PointVec2 = self:GetVec2()
local SurfaceType = land.getSurfaceType( PointVec2 )
local IsAboveRunway = SurfaceType == land.SurfaceType.RUNWAY
@ -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

View File

@ -0,0 +1,93 @@
--- @module Process
--- The PROCESS class
-- @type PROCESS
-- @field Scheduler#SCHEDULER ProcessScheduler
-- @field Unit#UNIT ProcessUnit
-- @field Task#TASK Task
-- @field StateMachine#STATEMACHINE_TASK Fsm
-- @field #string ProcessName
-- @extends Base#BASE
PROCESS = {
ClassName = "TASK",
ProcessScheduler = nil,
NextEvent = nil,
Scores = {},
}
--- Instantiates a new TASK Base. Should never be used. Interface Class.
-- @param #PROCESS self
-- @param #string ProcessName
-- @param Task#TASK_BASE Task
-- @param Unit#UNIT ProcessUnit
-- @return #PROCESS self
function PROCESS:New( ProcessName, Task, ProcessUnit )
local self = BASE:Inherit( self, BASE:New() )
self:F()
self.ProcessUnit = ProcessUnit
self.Task = Task
self.ProcessName = ProcessName
self.AllowEvents = true
return self
end
--- @param #PROCESS self
function PROCESS:NextEvent( NextEvent, ... )
self:F2( arg )
if self.AllowEvents == true then
self.ProcessScheduler = SCHEDULER:New( self.Fsm, NextEvent, { self, self.ProcessUnit, unpack( arg ) }, 1 )
end
end
--- @param #PROCESS self
function PROCESS:StopEvents( )
self:F2()
if self.ProcessScheduler then
self:E( "Stop" )
self.ProcessScheduler:Stop()
self.ProcessScheduler = nil
self.AllowEvents = false
end
end
--- Adds a score for the PROCESS to be achieved.
-- @param #PROCESS self
-- @param #string ProcessStatus is the status of the PROCESS when the score needs to be given.
-- @param #string ScoreText is a text describing the score that is given according the status.
-- @param #number Score is a number providing the score of the status.
-- @return #PROCESS self
function PROCESS:AddScore( ProcessStatus, ScoreText, Score )
self:F2( { ProcessStatus, ScoreText, Score } )
self.Scores[ProcessStatus] = self.Scores[ProcessStatus] or {}
self.Scores[ProcessStatus].ScoreText = ScoreText
self.Scores[ProcessStatus].Score = Score
return self
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS:OnStateChange( Fsm, Event, From, To )
self:E( { Event, From, To, self.ProcessUnit.UnitName } )
if self:IsTrace() then
MESSAGE:New( "Process " .. self.ProcessName .. " : " .. Event .. " changed to state " .. To, 15 ):ToAll()
end
if self.Scores[To] then
local Scoring = self.Task:GetScoring()
if Scoring then
Scoring:_AddMissionTaskScore( self.Task.Mission, self.ProcessUnit, self.Scores[To].ScoreText, self.Scores[To].Score )
end
end
end

View File

@ -0,0 +1,185 @@
--- 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
--
do -- PROCESS_ASSIGN_ACCEPT
--- 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",
}
--- 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 )
-- 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
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

View File

@ -0,0 +1,143 @@
--- @module Process_BAI
--- PROCESS_BAI class
-- @type PROCESS_BAI
-- @field Unit#UNIT ProcessUnit
-- @field Set#SET_UNIT TargetSetUnit
-- @extends Process#PROCESS
PROCESS_BAI = {
ClassName = "PROCESS_BAI",
Fsm = {},
TargetSetUnit = nil,
}
--- Creates a new BAI task.
-- @param #PROCESS_BAI self
-- @param Task#TASK Task
-- @param Unit#UNIT ProcessUnit
-- @param Set#SET_UNIT TargetSetUnit
-- @return #PROCESS_BAI self
function PROCESS_BAI:New( Task, ProcessUnit, TargetSetUnit )
-- Inherits from BASE
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 = 'Start', from = 'Assigned', 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,
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_BAI self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_BAI:OnStart( Fsm, Event, From, To )
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
self:NextEvent( Fsm.Start )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_BAI self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Event#EVENTDATA Event
function PROCESS_BAI:OnHitTarget( Fsm, Event, From, To, Event )
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_BAI self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_BAI:OnMoreTargets( Fsm, Event, From, To )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_BAI self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Event#EVENTDATA DCSEvent
function PROCESS_BAI:OnKilled( Fsm, Event, From, To )
self:NextEvent( Fsm.Restart )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_BAI self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_BAI:OnRestart( Fsm, Event, From, To )
self:NextEvent( Fsm.Menu )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_BAI self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_BAI:OnDestroyed( Fsm, Event, From, To )
end
--- DCS Events
--- @param #PROCESS_BAI self
-- @param Event#EVENTDATA Event
function PROCESS_BAI:EventDead( Event )
if Event.IniDCSUnit then
self.TargetSetUnit:Remove( Event.IniDCSUnitName )
self:NextEvent( self.Fsm.HitTarget, Event )
end
end

View File

@ -0,0 +1,143 @@
--- @module Process_CAS
--- PROCESS_CAS class
-- @type PROCESS_CAS
-- @field Unit#UNIT ProcessUnit
-- @field Set#SET_UNIT TargetSetUnit
-- @extends Process#PROCESS
PROCESS_CAS = {
ClassName = "PROCESS_CAS",
Fsm = {},
TargetSetUnit = nil,
}
--- Creates a new CAS task.
-- @param #PROCESS_CAS self
-- @param Task#TASK Task
-- @param Unit#UNIT ProcessUnit
-- @param Set#SET_UNIT TargetSetUnit
-- @return #PROCESS_CAS self
function PROCESS_CAS:New( Task, ProcessUnit, TargetSetUnit )
-- Inherits from BASE
local self = BASE:Inherit( self, PROCESS:New( "CAS", Task, ProcessUnit ) ) -- #PROCESS_CAS
self.TargetSetUnit = TargetSetUnit
self.Fsm = STATEMACHINE_PROCESS:New( self, {
initial = 'Assigned',
events = {
{ name = 'Start', from = 'Assigned', 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,
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_CAS self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_CAS:OnStart( Fsm, Event, From, To )
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
self:NextEvent( Fsm.Start )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_CAS self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Event#EVENTDATA Event
function PROCESS_CAS:OnHitTarget( Fsm, Event, From, To, Event )
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_CAS self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_CAS:OnMoreTargets( Fsm, Event, From, To )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_CAS self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Event#EVENTDATA DCSEvent
function PROCESS_CAS:OnKilled( Fsm, Event, From, To )
self:NextEvent( Fsm.Restart )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_CAS self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_CAS:OnRestart( Fsm, Event, From, To )
self:NextEvent( Fsm.Menu )
end
--- StateMachine callback function for a PROCESS
-- @param #PROCESS_CAS self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_CAS:OnDestroyed( Fsm, Event, From, To )
end
--- DCS Events
--- @param #PROCESS_CAS self
-- @param Event#EVENTDATA Event
function PROCESS_CAS:EventDead( Event )
if Event.IniDCSUnit then
self.TargetSetUnit:Remove( Event.IniDCSUnitName )
self:NextEvent( self.Fsm.HitTarget, Event )
end
end

View 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

View File

@ -0,0 +1,86 @@
--- @module Task_Route
--- PROCESS_ROUTE class
-- @type PROCESS_ROUTE
-- @field Task#TASK TASK
-- @field Unit#UNIT ProcessUnit
-- @field Zone#ZONE_BASE TargetZone
-- @extends Task2#TASK2
PROCESS_ROUTE = {
ClassName = "PROCESS_ROUTE",
}
--- Creates a new routing state machine. The task will route a CLIENT to a ZONE until the CLIENT is within that ZONE.
-- @param #PROCESS_ROUTE self
-- @param Task#TASK Task
-- @param Unit#UNIT Unit
-- @return #PROCESS_ROUTE self
function PROCESS_ROUTE:New( Task, ProcessUnit, TargetZone )
-- Inherits from BASE
local self = BASE:Inherit( self, PROCESS:New( "ROUTE", Task, ProcessUnit ) ) -- #PROCESS_ROUTE
self.TargetZone = TargetZone
self.DisplayInterval = 30
self.DisplayCount = 30
self.DisplayMessage = true
self.DisplayTime = 10 -- 10 seconds is the default
self.DisplayCategory = "HQ" -- Route is the default display category
self.Fsm = STATEMACHINE_PROCESS:New( self, {
initial = 'UnArrived',
events = {
{ name = 'Start', from = 'UnArrived', to = 'UnArrived' },
{ name = 'Fail', from = 'UnArrived', to = 'Failed' },
},
callbacks = {
onleaveUnArrived = self.OnLeaveUnArrived,
onFail = self.OnFail,
},
endstates = {
'Arrived', 'Failed'
},
} )
return self
end
--- Task Events
--- StateMachine callback function for a TASK2
-- @param #PROCESS_ROUTE self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ROUTE:OnLeaveUnArrived( Fsm, Event, From, To )
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
--if not IsInZone then
self:NextEvent( Fsm.Start )
--end
return IsInZone -- if false, then the event will not be executed...
end
return false
end

View 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

View File

@ -245,22 +245,6 @@ end
-- From http://lua-users.org/wiki/SimpleRound
-- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place
routines.utils.round = function(num, idp)
local mult = 10^(idp or 0)
return math.floor(num * mult + 0.5) / mult
end
-- porting in Slmod's dostring
routines.utils.dostring = function(s)
local f, err = loadstring(s)
if f then
return true, f()
else
return false, err
end
end
--3D Vector manipulation

View File

@ -95,6 +95,7 @@ function SCHEDULER:Stop()
self.Repeat = false
if self.ScheduleID then
self:E( "Stop Schedule" )
timer.removeFunction( self.ScheduleID )
end
self.ScheduleID = nil

View File

@ -59,6 +59,8 @@ function SCORING:New( GameName )
self.SchedulerId = SCHEDULER:New( self, self._FollowPlayersScheduled, {}, 0, 5 )
self:ScoreMenu()
self:OpenCSV( GameName)
return self
@ -262,10 +264,17 @@ end
--- Registers Scores the players completing a Mission Task.
function SCORING:_AddMissionTaskScore( PlayerUnit, MissionName, Score )
self:F( { PlayerUnit, MissionName, Score } )
-- @param #SCORING self
-- @param Mission#MISSION Mission
-- @param Unit#UNIT PlayerUnit
-- @param #string Text
-- @param #number Score
function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score )
local PlayerName = PlayerUnit:getPlayerName()
local PlayerName = PlayerUnit:GetPlayerName()
local MissionName = Mission:GetName()
self:F( { Mission:GetName(), PlayerUnit.UnitName, PlayerName, Text, Score } )
if not self.Players[PlayerName].Mission[MissionName] then
self.Players[PlayerName].Mission[MissionName] = {}
@ -279,26 +288,37 @@ function SCORING:_AddMissionTaskScore( PlayerUnit, MissionName, Score )
self.Players[PlayerName].Score = self.Players[PlayerName].Score + Score
self.Players[PlayerName].Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
MESSAGE:New( "Player '" .. PlayerName .. "' has finished another Task in Mission '" .. MissionName .. "'. " ..
Score .. " Score points added.",
20 ):ToAll()
MESSAGE:New( "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " ..
Score .. " task score!",
30 ):ToAll()
self:ScoreCSV( PlayerName, "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:getName() )
self:ScoreCSV( PlayerName, "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() )
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

View File

@ -224,10 +224,15 @@
--- SET_BASE class
-- @type SET_BASE
-- @field #table Filter
-- @field #table Set
-- @field #table List
-- @extends Base#BASE
SET_BASE = {
ClassName = "SET_BASE",
Filter = {},
Set = {},
List = {},
}
--- Creates a new SET_BASE object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names.
@ -246,6 +251,10 @@ function SET_BASE:New( Database )
self.YieldInterval = 10
self.TimeInterval = 0.001
self.List = {}
self.List.__index = self.List
self.List = setmetatable( { Count = 0 }, self.List )
return self
end
@ -275,18 +284,90 @@ end
-- @param Base#BASE Object
-- @return Base#BASE The added BASE Object.
function SET_BASE:Add( ObjectName, Object )
self:F2( ObjectName )
self.Set[ObjectName] = Object
local t = { _ = Object }
if self.List.last then
self.List.last._next = t
t._prev = self.List.last
self.List.last = t
else
-- this is the first node
self.List.first = t
self.List.last = t
end
self.List.Count = self.List.Count + 1
self.Set[ObjectName] = t._
end
--- Removes a @{Base#BASE} object from the @{Set#SET_BASE} and derived classes, based on the Object Name.
-- @param #SET_BASE self
-- @param #string ObjectName
function SET_BASE:Remove( ObjectName )
self:E( ObjectName )
self.Set[ObjectName] = nil
local t = self.Set[ObjectName]
if t then
if t._next then
if t._prev then
t._next._prev = t._prev
t._prev._next = t._next
else
-- this was the first node
t._next._prev = nil
self.List._first = t._next
end
elseif t._prev then
-- this was the last node
t._prev._next = nil
self.List._last = t._prev
else
-- this was the only node
self.List._first = nil
self.List._last = nil
end
t._next = nil
t._prev = nil
self.List.Count = self.List.Count - 1
self.Set[ObjectName] = nil
end
end
--- Retrieves the amount of objects in the @{Set#SET_BASE} and derived classes.
-- @param #SET_BASE self
-- @return #number Count
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
-- @return #SET_BASE
function SET_BASE:SetDatabase( BaseSet )
-- Copy the filter criteria of the BaseSet
local OtherFilter = routines.utils.deepCopy( BaseSet.Filter )
self.Filter = OtherFilter
-- Now base the new Set on the BaseSet
self.Database = BaseSet:GetSet()
return self
end
--- Define the SET iterator **"yield interval"** and the **"time interval"**.
-- @param #SET_BASE self
-- @param #number YieldInterval Sets the frequency when the iterator loop will yield after the number of objects processed. The default frequency is 10 objects processed.
@ -301,6 +382,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
@ -320,13 +415,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.
@ -340,9 +447,9 @@ function SET_BASE:FindNearestObjectFromPointVec2( PointVec2 )
for ObjectID, ObjectData in pairs( self.Set ) do
if NearestObject == nil then
NearestObject = ObjectData
ClosestDistance = PointVec2:DistanceFromVec2( ObjectData:GetPointVec2() )
ClosestDistance = PointVec2:DistanceFromVec2( ObjectData:GetVec2() )
else
local Distance = PointVec2:DistanceFromVec2( ObjectData:GetPointVec2() )
local Distance = PointVec2:DistanceFromVec2( ObjectData:GetVec2() )
if Distance < ClosestDistance then
NearestObject = ObjectData
ClosestDistance = Distance
@ -399,49 +506,58 @@ end
-- @param #SET_BASE self
-- @param Event#EVENTDATA Event
function SET_BASE:_EventOnDeadOrCrash( Event )
self:F3( { Event } )
self:E( { Event } )
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
@ -454,7 +570,8 @@ function SET_BASE:ForEach( IteratorFunction, arg, Set, Function, FunctionArgumen
local function CoRoutine()
local Count = 0
for ObjectID, Object in pairs( Set ) do
for ObjectID, ObjectData in pairs( Set ) do
local Object = ObjectData
self:T3( Object )
if Function then
if Function( unpack( FunctionArguments ), Object ) == true then
@ -554,7 +671,7 @@ function SET_BASE:Flush()
for ObjectName, Object in pairs( self.Set ) do
ObjectNames = ObjectNames .. ObjectName .. ", "
end
self:T( { "Objects in Set:", ObjectNames } )
self:E( { "Objects in Set:", ObjectNames } )
return ObjectNames
end
@ -732,6 +849,8 @@ function SET_GROUP:FilterStart()
self:_FilterStart()
end
return self
end
@ -966,10 +1085,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
@ -1124,6 +1239,31 @@ function SET_UNIT:FilterPrefixes( Prefixes )
return self
end
--- Builds a set of units having a radar of give types.
-- All the units having a radar of a given type will be included within the set.
-- @param #SET_UNIT self
-- @param #table RadarTypes The radar types.
-- @return #SET_UNIT self
function SET_UNIT:FilterHasRadar( RadarTypes )
self.Filter.RadarTypes = self.Filter.RadarTypes or {}
if type( RadarTypes ) ~= "table" then
RadarTypes = { RadarTypes }
end
for RadarTypeID, RadarType in pairs( RadarTypes ) do
self.Filter.RadarTypes[RadarType] = RadarType
end
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
@ -1163,9 +1303,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.
@ -1224,6 +1365,119 @@ 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 = {}
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
-- @return #number The amount of radars in the Set with the given type
function SET_UNIT:HasRadar( RadarType )
self:F2( RadarType )
local RadarCount = 0
for UnitID, UnitData in pairs( self:GetSet()) do
local UnitSensorTest = UnitData -- Unit#UNIT
local HasSensors
if RadarType then
HasSensors = UnitSensorTest:HasSensors( Unit.SensorType.RADAR, RadarType )
else
HasSensors = UnitSensorTest:HasSensors( Unit.SensorType.RADAR )
end
self:T3(HasSensors)
if HasSensors then
RadarCount = RadarCount + 1
end
end
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
-- @return #number The amount of ground targets in the Set.
function SET_UNIT:HasGroundUnits()
self:F2()
local GroundUnitCount = 0
for UnitID, UnitData in pairs( self:GetSet()) do
local UnitTest = UnitData -- Unit#UNIT
if UnitTest:IsGround() then
GroundUnitCount = GroundUnitCount + 1
end
end
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.
@ -1315,6 +1569,29 @@ function SET_UNIT:IsIncludeObject( MUnit )
MUnitInclude = MUnitInclude and MUnitPrefix
end
if self.Filter.RadarTypes then
local MUnitRadar = false
for RadarTypeID, RadarType in pairs( self.Filter.RadarTypes ) do
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:T3( "RADAR Found" )
end
MUnitRadar = true
end
end
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

View File

@ -565,7 +565,7 @@ function SPAWN:SpawnFromUnit( HostUnit, OuterRadius, InnerRadius, SpawnIndex )
if SpawnTemplate then
local UnitPoint = HostUnit:GetPointVec2()
local UnitPoint = HostUnit:GetVec2()
self:T( { "Current point of ", self.SpawnTemplatePrefix, UnitPoint } )
@ -648,7 +648,7 @@ function SPAWN:SpawnInZone( Zone, ZoneRandomize, SpawnIndex )
if ZoneRandomize == true then
ZonePoint = Zone:GetRandomVec2()
else
ZonePoint = Zone:GetPointVec2()
ZonePoint = Zone:GetVec2()
end
SpawnTemplate.route.points[1].x = ZonePoint.x

View File

@ -0,0 +1,283 @@
--- This module contains the STATEMACHINE class.
-- This development is based on a state machine implementation made by Conroy Kyle.
-- The state machine can be found here: https://github.com/kyleconroy/lua-state-machine
--
-- I've taken the development and enhanced it to make the state machine hierarchical...
-- It is a fantastic development, this module.
--
-- ===
--
-- 1) @{Workflow#STATEMACHINE} class, extends @{Base#BASE}
-- ==============================================
--
-- 1.1) Add or remove objects from the STATEMACHINE
-- --------------------------------------------
-- @module StateMachine
-- @author FlightControl
--- STATEMACHINE class
-- @type STATEMACHINE
STATEMACHINE = {
ClassName = "STATEMACHINE",
}
--- Creates a new STATEMACHINE object.
-- @param #STATEMACHINE self
-- @return #STATEMACHINE
function STATEMACHINE:New( options )
-- Inherits from BASE
local self = BASE:Inherit( self, BASE:New() )
--local self = routines.utils.deepCopy( self ) -- Create a new self instance
assert(options.events)
--local MT = {}
--setmetatable( self, MT )
--self.__index = self
self.options = options
self.current = options.initial or 'none'
self.events = {}
self.subs = {}
self.endstates = {}
for _, event in ipairs(options.events or {}) do
local name = event.name
self[name] = self[name] or self:_create_transition(name)
self.events[name] = self.events[name] or { map = {} }
self:_add_to_map(self.events[name].map, event)
end
for name, callback in pairs(options.callbacks or {}) do
self[name] = callback
end
for name, sub in pairs( options.subs or {} ) do
self:_submap( self.subs, sub, name )
end
for name, endstate in pairs( options.endstates or {} ) do
self.endstates[endstate] = endstate
end
return self
end
function STATEMACHINE:_submap( subs, sub, name )
self:E( { sub = sub, name = name } )
subs[sub.onstateparent] = subs[sub.onstateparent] or {}
subs[sub.onstateparent][sub.oneventparent] = subs[sub.onstateparent][sub.oneventparent] or {}
local Index = #subs[sub.onstateparent][sub.oneventparent] + 1
subs[sub.onstateparent][sub.oneventparent][Index] = {}
subs[sub.onstateparent][sub.oneventparent][Index].fsm = sub.fsm
subs[sub.onstateparent][sub.oneventparent][Index].event = sub.event
subs[sub.onstateparent][sub.oneventparent][Index].returnevents = sub.returnevents -- these events need to be given to find the correct continue event ... if none given, the processing will stop.
subs[sub.onstateparent][sub.oneventparent][Index].name = name
subs[sub.onstateparent][sub.oneventparent][Index].fsmparent = self
end
function STATEMACHINE:_call_handler(handler, params)
if handler then
return handler(unpack(params))
end
end
function STATEMACHINE:_create_transition(name)
self:E( { name = name } )
return function(self, ...)
local can, to = self:can(name)
self:T( { name, can, to } )
if can then
local from = self.current
local params = { self, name, from, to, ... }
if self:_call_handler(self["onbefore" .. name], params) == false
or self:_call_handler(self["onleave" .. from], params) == false then
return false
end
self.current = to
local execute = true
local subtable = self:_gosub( to, name )
for _, sub in pairs( subtable ) do
self:E( "calling sub: " .. sub.event )
sub.fsm.fsmparent = self
sub.fsm.returnevents = sub.returnevents
sub.fsm[sub.event]( sub.fsm )
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)
fsmparent[event]( fsmparent )
execute = false
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)
end
return true
end
return false
end
end
function STATEMACHINE:_gosub( parentstate, parentevent )
local fsmtable = {}
if self.subs[parentstate] and self.subs[parentstate][parentevent] then
return self.subs[parentstate][parentevent]
else
return {}
end
end
function STATEMACHINE:_isendstate( state )
local fsmparent = self.fsmparent
if fsmparent and self.endstates[state] then
self:E( { state = state, endstates = self.endstates, endstate = self.endstates[state] } )
local returnevent = nil
local fromstate = fsmparent.current
self:E( fromstate )
self:E( self.returnevents )
for _, eventname in pairs( self.returnevents ) do
local event = fsmparent.events[eventname]
self:E( event )
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
return nil
end
function STATEMACHINE:_add_to_map(map, event)
if type(event.from) == 'string' then
map[event.from] = event.to
else
for _, from in ipairs(event.from) do
map[from] = event.to
end
end
end
function STATEMACHINE:is(state)
return self.current == state
end
function STATEMACHINE:can(e)
local event = self.events[e]
local to = event and event.map[self.current] or event.map['*']
return to ~= nil, to
end
function STATEMACHINE:cannot(e)
return not self:can(e)
end
function STATEMACHINE:todot(filename)
local dotfile = io.open(filename,'w')
dotfile:write('digraph {\n')
local transition = function(event,from,to)
dotfile:write(string.format('%s -> %s [label=%s];\n',from,to,event))
end
for _, event in pairs(self.options.events) do
if type(event.from) == 'table' then
for _, from in ipairs(event.from) do
transition(event.name,from,event.to)
end
else
transition(event.name,event.from,event.to)
end
end
dotfile:write('}\n')
dotfile:close()
end
--- STATEMACHINE_PROCESS class
-- @type STATEMACHINE_PROCESS
-- @field Process#PROCESS Process
-- @extends StateMachine#STATEMACHINE
STATEMACHINE_PROCESS = {
ClassName = "STATEMACHINE_PROCESS",
}
--- Creates a new STATEMACHINE_PROCESS object.
-- @param #STATEMACHINE_PROCESS self
-- @return #STATEMACHINE_PROCESS
function STATEMACHINE_PROCESS:New( Process, options )
local FsmProcess = routines.utils.deepCopy( self ) -- Create a new self instance
local Parent = STATEMACHINE:New(options)
setmetatable( FsmProcess, Parent )
FsmProcess.__index = FsmProcess
FsmProcess["onstatechange"] = Process.OnStateChange
FsmProcess.Process = Process
return FsmProcess
end
function STATEMACHINE_PROCESS:_call_handler( handler, params )
if handler then
return handler( self.Process, unpack( params ) )
end
end
--- STATEMACHINE_TASK class
-- @type STATEMACHINE_TASK
-- @field Task#TASK_BASE Task
-- @extends StateMachine#STATEMACHINE
STATEMACHINE_TASK = {
ClassName = "STATEMACHINE_TASK",
}
--- Creates a new STATEMACHINE_TASK object.
-- @param #STATEMACHINE_TASK self
-- @return #STATEMACHINE_TASK
function STATEMACHINE_TASK:New( Task, TaskUnit, options )
local FsmTask = routines.utils.deepCopy( self ) -- Create a new self instance
local Parent = STATEMACHINE:New(options)
setmetatable( FsmTask, Parent )
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, self.TaskUnit, unpack( params ) )
end
end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,84 @@
--- @module Task_Client_Menu
--- TASK2_MENU_CLIENT class
-- @type TASK2_MENU_CLIENT
-- @field Unit#UNIT TaskUnit
-- @field Set#SET_UNIT TargetSet
-- @field Menu#MENU_CLIENT_COMMAND MenuTask
-- @extends Task2#TASK2
TASK2_MENU_CLIENT = {
ClassName = "TASK2_MENU_CLIENT",
TargetSet = nil,
}
--- Creates a new MENU handling machine.
-- @param #TASK2_MENU_CLIENT self
-- @param Mission#MISSION Mission
-- @param Unit#UNIT TaskUnit
-- @param #string MenuText The text of the menu item.
-- @return #TASK2_MENU_CLIENT self
function TASK2_MENU_CLIENT:New( Mission, TaskUnit, MenuText )
-- Inherits from BASE
local self = BASE:Inherit( self, TASK2:New( Mission, TaskUnit ) ) -- #TASK2_MENU_CLIENT
self.MenuText = MenuText
self.Fsm = STATEMACHINE_TASK:New( self, {
initial = 'Unassigned',
events = {
{ name = 'Menu', from = 'Unassigned', to = 'AwaitingMenu' },
{ name = 'Assign', from = 'AwaitingMenu', to = 'Assigned' },
},
callbacks = {
onMenu = self.OnMenu,
onAssign = self.OnAssign,
},
endstates = {
'Assigned'
},
} )
return self
end
--- Task Events
--- StateMachine callback function for a TASK2
-- @param #TASK2_MENU_CLIENT self
-- @param StateMachine#STATEMACHINE_TASK Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function TASK2_MENU_CLIENT:OnMenu( Fsm, Event, From, To )
self:E( { Event, From, To, self.TaskUnit.UnitName} )
self.TaskUnit:Message( "Press F10 for task menu", 15 )
self.Menu = MENU_CLIENT:New( self.TaskUnit, self.Mission:GetName(), nil )
self.MenuTask = MENU_CLIENT_COMMAND:New( self.TaskUnit, self.MenuText, self.Menu, self.MenuAssign, self )
end
--- Menu function.
-- @param #TASK2_MENU_CLIENT self
function TASK2_MENU_CLIENT:MenuAssign()
self:E( )
self.TaskUnit:Message( "Menu Assign", 15 )
self:NextEvent( self.Fsm.Assign )
end
--- StateMachine callback function for a TASK2
-- @param #TASK2_MENU_CLIENT self
-- @param StateMachine#STATEMACHINE_TASK Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function TASK2_MENU_CLIENT:OnAssign( Fsm, Event, From, To )
self:E( { Event, From, To, self.TaskUnit.UnitName} )
self.TaskUnit:Message( "Assign Task", 15 )
self.MenuTask:Remove()
end

View 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

View File

@ -0,0 +1,145 @@
--- 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
do -- 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_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()
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_CAS.
-- @param #TASK_CAS self
-- @return #nil
function TASK_CAS:CleanUp()
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

View File

@ -0,0 +1,145 @@
--- 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
do -- TASK_SEAD
--- The TASK_SEAD class
-- @type TASK_SEAD
-- @field Set#SET_UNIT TargetSetUnit
-- @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_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()
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_SEAD.
-- @param #TASK_SEAD self
-- @return #nil
function TASK_SEAD:CleanUp()
self:GetParent(self):CleanUp()
return nil
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

View File

@ -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
-- ------------------
@ -109,6 +109,14 @@ UNIT = {
-- @field Orange
-- @field Blue
--- Unit.SensorType
-- @type Unit.SensorType
-- @field OPTIC
-- @field RADAR
-- @field IRST
-- @field RWR
-- Registration.
--- Create a new UNIT from DCSUnit.
@ -179,6 +187,24 @@ function UNIT:IsActive()
return nil
end
--- Destroys the @{Unit}.
-- @param Unit#UNIT self
-- @return #nil The DCS Unit is not existing or alive.
function UNIT:Destroy()
self:F2( self.UnitName )
local DCSUnit = self:GetDCSObject()
if DCSUnit then
DCSUnit:destroy()
end
return nil
end
--- Returns the Unit's callsign - the localized string.
-- @param Unit#UNIT self
-- @return #string The Callsign of the Unit.
@ -316,6 +342,46 @@ end
-- Need to add here a function per sensortype
-- unit:hasSensors(Unit.SensorType.RADAR, Unit.RadarType.AS)
--- Returns if the unit has sensors of a certain type.
-- @param Unit#UNIT self
-- @return #boolean returns true if the unit has specified types of sensors. This function is more preferable than Unit.getSensors() if you don't want to get information about all the unit's sensors, and just want to check if the unit has specified types of sensors.
-- @return #nil The DCS Unit is not existing or alive.
function UNIT:HasSensors( ... )
self:F2( arg )
local DCSUnit = self:GetDCSObject()
if DCSUnit then
local HasSensors = DCSUnit:hasSensors( unpack( arg ) )
return HasSensors
end
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.
@ -388,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
@ -405,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}.
@ -489,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.
@ -543,12 +657,83 @@ end
function UNIT:IsAir()
self:F2()
local UnitDescriptor = self.DCSUnit:getDesc()
self:T3( { UnitDescriptor.category, Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
local DCSUnit = self:GetDCSObject()
local IsAirResult = ( UnitDescriptor.category == Unit.Category.AIRPLANE ) or ( UnitDescriptor.category == Unit.Category.HELICOPTER )
self:T3( IsAirResult )
return IsAirResult
if DCSUnit then
local UnitDescriptor = DCSUnit:getDesc()
self:T3( { UnitDescriptor.category, Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
local IsAirResult = ( UnitDescriptor.category == Unit.Category.AIRPLANE ) or ( UnitDescriptor.category == Unit.Category.HELICOPTER )
self:T3( IsAirResult )
return IsAirResult
end
return nil
end
--- Returns if the unit is of an ground category.
-- If the unit is a ground vehicle or infantry, this method will return true, otherwise false.
-- @param #UNIT self
-- @return #boolean Ground category evaluation result.
function UNIT:IsGround()
self:F2()
local DCSUnit = self:GetDCSObject()
if DCSUnit then
local UnitDescriptor = DCSUnit:getDesc()
self:T3( { UnitDescriptor.category, Unit.Category.GROUND_UNIT } )
local IsGroundResult = ( UnitDescriptor.category == Unit.Category.GROUND_UNIT )
self:T3( IsGroundResult )
return IsGroundResult
end
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
-- @return #boolean Ship category evaluation result.
function UNIT:IsShip()
self:F2()
local DCSUnit = self:GetDCSObject()
if DCSUnit then
local UnitDescriptor = DCSUnit:getDesc()
self:T3( { UnitDescriptor.category, Unit.Category.SHIP } )
local IsShipResult = ( UnitDescriptor.category == Unit.Category.SHIP )
self:T3( IsShipResult )
return IsShipResult
end
return nil
end

View File

@ -0,0 +1,282 @@
--- @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 = {}
--from http://lua-users.org/wiki/CopyTable
UTILS.DeepCopy = function(object)
local lookup_table = {}
local function _copy(object)
if type(object) ~= "table" then
return object
elseif lookup_table[object] then
return lookup_table[object]
end
local new_table = {}
lookup_table[object] = new_table
for index, value in pairs(object) do
new_table[_copy(index)] = _copy(value)
end
return setmetatable(new_table, getmetatable(object))
end
local objectreturn = _copy(object)
return objectreturn
end
-- porting in Slmod's serialize_slmod2
UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function
lookup_table = {}
local function _Serialize( tbl )
if type(tbl) == 'table' then --function only works for tables!
if lookup_table[tbl] then
return lookup_table[object]
end
local tbl_str = {}
lookup_table[tbl] = tbl_str
tbl_str[#tbl_str + 1] = '{'
for ind,val in pairs(tbl) do -- serialize its fields
local ind_str = {}
if type(ind) == "number" then
ind_str[#ind_str + 1] = '['
ind_str[#ind_str + 1] = tostring(ind)
ind_str[#ind_str + 1] = ']='
else --must be a string
ind_str[#ind_str + 1] = '['
ind_str[#ind_str + 1] = routines.utils.basicSerialize(ind)
ind_str[#ind_str + 1] = ']='
end
local val_str = {}
if ((type(val) == 'number') or (type(val) == 'boolean')) then
val_str[#val_str + 1] = tostring(val)
val_str[#val_str + 1] = ','
tbl_str[#tbl_str + 1] = table.concat(ind_str)
tbl_str[#tbl_str + 1] = table.concat(val_str)
elseif type(val) == 'string' then
val_str[#val_str + 1] = routines.utils.basicSerialize(val)
val_str[#val_str + 1] = ','
tbl_str[#tbl_str + 1] = table.concat(ind_str)
tbl_str[#tbl_str + 1] = table.concat(val_str)
elseif type(val) == 'nil' then -- won't ever happen, right?
val_str[#val_str + 1] = 'nil,'
tbl_str[#tbl_str + 1] = table.concat(ind_str)
tbl_str[#tbl_str + 1] = table.concat(val_str)
elseif type(val) == 'table' then
if ind == "__index" then
-- tbl_str[#tbl_str + 1] = "__index"
-- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
else
val_str[#val_str + 1] = _Serialize(val)
val_str[#val_str + 1] = ',' --I think this is right, I just added it
tbl_str[#tbl_str + 1] = table.concat(ind_str)
tbl_str[#tbl_str + 1] = table.concat(val_str)
end
elseif type(val) == 'function' then
-- tbl_str[#tbl_str + 1] = "function " .. tostring(ind)
-- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
else
-- env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind))
-- env.info( debug.traceback() )
end
end
tbl_str[#tbl_str + 1] = '}'
return table.concat(tbl_str)
else
return tostring(tbl)
end
end
local objectreturn = _Serialize(tbl)
return objectreturn
end
--porting in Slmod's "safestring" basic serialize
UTILS.BasicSerialize = function(s)
if s == nil then
return "\"\""
else
if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then
return tostring(s)
elseif type(s) == 'string' then
s = string.format('%q', s)
return s
end
end
end
UTILS.ToDegree = function(angle)
return angle*180/math.pi
end
UTILS.ToRadian = function(angle)
return angle*math.pi/180
end
UTILS.MetersToNM = function(meters)
return meters/1852
end
UTILS.MetersToFeet = function(meters)
return meters/0.3048
end
UTILS.NMToMeters = function(NM)
return NM*1852
end
UTILS.FeetToMeters = function(feet)
return feet*0.3048
end
UTILS.MpsToKnots = function(mps)
return mps*3600/1852
end
UTILS.MpsToKmph = function(mps)
return mps*3.6
end
UTILS.KnotsToMps = function(knots)
return knots*1852/3600
end
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
function UTILS.Round( num, idp )
local mult = 10 ^ ( idp or 0 )
return math.floor( num * mult + 0.5 ) / mult
end
-- porting in Slmod's dostring
function UTILS.DoString( s )
local f, err = loadstring( s )
if f then
return true, f()
else
return false, err
end
end

View File

@ -101,10 +101,10 @@ end
--- Returns if a location is within the zone.
-- @param #ZONE_BASE self
-- @param DCSTypes#Vec2 PointVec2 The location to test.
-- @param DCSTypes#Vec2 Vec2 The location to test.
-- @return #boolean true if the location is within the zone.
function ZONE_BASE:IsPointVec2InZone( PointVec2 )
self:F2( PointVec2 )
function ZONE_BASE:IsPointVec2InZone( Vec2 )
self:F2( Vec2 )
return false
end
@ -121,18 +121,27 @@ function ZONE_BASE:IsPointVec3InZone( PointVec3 )
return InZone
end
--- Returns the Vec2 coordinate of the zone.
-- @param #ZONE_BASE self
-- @return #nil.
function ZONE_BASE:GetVec2()
self:F2( self.ZoneName )
return nil
end
--- Define a random @{DCSTypes#Vec2} within the zone.
-- @param #ZONE_BASE self
-- @return DCSTypes#Vec2 The Vec2 coordinates.
-- @return #nil The Vec2 coordinates.
function ZONE_BASE:GetRandomVec2()
return { x = 0, y = 0 }
return nil
end
--- Get the bounding square the zone.
-- @param #ZONE_BASE self
-- @return #ZONE_BASE.BoundingSquare The bounding square.
-- @return #nil The bounding square.
function ZONE_BASE:GetBoundingSquare()
return { x1 = 0, y1 = 0, x2 = 0, y2 = 0 }
--return { x1 = 0, y1 = 0, x2 = 0, y2 = 0 }
return nil
end
@ -147,7 +156,7 @@ end
--- The ZONE_RADIUS class, defined by a zone name, a location and a radius.
-- @type ZONE_RADIUS
-- @field DCSTypes#Vec2 PointVec2 The current location of the zone.
-- @field DCSTypes#Vec2 Vec2 The current location of the zone.
-- @field DCSTypes#Distance Radius The radius of the zone.
-- @extends Zone#ZONE_BASE
ZONE_RADIUS = {
@ -157,15 +166,15 @@ ZONE_RADIUS = {
--- Constructor of ZONE_RADIUS, taking the zone name, the zone location and a radius.
-- @param #ZONE_RADIUS self
-- @param #string ZoneName Name of the zone.
-- @param DCSTypes#Vec2 PointVec2 The location of the zone.
-- @param DCSTypes#Vec2 Vec2 The location of the zone.
-- @param DCSTypes#Distance Radius The radius of the zone.
-- @return #ZONE_RADIUS self
function ZONE_RADIUS:New( ZoneName, PointVec2, Radius )
function ZONE_RADIUS:New( ZoneName, Vec2, Radius )
local self = BASE:Inherit( self, ZONE_BASE:New( ZoneName ) )
self:F( { ZoneName, PointVec2, Radius } )
self:F( { ZoneName, Vec2, Radius } )
self.Radius = Radius
self.PointVec2 = PointVec2
self.Vec2 = Vec2
return self
end
@ -179,7 +188,7 @@ function ZONE_RADIUS:SmokeZone( SmokeColor, Points )
self:F2( SmokeColor )
local Point = {}
local PointVec2 = self:GetPointVec2()
local Vec2 = self:GetVec2()
Points = Points and Points or 360
@ -188,8 +197,8 @@ function ZONE_RADIUS:SmokeZone( SmokeColor, Points )
for Angle = 0, 360, 360 / Points do
local Radial = Angle * RadialBase / 360
Point.x = PointVec2.x + math.cos( Radial ) * self:GetRadius()
Point.y = PointVec2.y + math.sin( Radial ) * self:GetRadius()
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
POINT_VEC2:New( Point.x, Point.y ):Smoke( SmokeColor )
end
@ -207,7 +216,7 @@ function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth )
self:F2( { FlareColor, Azimuth } )
local Point = {}
local PointVec2 = self:GetPointVec2()
local Vec2 = self:GetVec2()
Points = Points and Points or 360
@ -216,8 +225,8 @@ function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth )
for Angle = 0, 360, 360 / Points do
local Radial = Angle * RadialBase / 360
Point.x = PointVec2.x + math.cos( Radial ) * self:GetRadius()
Point.y = PointVec2.y + math.sin( Radial ) * self:GetRadius()
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
POINT_VEC2:New( Point.x, Point.y ):Flare( FlareColor, Azimuth )
end
@ -251,26 +260,26 @@ end
--- Returns the location of the zone.
-- @param #ZONE_RADIUS self
-- @return DCSTypes#Vec2 The location of the zone.
function ZONE_RADIUS:GetPointVec2()
function ZONE_RADIUS:GetVec2()
self:F2( self.ZoneName )
self:T2( { self.PointVec2 } )
self:T2( { self.Vec2 } )
return self.PointVec2
return self.Vec2
end
--- Sets the location of the zone.
-- @param #ZONE_RADIUS self
-- @param DCSTypes#Vec2 PointVec2 The new location of the zone.
-- @param DCSTypes#Vec2 Vec2 The new location of the zone.
-- @return DCSTypes#Vec2 The new location of the zone.
function ZONE_RADIUS:SetPointVec2( PointVec2 )
function ZONE_RADIUS:SetPointVec2( Vec2 )
self:F2( self.ZoneName )
self.PointVec2 = PointVec2
self.Vec2 = Vec2
self:T2( { self.PointVec2 } )
self:T2( { self.Vec2 } )
return self.PointVec2
return self.Vec2
end
--- Returns the point of the zone.
@ -280,9 +289,9 @@ end
function ZONE_RADIUS:GetPointVec3( Height )
self:F2( self.ZoneName )
local PointVec2 = self:GetPointVec2()
local Vec2 = self:GetVec2()
local PointVec3 = { x = PointVec2.x, y = land.getHeight( self:GetPointVec2() ) + Height, z = PointVec2.y }
local PointVec3 = { x = Vec2.x, y = land.getHeight( self:GetVec2() ) + Height, z = Vec2.y }
self:T2( { PointVec3 } )
@ -292,15 +301,17 @@ end
--- Returns if a location is within the zone.
-- @param #ZONE_RADIUS self
-- @param DCSTypes#Vec2 PointVec2 The location to test.
-- @param DCSTypes#Vec2 Vec2 The location to test.
-- @return #boolean true if the location is within the zone.
function ZONE_RADIUS:IsPointVec2InZone( PointVec2 )
self:F2( PointVec2 )
function ZONE_RADIUS:IsPointVec2InZone( Vec2 )
self:F2( Vec2 )
local ZonePointVec2 = self:GetPointVec2()
if (( PointVec2.x - ZonePointVec2.x )^2 + ( PointVec2.y - ZonePointVec2.y ) ^2 ) ^ 0.5 <= self:GetRadius() then
return true
local ZoneVec2 = self:GetVec2()
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
@ -310,10 +321,10 @@ end
-- @param #ZONE_RADIUS self
-- @param DCSTypes#Vec3 PointVec3 The point to test.
-- @return #boolean true if the point is within the zone.
function ZONE_RADIUS:IsPointVec3InZone( PointVec3 )
self:F2( PointVec3 )
function ZONE_RADIUS:IsPointVec3InZone( Vec3 )
self:F2( Vec3 )
local InZone = self:IsPointVec2InZone( { x = PointVec3.x, y = PointVec3.z } )
local InZone = self:IsPointVec2InZone( { x = Vec3.x, y = Vec3.z } )
return InZone
end
@ -325,11 +336,11 @@ function ZONE_RADIUS:GetRandomVec2()
self:F( self.ZoneName )
local Point = {}
local PointVec2 = self:GetPointVec2()
local Vec2 = self:GetVec2()
local angle = math.random() * math.pi*2;
Point.x = PointVec2.x + math.cos( angle ) * math.random() * self:GetRadius();
Point.y = PointVec2.y + math.sin( angle ) * math.random() * self:GetRadius();
Point.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius();
Point.y = Vec2.y + math.sin( angle ) * math.random() * self:GetRadius();
self:T( { Point } )
@ -383,10 +394,11 @@ ZONE_UNIT = {
-- @param DCSTypes#Distance Radius The radius of the zone.
-- @return #ZONE_UNIT self
function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius )
local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneUNIT:GetPointVec2(), Radius ) )
self:F( { ZoneName, ZoneUNIT:GetPointVec2(), Radius } )
local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneUNIT:GetVec2(), Radius ) )
self:F( { ZoneName, ZoneUNIT:GetVec2(), Radius } )
self.ZoneUNIT = ZoneUNIT
self.LastVec2 = ZoneUNIT:GetVec2()
return self
end
@ -395,14 +407,20 @@ end
--- Returns the current location of the @{Unit#UNIT}.
-- @param #ZONE_UNIT self
-- @return DCSTypes#Vec2 The location of the zone based on the @{Unit#UNIT}location.
function ZONE_UNIT:GetPointVec2()
function ZONE_UNIT:GetVec2()
self:F( self.ZoneName )
local ZonePointVec2 = self.ZoneUNIT:GetPointVec2()
local ZoneVec2 = self.ZoneUNIT:GetVec2()
if ZoneVec2 then
self.LastVec2 = ZoneVec2
return ZoneVec2
else
return self.LastVec2
end
self:T( { ZonePointVec2 } )
return ZonePointVec2
self:T( { ZoneVec2 } )
return nil
end
--- Returns a random location within the zone.
@ -413,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();
@ -423,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
@ -567,10 +606,10 @@ end
--- Returns if a location is within the zone.
-- Source learned and taken from: https://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
-- @param #ZONE_POLYGON_BASE self
-- @param DCSTypes#Vec2 PointVec2 The location to test.
-- @param DCSTypes#Vec2 Vec2 The location to test.
-- @return #boolean true if the location is within the zone.
function ZONE_POLYGON_BASE:IsPointVec2InZone( PointVec2 )
self:F2( PointVec2 )
function ZONE_POLYGON_BASE:IsPointVec2InZone( Vec2 )
self:F2( Vec2 )
local Next
local Prev
@ -581,8 +620,8 @@ function ZONE_POLYGON_BASE:IsPointVec2InZone( PointVec2 )
while Next <= #self.Polygon do
self:T( { Next, Prev, self.Polygon[Next], self.Polygon[Prev] } )
if ( ( ( self.Polygon[Next].y > PointVec2.y ) ~= ( self.Polygon[Prev].y > PointVec2.y ) ) and
( PointVec2.x < ( self.Polygon[Prev].x - self.Polygon[Next].x ) * ( PointVec2.y - self.Polygon[Next].y ) / ( self.Polygon[Prev].y - self.Polygon[Next].y ) + self.Polygon[Next].x )
if ( ( ( self.Polygon[Next].y > Vec2.y ) ~= ( self.Polygon[Prev].y > Vec2.y ) ) and
( Vec2.x < ( self.Polygon[Prev].x - self.Polygon[Next].x ) * ( Vec2.y - self.Polygon[Next].y ) / ( self.Polygon[Prev].y - self.Polygon[Next].y ) + self.Polygon[Next].x )
) then
InPolygon = not InPolygon
end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,7 @@ COPY /b Moose.lua + "Moose Create Static\Moose_Static_Loader.lua" Moose.
COPY /b Moose.lua + %1\Routines.lua Moose.lua
COPY /b Moose.lua + %1\Utils.lua Moose.lua
COPY /b Moose.lua + %1\Base.lua Moose.lua
COPY /b Moose.lua + %1\Object.lua Moose.lua
COPY /b Moose.lua + %1\Identifiable.lua Moose.lua
@ -81,8 +82,22 @@ COPY /b Moose.lua + %1\MissileTrainer.lua Moose.lua
COPY /b Moose.lua + %1\PatrolZone.lua Moose.lua
COPY /b Moose.lua + %1\AIBalancer.lua Moose.lua
COPY /b Moose.lua + %1\AirbasePolice.lua Moose.lua
COPY /b Moose.lua + %1\Detection.lua Moose.lua
COPY /b Moose.lua + %1\FAC.lua Moose.lua
COPY /b Moose.lua + %1\DetectionManager.lua Moose.lua
COPY /b Moose.lua + %1\StateMachine.lua Moose.lua
COPY /b Moose.lua + %1\Process.lua Moose.lua
COPY /b Moose.lua + %1\Process_Assign.lua Moose.lua
COPY /b Moose.lua + %1\Process_Route.lua Moose.lua
COPY /b Moose.lua + %1\Process_Smoke.lua Moose.lua
COPY /b Moose.lua + %1\Process_Destroy.lua Moose.lua
COPY /b Moose.lua + %1\Task.lua Moose.lua
COPY /b Moose.lua + %1\Task_SEAD.lua Moose.lua
COPY /b Moose.lua + %1\Task_CAS.lua Moose.lua
COPY /b Moose.lua + %1\Task_BAI.lua Moose.lua
COPY /b Moose.lua + "Moose Create Static\Moose_Trace_Off.lua" Moose.lua

View File

@ -1,5 +1,5 @@
local FACGroup = GROUP:FindByName( "FAC Group" )
local FACDetection = DETECTION_UNITGROUPS:New( FACGroup, 1000, 250 ):SmokeDetectedZones():FlareDetectedUnits()
local FACDetection = DETECTION_AREAS:New( FACGroup, 1000, 250 ):FlareDetectedZones():FlareDetectedUnits()

View File

@ -0,0 +1,17 @@
local Mission = MISSION:New( "Attack Detect Mission", "High", "Attack Detect Mission Briefing", coalition.side.RED )
local Scoring = SCORING:New( "Detect Demo" )
Mission:AddScoring( Scoring )
local FACSet = SET_GROUP:New():FilterPrefixes( "FAC" ):FilterCoalitions("red"):FilterStart()
local FACDetection = DETECTION_AREAS:New( FACSet, 10000, 3000 )
local AttackGroups = SET_GROUP:New():FilterCoalitions( "red" ):FilterPrefixes( "Attack" ):FilterStart()
local CommandCenter = GROUP:FindByName( "HQ" )
local TaskAssign = DETECTION_DISPATCHER:New( Mission, CommandCenter, AttackGroups, FACDetection )

View File

@ -2,7 +2,8 @@
local FACGroup = GROUP:FindByName( "FAC Group" )
local FACDetection = DETECTION_UNITGROUPS:New( FACGroup, 1000, 250 )
local FACClientSet = SET_CLIENT:New():FilterCoalitions( "blue" ):FilterStart()
local FACDetection = DETECTION_AREAS:New( FACGroup, 1000, 250 )
local SeadClientSet = SET_CLIENT:New():FilterCoalitions( "blue" ):FilterStart()
local DestroyClientSet = SET_CLIENT:New():FilterCoalitions( "blue" ):FilterStart()
local FACReporting = FAC_REPORTING:New( FACClientSet, FACDetection )
local FACReporting = FAC_REPORTING:New( FACClientSet, FACDetection )

View File

@ -0,0 +1,16 @@
local Mission = MISSION:New( 'SEAD Targets', "Strategic", "SEAD the enemy", coalition.side.RED )
local Scoring = SCORING:New( "SEAD" )
Mission:AddScoring( Scoring )
local SEADGroup = GROUP:FindByName( "Test SEAD" )
local TargetSet = SET_UNIT:New():FilterPrefixes( "US Hawk SR" ):FilterStart()
local TargetZone = ZONE:New( "Target Zone" )
local TaskSEAD = TASK_SEAD:New( Mission, TargetSet, TargetZone ):SetName( "SEAD Radars" ):AssignToGroup( SEADGroup )

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>
@ -102,15 +112,15 @@ CLIENTS should not be allowed to:</p>
<p>All the airbases on the caucasus map can be monitored using this class.
If you want to monitor specific airbases, you need to use the <a href="##(AIRBASEPOLICE_BASE).Monitor">AIRBASEPOLICE_BASE.Monitor</a>() method, which takes a table or airbase names.
The following names can be given:
* AnapaVityazevo
* Batumi
* Beslan
* Gelendzhik
* Gudauta
* Kobuleti
* KrasnodarCenter
* KrasnodarPashkovsky
* Krymsk
* AnapaVityazevo
* Batumi
* Beslan
* Gelendzhik
* Gudauta
* Kobuleti
* KrasnodarCenter
* KrasnodarPashkovsky
* Krymsk
* Kutaisi
* MaykopKhanskaya
* MineralnyeVody
@ -122,8 +132,17 @@ The following names can be given:
* Soganlug
* SukhumiBabushara
* TbilisiLochini
* Vaziani
</p>
* Vaziani</p>
<h1>3) <a href="AirbasePolice.html##(AIRBASEPOLICE_NEVADA)">AirbasePolice#AIRBASEPOLICE_NEVADA</a> class, extends <a href="AirbasePolice.html##(AIRBASEPOLICE_BASE)">AirbasePolice#AIRBASEPOLICE_BASE</a></h1>
<p>All the airbases on the NEVADA map can be monitored using this class.
If you want to monitor specific airbases, you need to use the <a href="##(AIRBASEPOLICE_BASE).Monitor">AIRBASEPOLICE_BASE.Monitor</a>() method, which takes a table or airbase names.
The following names can be given:
* Nellis
* McCarran
* Creech
* Groom Lake</p>
<h2>Global(s)</h2>
<table class="function_list">
@ -137,6 +156,12 @@ The following names can be given:
<td class="name" nowrap="nowrap"><a href="#AIRBASEPOLICE_CAUCASUS">AIRBASEPOLICE_CAUCASUS</a></td>
<td class="summary">
</td>
</tr>
<tr>
<td class="name" nowrap="nowrap"><a href="#AIRBASEPOLICE_NEVADA">AIRBASEPOLICE_NEVADA</a></td>
<td class="summary">
</td>
</tr>
</table>
@ -162,6 +187,28 @@ The following names can be given:
<td class="name" nowrap="nowrap"><a href="##(AIRBASEPOLICE_CAUCASUS).SetClient">AIRBASEPOLICE_CAUCASUS.SetClient</a></td>
<td class="summary">
</td>
</tr>
</table>
<h2><a id="#(AIRBASEPOLICE_NEVADA)">Type <code>AIRBASEPOLICE_NEVADA</code></a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap="nowrap"><a href="##(AIRBASEPOLICE_NEVADA).Airbases">AIRBASEPOLICE_NEVADA.Airbases</a></td>
<td class="summary">
</td>
</tr>
<tr>
<td class="name" nowrap="nowrap"><a href="##(AIRBASEPOLICE_NEVADA).ClassName">AIRBASEPOLICE_NEVADA.ClassName</a></td>
<td class="summary">
</td>
</tr>
<tr>
<td class="name" nowrap="nowrap"><a href="##(AIRBASEPOLICE_NEVADA).New">AIRBASEPOLICE_NEVADA:New(SetClient)</a></td>
<td class="summary">
<p>Creates a new AIRBASEPOLICE_NEVADA object.</p>
</td>
</tr>
</table>
@ -193,6 +240,20 @@ The following names can be given:
</dd>
</dl>
<dl class="function">
<dt>
<em><a href="##(AIRBASEPOLICE_NEVADA)">#AIRBASEPOLICE_NEVADA</a></em>
<a id="AIRBASEPOLICE_NEVADA" >
<strong>AIRBASEPOLICE_NEVADA</strong>
</a>
</dt>
<dd>
</dd>
</dl>
<h2><a id="#(AirbasePolice)" >Type <code>AirbasePolice</code></a></h2>
@ -244,6 +305,64 @@ The following names can be given:
</dd>
</dl>
<h2><a id="#(AIRBASEPOLICE_NEVADA)" >Type <code>AIRBASEPOLICE_NEVADA</code></a></h2>
<h3>Field(s)</h3>
<dl class="function">
<dt>
<em></em>
<a id="#(AIRBASEPOLICE_NEVADA).Airbases" >
<strong>AIRBASEPOLICE_NEVADA.Airbases</strong>
</a>
</dt>
<dd>
</dd>
</dl>
<dl class="function">
<dt>
<em>#string</em>
<a id="#(AIRBASEPOLICE_NEVADA).ClassName" >
<strong>AIRBASEPOLICE_NEVADA.ClassName</strong>
</a>
</dt>
<dd>
</dd>
</dl>
<dl class="function">
<dt>
<a id="#(AIRBASEPOLICE_NEVADA).New" >
<strong>AIRBASEPOLICE_NEVADA:New(SetClient)</strong>
</a>
</dt>
<dd>
<p>Creates a new AIRBASEPOLICE_NEVADA object.</p>
<h3>Parameter</h3>
<ul>
<li>
<p><code><em> SetClient </em></code>:
A SET_CLIENT object that will contain the CLIENT objects to be monitored if they follow the rules of the airbase.</p>
</li>
</ul>
<h3>Return value</h3>
<p><em><a href="##(AIRBASEPOLICE_NEVADA)">#AIRBASEPOLICE_NEVADA</a>:</em>
self</p>
</dd>
</dl>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>
@ -140,6 +150,8 @@ These tracing levels were defined to avoid bulks of tracing to be generated by l
<hr/>
<h3>Author: FlightControl</h3>
<h2>Global(s)</h2>
<table class="function_list">

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>
@ -269,24 +279,6 @@ If the DCS Unit object does not exist or is nil, the CLIENT methods will return
<td class="name" nowrap="nowrap"><a href="##(CLIENT).IsTransport">CLIENT:IsTransport()</a></td>
<td class="summary">
<p>Evaluates if the CLIENT is a transport.</p>
</td>
</tr>
<tr>
<td class="name" nowrap="nowrap"><a href="##(CLIENT).MenuMessages">CLIENT.MenuMessages</a></td>
<td class="summary">
</td>
</tr>
<tr>
<td class="name" nowrap="nowrap"><a href="##(CLIENT).MenuRouteMessageOff">CLIENT.MenuRouteMessageOff</a></td>
<td class="summary">
</td>
</tr>
<tr>
<td class="name" nowrap="nowrap"><a href="##(CLIENT).MenuRouteMessageOn">CLIENT.MenuRouteMessageOn</a></td>
<td class="summary">
</td>
</tr>
<tr>
@ -843,48 +835,6 @@ true if multi-seated.</p>
<p><em>#boolean:</em>
true is a transport.</p>
</dd>
</dl>
<dl class="function">
<dt>
<em></em>
<a id="#(CLIENT).MenuMessages" >
<strong>CLIENT.MenuMessages</strong>
</a>
</dt>
<dd>
</dd>
</dl>
<dl class="function">
<dt>
<em></em>
<a id="#(CLIENT).MenuRouteMessageOff" >
<strong>CLIENT.MenuRouteMessageOff</strong>
</a>
</dt>
<dd>
</dd>
</dl>
<dl class="function">
<dt>
<em></em>
<a id="#(CLIENT).MenuRouteMessageOn" >
<strong>CLIENT.MenuRouteMessageOn</strong>
</a>
</dt>
<dd>
</dd>
</dl>
<dl class="function">

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

View File

@ -44,9 +44,9 @@
<li><a href="DESTROYUNITTYPESTASK.html">DESTROYUNITTYPESTASK</a></li>
<li><a href="Database.html">Database</a></li>
<li><a href="Detection.html">Detection</a></li>
<li><a href="DetectionManager.html">DetectionManager</a></li>
<li><a href="Escort.html">Escort</a></li>
<li><a href="Event.html">Event</a></li>
<li><a href="Fac.html">Fac</a></li>
<li><a href="GOHOMETASK.html">GOHOMETASK</a></li>
<li><a href="Group.html">Group</a></li>
<li><a href="Identifiable.html">Identifiable</a></li>
@ -61,6 +61,9 @@
<li><a href="PatrolZone.html">PatrolZone</a></li>
<li><a href="Point.html">Point</a></li>
<li><a href="Positionable.html">Positionable</a></li>
<li><a href="Process.html">Process</a></li>
<li><a href="Process_CAS.html">Process_CAS</a></li>
<li><a href="Process_SEAD.html">Process_SEAD</a></li>
<li><a href="ROUTETASK.html">ROUTETASK</a></li>
<li><a href="STAGE.html">STAGE</a></li>
<li><a href="Scheduler.html">Scheduler</a></li>
@ -68,9 +71,16 @@
<li><a href="Sead.html">Sead</a></li>
<li><a href="Set.html">Set</a></li>
<li><a href="Spawn.html">Spawn</a></li>
<li><a href="StateMachine.html">StateMachine</a></li>
<li><a href="Static.html">Static</a></li>
<li><a href="StaticObject.html">StaticObject</a></li>
<li><a href="TASK.html">TASK</a></li>
<li><a href="Task.html">Task</a></li>
<li><a href="Task_Assign.html">Task_Assign</a></li>
<li><a href="Task_CAS.html">Task_CAS</a></li>
<li><a href="Task_Client_Menu.html">Task_Client_Menu</a></li>
<li><a href="Task_Route.html">Task_Route</a></li>
<li><a href="Task_SEAD.html">Task_SEAD</a></li>
<li><a href="Unit.html">Unit</a></li>
<li><a href="Zone.html">Zone</a></li>
<li><a href="env.html">env</a></li>

Some files were not shown because too many files have changed in this diff Show More