Updated detection algorithm

Now the detected sets are kept consistent to previous sets. New
algorithm developed. This is important to keep assigned tasks consistent
with the detected sets.
This commit is contained in:
FlightControl 2016-07-10 09:11:05 +02:00
parent 40a9c1f7d1
commit 17abcb7b7f
19 changed files with 812 additions and 51696 deletions

View File

@ -73,23 +73,26 @@
-- @type DETECTION_BASE -- @type DETECTION_BASE
-- @field Group#GROUP DetectionGroups The GROUP in the Forward Air Controller role. -- @field Group#GROUP DetectionGroups The GROUP in the Forward Air Controller role.
-- @field DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected. -- @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 #number DetectionRun
-- @extends Base#BASE -- @extends Base#BASE
DETECTION_BASE = { DETECTION_BASE = {
ClassName = "DETECTION_BASE", ClassName = "DETECTION_BASE",
DetectedSets = {},
DetectedObjects = {},
DetectionGroups = nil, DetectionGroups = nil,
DetectionRange = nil, DetectionRange = nil,
DetectedObjects = {},
DetectionRun = 0,
} }
--- @type DETECTION_BASE.DetectedSets --- @type DETECTION_BASE.DetectedObjects
-- @list <Set#SET_BASE> -- @list <#DETECTION_BASE.DetectedObject>
--- @type DETECTION_BASE.DetectedZones
-- @list <Zone#ZONE_BASE>
--- @type DETECTION_BASE.DetectedObject
-- @field #string Name
-- @field #boolean Visible
-- @field #string Type
-- @field #number Distance
-- @field #boolean Identified
--- DETECTION constructor. --- DETECTION constructor.
-- @param #DETECTION_BASE self -- @param #DETECTION_BASE self
@ -173,13 +176,19 @@ function DETECTION_BASE:InitDetectDLINK( DetectDLINK )
self.DetectDLINK = DetectDLINK self.DetectDLINK = DetectDLINK
end end
--- Gets the Detection group. --- Gets a detected object with a given name.
-- @param #DETECTION_BASE self -- @param #DETECTION_BASE self
-- @return Group#GROUP self -- @param #string ObjectName
function DETECTION_BASE:GetDetectionGroups() -- @return #DETECTION_BASE.DetectedObject
self:F2() function DETECTION_BASE:GetDetectedObject( ObjectName )
self:F( ObjectName )
return self.DetectionGroups if ObjectName then
local DetectedObject = self.DetectedObjects[ObjectName]
return DetectedObject
end
return nil
end end
--- Get the detected @{Set#SET_BASE}s. --- Get the detected @{Set#SET_BASE}s.
@ -214,13 +223,13 @@ function DETECTION_BASE:GetDetectedSet( Index )
return nil return nil
end end
--- Get the detected @{Zone}s. --- Get the detection Groups.
-- @param #DETECTION_BASE self -- @param #DETECTION_BASE self
-- @return #DETECTION_BASE.DetectedZones DetectedZones -- @return Group#GROUP
function DETECTION_BASE:GetDetectedZones() function DETECTION_BASE:GetDetectionGroups()
local DetectionZones = self.DetectedZones local DetectionGroups = self.DetectionGroups
return DetectionZones return DetectionGroups
end end
--- Make a DetectionSet table. This function will be overridden in the derived clsses. --- Make a DetectionSet table. This function will be overridden in the derived clsses.
@ -255,8 +264,7 @@ function DETECTION_BASE:_DetectionScheduler( SchedulerName )
self:F2( { SchedulerName } ) self:F2( { SchedulerName } )
self.DetectedObjects = {} self.DetectedObjects = {}
self.DetectedSets = {} self.DetectionRun = self.DetectionRun + 1
self.DetectedZones = {}
if self.DetectionGroups:IsAlive() then if self.DetectionGroups:IsAlive() then
local DetectionGroupsName = self.DetectionGroups:GetName() local DetectionGroupsName = self.DetectionGroups:GetName()
@ -286,7 +294,7 @@ function DETECTION_BASE:_DetectionScheduler( SchedulerName )
( DetectionDetectedObjectPositionVec3.z - DetectionGroupsPositionVec3.z )^2 ( DetectionDetectedObjectPositionVec3.z - DetectionGroupsPositionVec3.z )^2
) ^ 0.5 / 1000 ) ^ 0.5 / 1000
self:T( { DetectionGroupsName, DetectionDetectedObjectName, Distance } ) self:T2( { DetectionGroupsName, DetectionDetectedObjectName, Distance } )
if Distance <= self.DetectionRange then if Distance <= self.DetectionRange then
@ -297,6 +305,7 @@ function DETECTION_BASE:_DetectionScheduler( SchedulerName )
self.DetectedObjects[DetectionDetectedObjectName].Visible = DetectionDetectedTarget.visible self.DetectedObjects[DetectionDetectedObjectName].Visible = DetectionDetectedTarget.visible
self.DetectedObjects[DetectionDetectedObjectName].Type = DetectionDetectedTarget.type self.DetectedObjects[DetectionDetectedObjectName].Type = DetectionDetectedTarget.type
self.DetectedObjects[DetectionDetectedObjectName].Distance = DetectionDetectedTarget.distance self.DetectedObjects[DetectionDetectedObjectName].Distance = DetectionDetectedTarget.distance
self.DetectedObjects[DetectionDetectedObjectName].Identified = false -- This flag is used to control identification.
else else
-- if beyond the DetectionRange then nullify... -- if beyond the DetectionRange then nullify...
if self.DetectedObjects[DetectionDetectedObjectName] then if self.DetectedObjects[DetectionDetectedObjectName] then
@ -324,27 +333,26 @@ function DETECTION_BASE:_DetectionScheduler( SchedulerName )
end end
end end
--- @type DETECTION_UNITGROUPS.DetectedSets
-- @list <Set#SET_UNIT>
--
--- @type DETECTION_UNITGROUPS.DetectedZones
-- @list <Zone#ZONE_UNIT>
--
--- DETECTION_UNITGROUPS class --- DETECTION_UNITGROUPS class
-- @type DETECTION_UNITGROUPS -- @type DETECTION_UNITGROUPS
-- @param DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target. -- @field 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.DetectedAreas DetectedAreas A list of areas containing the set of @{Unit}s, @{Zone}s, the center @{Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
-- @field #DETECTION_UNITGROUPS.DetectedZones DetectedZones A list of @{Zone#ZONE_UNIT}s containing the zones of the reference detected units.
-- @extends Detection#DETECTION_BASE -- @extends Detection#DETECTION_BASE
DETECTION_UNITGROUPS = { DETECTION_UNITGROUPS = {
ClassName = "DETECTION_UNITGROUPS", ClassName = "DETECTION_UNITGROUPS",
DetectedZones = {}, DetectedAreas = { n = 0 },
DetectionZoneRange = nil,
} }
--- @type DETECTION_UNITGROUPS.DetectedAreas
-- @list <#DETECTION_UNITGROUPS.DetectedArea>
--- @type DETECTION_UNITGROUPS.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 #number AreaID -- The identifier of the detected area.
--- DETECTION_UNITGROUPS constructor. --- DETECTION_UNITGROUPS constructor.
@ -357,6 +365,7 @@ function DETECTION_UNITGROUPS:New( DetectionGroups, DetectionRange, DetectionZon
-- Inherits from DETECTION_BASE -- Inherits from DETECTION_BASE
local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionGroups, DetectionRange ) ) local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionGroups, DetectionRange ) )
self.DetectionZoneRange = DetectionZoneRange self.DetectionZoneRange = DetectionZoneRange
self:Schedule( 10, 30 ) self:Schedule( 10, 30 )
@ -364,31 +373,73 @@ function DETECTION_UNITGROUPS:New( DetectionGroups, DetectionRange, DetectionZon
return self return self
end end
--- Get the detected @{Zone#ZONE_UNIT}s. --- Add a detected @{#DETECTION_UNITGROUPS.DetectedArea}.
-- @param #DETECTION_UNITGROUPS self -- @param Set#SET_UNIT Set -- The Set of Units in the detected area.
-- @return #DETECTION_UNITGROUPS.DetectedZones DetectedZones -- @param Zone#ZONE_UNIT Zone -- The Zone of the detected area.
function DETECTION_UNITGROUPS:GetDetectedZones() -- @return #DETECTION_UNITGROUPS.DetectedArea DetectedArea
function DETECTION_UNITGROUPS:AddDetectedArea( Set, Zone )
local DetectedZones = self.DetectedZones local DetectedAreas = self:GetDetectedAreas()
return DetectedZones DetectedAreas.n = self:GetDetectedAreaCount() + 1
DetectedAreas[DetectedAreas.n] = {}
local DetectedArea = DetectedAreas[DetectedAreas.n]
DetectedArea.Set = Set
DetectedArea.Zone = Zone
DetectedArea.AreaID = #DetectedAreas
return DetectedArea
end end
--- Get the amount of @{Zone#ZONE_UNIT}s with detected units. --- Remove a detected @{#DETECTION_UNITGROUPS.DetectedArea} with a given Index.
-- @param #DETECTION_UNITGROUPS self -- @param #DETECTION_UNITGROUPS self
-- @return #number Count -- @param #number Index The Index of the detection are to be removed.
function DETECTION_UNITGROUPS:GetDetectedZoneCount() -- @return #nil
function DETECTION_UNITGROUPS:RemoveDetectedArea( Index )
local DetectedZoneCount = #self.DetectedZones local DetectedAreas = self:GetDetectedAreas()
return DetectedZoneCount local DetectedAreaCount = self:GetDetectedAreaCount()
DetectedAreas[Index] = nil
DetectedAreas.n = DetectedAreas.n - 1
return nil
end end
--- Get a SET of detected objects using a given numeric index.
--- Get the detected @{#DETECTION_UNITGROUPS.DetectedAreas}.
-- @param #DETECTION_UNITGROUPS self
-- @return #DETECTION_UNITGROUPS.DetectedAreas DetectedAreas
function DETECTION_UNITGROUPS:GetDetectedAreas()
local DetectedAreas = self.DetectedAreas
return DetectedAreas
end
--- Get the amount of @{#DETECTION_UNITGROUPS.DetectedAreas}.
-- @param #DETECTION_UNITGROUPS self
-- @return #number DetectedAreaCount
function DETECTION_UNITGROUPS:GetDetectedAreaCount()
local DetectedAreaCount = self.DetectedAreas.n
return DetectedAreaCount
end
--- Get the @{Set#SET_UNIT} of a detecttion area using a given numeric index.
-- @param #DETECTION_UNITGROUPS self -- @param #DETECTION_UNITGROUPS self
-- @param #number Index -- @param #number Index
-- @return Zone#ZONE_UNIT -- @return Set#SET_UNIT DetectedSet
function DETECTION_UNITGROUPS:GetDetectedSet( 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_UNITGROUPS self
-- @param #number Index
-- @return Zone#ZONE_UNIT DetectedZone
function DETECTION_UNITGROUPS:GetDetectedZone( Index ) function DETECTION_UNITGROUPS:GetDetectedZone( Index )
local DetectedZone = self.DetectedZones[Index] local DetectedZone = self.DetectedAreas[Index].Zone
if DetectedZone then if DetectedZone then
return DetectedZone return DetectedZone
end end
@ -396,6 +447,7 @@ function DETECTION_UNITGROUPS:GetDetectedZone( Index )
return nil return nil
end end
--- Smoke the detected units --- Smoke the detected units
-- @param #DETECTION_UNITGROUPS self -- @param #DETECTION_UNITGROUPS self
-- @return #DETECTION_UNITGROUPS self -- @return #DETECTION_UNITGROUPS self
@ -443,34 +495,126 @@ end
function DETECTION_UNITGROUPS:CreateDetectionSets() function DETECTION_UNITGROUPS:CreateDetectionSets()
self:F2() self:F2()
for DetectedUnitName, DetectedUnitData in pairs( self.DetectedObjects ) do -- First go through all detected sets, and check if there are new detected units, match all existing detected units and identify undetected units.
self:T( DetectedUnitData.Name ) -- Regroup when needed, split groups when needed.
local DetectedUnit = UNIT:FindByName( DetectedUnitData.Name ) -- Unit#UNIT for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do
if DetectedUnit and DetectedUnit:IsAlive() then
self:T( DetectedUnit:GetName() ) local DetectedArea = DetectedAreaData -- #DETECTION_UNITGROUPS.DetectedArea
if #self.DetectedSets == 0 then if DetectedArea then
self:T( { "Adding Unit Set #", 1 } )
self.DetectedZones[1] = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) local DetectedSet = DetectedArea.Set
self.DetectedSets[1] = SET_UNIT:New() local DetectedZone = DetectedArea.Zone
self.DetectedSets[1]:AddUnit( DetectedUnit )
-- first test if the center unit is detected in the detection area.
local AreaExists = false -- This flag will determine of the detected area is still existing.
local DetectedObject = self:GetDetectedObject( DetectedArea.Zone.ZoneUNIT.UnitName )
self:T( DetectedObject )
if DetectedObject then
DetectedObject.Identified = true
AreaExists = true
self:T( { DetectedArea = DetectedArea.AreaID, "Detected Center Unit " .. DetectedArea.Zone.ZoneUNIT.UnitName } )
else else
local AddedToSet = false -- 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.
for DetectedZoneIndex = 1, #self.DetectedZones do -- First remove the center unit from the set.
self:T( "Detected Unit Set #" .. DetectedZoneIndex ) DetectedSet:RemoveUnitsByName( DetectedArea.Zone.ZoneUNIT.UnitName )
local DetectedUnitSet = self.DetectedSets[DetectedZoneIndex] -- Set#SET_BASE self:T( { DetectedArea = DetectedArea.AreaID, "Removed Center Unit " .. DetectedArea.Zone.ZoneUNIT.UnitName } )
local DetectedZone = self.DetectedZones[DetectedZoneIndex] -- Zone#ZONE_UNIT for DetectedUnitName, DetectedUnitData in pairs( DetectedSet:GetSet() ) do
if DetectedUnit:IsInZone( DetectedZone ) then local DetectedUnit = DetectedUnitData -- Unit#UNIT
self:T( "Adding to Unit Set #" .. DetectedZoneIndex ) local DetectedObject = self:GetDetectedObject( DetectedUnit.UnitName )
DetectedUnitSet:AddUnit( DetectedUnit ) if DetectedObject then
AddedToSet = true if DetectedObject.Identified == false and DetectedUnit:IsAlive() then
DetectedObject.Identified = true
AreaExists = true
-- Assign the Unit as the new center unit of the detected area.
DetectedArea.Zone = ZONE_UNIT:New( DetectedUnit:GetName(), DetectedUnit, self.DetectionZoneRange )
self:T( { DetectedArea = DetectedArea.AreaID, "New Center Unit " .. DetectedArea.Zone.ZoneUNIT.UnitName } )
break
end
end end
end end
if AddedToSet == false then end
local DetectedZoneIndex = #self.DetectedZones + 1
self:T( "Adding new zone #" .. DetectedZoneIndex ) -- Now we've determined the center unit of the area, now we can iterate the units in the detected area.
self.DetectedZones[DetectedZoneIndex] = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange ) -- Note that the position of the area may have moved due to the center unit repositioning.
self.DetectedSets[DetectedZoneIndex] = SET_UNIT:New() -- 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.
self.DetectedSets[DetectedZoneIndex]:AddUnit( DetectedUnit ) if AreaExists then
-- ok, we found the center unit of the area, now iterate through the detected area set and see which units are still within the center unit zone ...
-- Those units within the zone are flagged as Identified.
-- If a unit was not found in the set, remove it from the set. This may be added later to other existing or new sets.
for DetectedUnitName, DetectedUnitData in pairs( DetectedSet:GetSet() ) do
local DetectedUnit = DetectedUnitData -- Unit#UNIT
local DetectedObject = self:GetDetectedObject( DetectedUnit:GetName() )
if DetectedObject then
if DetectedObject.Identified == false then
if DetectedUnit:IsInZone( DetectedZone ) then
DetectedObject.Identified = true
self:T( { DetectedArea = DetectedArea.AreaID, "Unit in zone " .. DetectedUnit.UnitName } )
else
-- Not anymore in the zone. Remove from the set.
DetectedSet:Remove( DetectedUnitName )
self:T( { DetectedArea = DetectedArea.AreaID, "Unit not in zone " .. DetectedUnit.UnitName } )
end
end
else
-- The detected object has not been found, delete from the Set!
DetectedSet:Remove( DetectedUnitName )
self:T( { DetectedArea = DetectedArea.AreaID, "Unit not found " .. DetectedUnit.UnitName } )
end
end
else
self:T( { DetectedArea = DetectedArea.AreaID, "Removed detected area " } )
self:RemoveDetectedArea( DetectedAreaID )
end
end
end
-- 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 = DetectedObjectData -- #DETECTION_BASE.DetectedObject
if DetectedObject.Identified == false then
-- We found an unidentified unit outside of any existing detection area.
local DetectedUnit = UNIT:FindByName( DetectedObjectData.Name ) -- Unit#UNIT
if DetectedUnit and DetectedUnit:IsAlive() then
self:T( { "Search for " .. DetectedObjectData.Name, DetectedObjectData.Identified } )
local AddedToDetectionArea = false
for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do
local DetectedArea = DetectedAreaData -- #DETECTION_UNITGROUPS.DetectedArea
if DetectedArea then
self:T( "Detection Area #" .. DetectedArea.AreaID )
local DetectedSet = DetectedArea.Set
local DetectedZone = DetectedArea.Zone -- Zone#ZONE_UNIT
if DetectedUnit:IsInZone( DetectedZone ) then
DetectedSet:AddUnit( DetectedUnit )
AddedToDetectionArea = true
DetectedObject.Identified = true
self:T( "Detection Area #" .. DetectedArea.AreaID .. " added unit " .. DetectedUnit.UnitName )
end
end
end
if AddedToDetectionArea == false then
-- New detection area
local DetectedArea = self:AddDetectedArea(
SET_UNIT:New(),
ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange )
)
self:T( { "Added Detection Area #", DetectedArea.AreaID } )
DetectedArea.Set:AddUnit( DetectedUnit )
self:T( "Detection Area #" .. DetectedArea.AreaID .. " added unit " .. DetectedUnit.UnitName )
DetectedObject.Identified = true
end end
end end
end end
@ -478,14 +622,17 @@ function DETECTION_UNITGROUPS:CreateDetectionSets()
-- Now all the tests should have been build, now make some smoke and flares... -- Now all the tests should have been build, now make some smoke and flares...
for DetectedZoneIndex = 1, #self.DetectedZones do for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do
local DetectedUnitSet = self.DetectedSets[DetectedZoneIndex] -- Set#SET_BASE
local DetectedZone = self.DetectedZones[DetectedZoneIndex] -- Zone#ZONE_UNIT
self:T( "Detected Set #" .. DetectedZoneIndex ) local DetectedArea = DetectedAreaData -- #DETECTION_UNITGROUPS.DetectedArea
DetectedUnitSet:ForEachUnit( local DetectedSet = DetectedArea.Set
local DetectedZone = DetectedArea.Zone
DetectedZone.ZoneUNIT:SmokeRed()
DetectedSet:ForEachUnit(
--- @param Unit#UNIT DetectedUnit --- @param Unit#UNIT DetectedUnit
function( DetectedUnit ) function( DetectedUnit )
self:T( DetectedUnit:GetName() ) self:T( "Detected Set #" .. DetectedArea.AreaID .. ":" .. DetectedUnit:GetName() )
if self._FlareDetectedUnits then if self._FlareDetectedUnits then
DetectedUnit:FlareRed() DetectedUnit:FlareRed()
end end

View File

@ -1,44 +1,45 @@
--- This module contains the FAC classes. --- This module contains the DETECTION_MANAGER class and derived classes.
-- @module DetectionManager
-- --
-- === -- ===
-- --
-- 1) @{Fac#DETECTION_MANAGER} class, extends @{Base#BASE} -- 1) @{DetectionManager#DETECTION_MANAGER} class, extends @{Base#BASE}
-- ============================================== -- ====================================================================
-- The @{Fac#DETECTION_MANAGER} class defines the core functions to report detected objects to groups. -- 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. -- 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: -- 1.1) DETECTION_MANAGER constructor:
-- ---------------------------- -- -----------------------------------
-- * @{Fac#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance. -- * @{DetectionManager#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance.
-- --
-- 1.2) DETECTION_MANAGER reporting: -- 1.2) DETECTION_MANAGER reporting:
-- ------------------------ -- ---------------------------------
-- Derived DETECTION_MANAGER classes will reports detected units using the method @{Fac#DETECTION_MANAGER.ReportDetected}(). This method implements polymorphic behaviour. -- 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 @{Fac#DETECTION_MANAGER.SetReportInterval}(). -- 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 @{Fac#DETECTION_MANAGER.SetReportDisplayTime}(). -- To control how long a reporting message is displayed, use @{DetectionManager#DETECTION_MANAGER.SetReportDisplayTime}().
-- Derived classes need to implement the method @{Fac#DETECTION_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report. -- 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 @{Fac#DETECTION_MANAGER.StartReporting}() and @{Fac#DETECTION_MANAGER.StopReporting}() respectively. -- 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 @{Fac#DETECTION_MANAGER#ReportNow}(). -- 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. -- The default reporting interval is every 60 seconds. The reporting messages are displayed 15 seconds.
-- --
-- === -- ===
-- --
-- 2) @{Fac#FAC_REPORTING} class, extends @{Fac#DETECTION_MANAGER} -- 2) @{DetectionManager#FAC_REPORTING} class, extends @{DetectionManager#DETECTION_MANAGER}
-- ====================================================== -- ======================================================
-- The @{Fac#FAC_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{Fac#DETECTION_MANAGER} class. -- The @{DetectionManager#FAC_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{DetectionManager#DETECTION_MANAGER} class.
-- --
-- 2.1) FAC_REPORTING constructor: -- 2.1) FAC_REPORTING constructor:
-- ------------------------------- -- -------------------------------
-- The @{Fac#FAC_REPORTING.New}() method creates a new FAC_REPORTING instance. -- The @{DetectionManager#FAC_REPORTING.New}() method creates a new FAC_REPORTING instance.
-- --
-- === -- ===
-- --
-- @module Fac -- ### Contributions - Mechanic, Prof_Hilactic, FlightControl : Concept & Testing
-- @author Mechanic, Prof_Hilactic, FlightControl : Concept & Testing -- ### Author - FlightControl : Framework Design & Programming
-- @author FlightControl : Design & Programming --
@ -102,47 +103,15 @@ function DETECTION_MANAGER:GetReportDisplayTime()
return self._ReportDisplayTime return self._ReportDisplayTime
end end
--- Creates a string of the detected items in a @{Set}.
-- @param #DETECTION_MANAGER self
-- @param Set#SET_BASE DetectedSets The detected Sets created by the @{Detection#DETECTION_BASE} object.
-- @return #DETECTION_MANAGER self
function DETECTION_MANAGER:GetDetectedItemsText( DetectedSet )
self:F2()
local MT = {} -- Message Text
local UnitTypes = {}
for DetectedUnitID, DetectedUnitData in pairs( DetectedSet:GetSet() ) do
local DetectedUnit = DetectedUnitData -- Unit#UNIT
local UnitType = DetectedUnit:GetTypeName()
if not UnitTypes[UnitType] then
UnitTypes[UnitType] = 1
else
UnitTypes[UnitType] = UnitTypes[UnitType] + 1
end
end
for UnitTypeID, UnitType in pairs( UnitTypes ) do
MT[#MT+1] = UnitType .. " of " .. UnitTypeID
end
local MessageText = table.concat( MT, ", " )
return MessageText
end
--- Reports the detected items to the @{Set#SET_GROUP}. --- Reports the detected items to the @{Set#SET_GROUP}.
-- @param #DETECTION_MANAGER self -- @param #DETECTION_MANAGER self
-- @param Set#SET_BASE DetectedSets The detected Sets created by the @{Detection#DETECTION_BASE} object. -- @param Detection#DETECTION_BASE Detection
-- @return #DETECTION_MANAGER self -- @return #DETECTION_MANAGER self
function DETECTION_MANAGER:ReportDetected( DetectedSets ) function DETECTION_MANAGER:ReportDetected( Detection )
self:F2() self:F2()
end end
--- Schedule the FAC reporting. --- Schedule the FAC reporting.
@ -157,7 +126,7 @@ function DETECTION_MANAGER:Schedule( DelayTime, ReportInterval )
self:SetReportInterval( ReportInterval ) self:SetReportInterval( ReportInterval )
self.FacScheduler = SCHEDULER:New(self, self._FacScheduler, { self, "Fac" }, self._ScheduleDelayTime, self._ReportInterval ) self.FacScheduler = SCHEDULER:New(self, self._FacScheduler, { self, "DetectionManager" }, self._ScheduleDelayTime, self._ReportInterval )
return self return self
end end
@ -170,9 +139,7 @@ function DETECTION_MANAGER:_FacScheduler( SchedulerName )
--- @param Group#GROUP Group --- @param Group#GROUP Group
function( Group ) function( Group )
if Group:IsAlive() then if Group:IsAlive() then
local DetectedSets = self.Detection:GetDetectedSets() return self:ProcessDetected( Group, self.Detection )
local DetectedZones =self.Detection:GetDetectedZones()
return self:ProcessDetected( Group, DetectedSets, DetectedZones )
end end
end end
) )
@ -195,7 +162,7 @@ FAC_REPORTING = {
--- FAC_REPORTING constructor. --- FAC_REPORTING constructor.
-- @param #FAC_REPORTING self -- @param #FAC_REPORTING self
-- @param Set#SET_GROUP SetGroup -- @param Set#SET_GROUP SetGroup
-- @param Detection#DETECTION_BASE Detection -- @param Detection#DETECTION_UNITGROUPS Detection
-- @return #FAC_REPORTING self -- @return #FAC_REPORTING self
function FAC_REPORTING:New( SetGroup, Detection ) function FAC_REPORTING:New( SetGroup, Detection )
@ -206,22 +173,51 @@ function FAC_REPORTING:New( SetGroup, Detection )
return self return self
end end
--- Creates a string of the detected items in a @{Detection}.
-- @param #DETECTION_MANAGER self
-- @param Set#SET_UNIT DetectedSet The detected Set created by the @{Detection#DETECTION_BASE} object.
-- @return #DETECTION_MANAGER self
function FAC_REPORTING:GetDetectedItemsText( DetectedSet )
self:F2()
local MT = {} -- Message Text
local UnitTypes = {}
for DetectedUnitID, DetectedUnitData in pairs( DetectedSet:GetSet() ) do
local DetectedUnit = DetectedUnitData -- Unit#UNIT
local UnitType = DetectedUnit:GetTypeName()
if not UnitTypes[UnitType] then
UnitTypes[UnitType] = 1
else
UnitTypes[UnitType] = UnitTypes[UnitType] + 1
end
end
for UnitTypeID, UnitType in pairs( UnitTypes ) do
MT[#MT+1] = UnitType .. " of " .. UnitTypeID
end
return table.concat( MT, ", " )
end
--- Reports the detected items to the @{Set#SET_GROUP}. --- Reports the detected items to the @{Set#SET_GROUP}.
-- @param #FAC_REPORTING self -- @param #FAC_REPORTING self
-- @param Group#GROUP Group The @{Group} object to where the report needs to go. -- @param Group#GROUP Group The @{Group} object to where the report needs to go.
-- @param Set#SET_BASE DetectedSets The detected Sets created by the @{Detection#DETECTION_BASE} object. -- @param Detection#DETECTION_UNITGROUPS Detection The detection created by the @{Detection#DETECTION_BASE} object.
-- @return #boolean Return true if you want the reporting to continue... false will cancel the reporting loop. -- @return #boolean Return true if you want the reporting to continue... false will cancel the reporting loop.
function FAC_REPORTING:ProcessDetected( Group, DetectedSets, DetectedZones ) function FAC_REPORTING:ProcessDetected( Group, Detection )
self:F2( Group ) self:F2( Group )
self:E( Group ) self:E( Group )
local DetectedMsg = {} local DetectedMsg = {}
for DetectedUnitSetID, DetectedUnitSet in pairs( DetectedSets ) do for DetectedAreaID, DetectedAreaData in pairs( Detection:GetDetectedAreas() ) do
local UnitSet = DetectedUnitSet -- Set#SET_UNIT local DetectedArea = DetectedAreaData -- Detection#DETECTION_UNITGROUPS.DetectedArea
DetectedMsg[#DetectedMsg+1] = " - Group #" .. DetectedUnitSetID .. ": " .. self:GetDetectedItemsText( UnitSet ) DetectedMsg[#DetectedMsg+1] = " - Group #" .. DetectedAreaID .. ": " .. self:GetDetectedItemsText( DetectedArea.Set )
end end
local FACGroup = self.Detection:GetDetectionGroups() local FACGroup = Detection:GetDetectionGroups()
FACGroup:MessageToGroup( "Reporting detected target groups:\n" .. table.concat( DetectedMsg, "\n" ), self:GetReportDisplayTime(), Group ) FACGroup:MessageToGroup( "Reporting detected target groups:\n" .. table.concat( DetectedMsg, "\n" ), self:GetReportDisplayTime(), Group )
return true return true
@ -236,7 +232,7 @@ end
-- @field Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects. -- @field Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects.
-- @field Mission#MISSION Mission -- @field Mission#MISSION Mission
-- @field Group#GROUP CommandCenter -- @field Group#GROUP CommandCenter
-- @extends #DETECTION_MANAGER -- @extends DetectionManager#DETECTION_MANAGER
TASK_DISPATCHER = { TASK_DISPATCHER = {
ClassName = "TASK_DISPATCHER", ClassName = "TASK_DISPATCHER",
Mission = nil, Mission = nil,
@ -264,13 +260,106 @@ function TASK_DISPATCHER:New( Mission, CommandCenter, SetGroup, Detection )
end end
--- Creates a SEAD task when there are targets for it.
-- @param #TASK_DISPATCHER self
-- @param Mission#MISSION Mission
-- @param Detection#DETECTION_UNITGROUPS.DetectedArea DetectedArea
-- @return #string Message explaining which task was added.
function TASK_DISPATCHER:EvaluateTaskSEAD( Mission, DetectedArea )
self:F( { Mission, DetectedArea.AreaID } )
MT = {}
local DetectedSet = DetectedArea.Set
local DetectedZone = DetectedArea.Zone
-- Determine if the set has radar targets. If it does, construct a SEAD task.
local RadarCount = DetectedSet:HasRadar( Unit.RadarType.AS )
DetectedArea.Tasks = DetectedArea.Tasks or {}
if RadarCount > 0 then
if not DetectedArea.Tasks.SEADTask then
local Task = TASK_SEAD:New( Mission, DetectedSet, DetectedZone )
self.Mission:AddTask( Task )
MT[#MT+1] = "SEAD"
DetectedArea.Tasks.SEADTask = Task
end
else
if DetectedArea.Tasks.SEADTask then
-- Abort Task
end
end
return table.concat( MT, "," )
end
--- Creates a CAS task when there are targets for it.
-- @param #TASK_DISPATCHER self
-- @param Mission#MISSION Mission
-- @param Detection#DETECTION_UNITGROUPS.DetectedArea DetectedArea
-- @return #string Message explaining which task was added.
function TASK_DISPATCHER:EvaluateTaskCAS( Mission, DetectedArea )
self:F2( { Mission, DetectedArea.AreaID } )
MT = {}
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()
DetectedArea.Tasks = DetectedArea.Tasks or {}
if GroundUnitCount > 0 then
if not DetectedArea.Tasks.CASTask then
local Task = TASK_CAS:New( Mission, DetectedSet , DetectedZone )
self.Mission:AddTask( Task )
MT[#MT+1] = "CAS"
DetectedArea.Tasks.CASTask = Task
end
else
if DetectedArea.Tasks.CASTask then
-- Abort Mission
end
end
return table.concat( MT, "," )
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 TASK_DISPATCHER:GetDetectedItemsText( DetectedSet )
self:F2()
local MT = {} -- Message Text
local UnitTypes = {}
for DetectedUnitID, DetectedUnitData in pairs( DetectedSet:GetSet() ) do
local DetectedUnit = DetectedUnitData -- Unit#UNIT
local UnitType = DetectedUnit:GetTypeName()
if not UnitTypes[UnitType] then
UnitTypes[UnitType] = 1
else
UnitTypes[UnitType] = UnitTypes[UnitType] + 1
end
end
for UnitTypeID, UnitType in pairs( UnitTypes ) do
MT[#MT+1] = UnitType .. " of " .. UnitTypeID
end
return table.concat( MT, ", " )
end
--- Assigns tasks in relation to the detected items to the @{Set#SET_GROUP}. --- Assigns tasks in relation to the detected items to the @{Set#SET_GROUP}.
-- @param #TASK_DISPATCHER self -- @param #TASK_DISPATCHER self
-- @param Group#GROUP Group The @{Group} object to where the report needs to go. -- @param Group#GROUP Group The @{Group} object to where the report needs to go.
-- @param #table DetectedSets The detected Sets created by the @{Detection#DETECTION_BASE} object. -- @param Detection#DETECTION_UNITGROUPS Detection The detection created by the @{Detection#DETECTION_UNITGROUPS} object.
-- @param #table DetectedZones The detected Zones cretaed by the @{Detection#DETECTION_BASE} object.
-- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop. -- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop.
function TASK_DISPATCHER:ProcessDetected( TaskGroup, DetectedSets, DetectedZones ) function TASK_DISPATCHER:ProcessDetected( TaskGroup, Detection )
self:F2( TaskGroup ) self:F2( TaskGroup )
local DetectedMsg = {} local DetectedMsg = {}
@ -281,33 +370,31 @@ function TASK_DISPATCHER:ProcessDetected( TaskGroup, DetectedSets, DetectedZones
self:E( TaskGroup ) self:E( TaskGroup )
--- First we need to the detected targets. --- First we need to the detected targets.
for DetectedID, DetectedUnitSet in pairs( DetectedSets ) do for DetectedAreaID, DetectedAreaData in ipairs( Detection:GetDetectedAreas() ) do
local UnitSet = DetectedUnitSet -- Set#SET_UNIT local DetectedArea = DetectedAreaData -- Detection#DETECTION_UNITGROUPS.DetectedArea
local TargetSetUnit = DetectedArea.Set
local MT = {} -- Message Text local MT = {} -- Message Text
local UnitTypes = {} local UnitTypes = {}
local TargetZone = DetectedArea.Zone -- Zone#ZONE_BASE
Detection:FlareDetectedZones()
Detection:FlareDetectedUnits()
for DetectedUnitID, DetectedUnitData in pairs( UnitSet:GetSet() ) do for DetectedUnitID, DetectedUnitData in pairs( TargetSetUnit:GetSet() ) do
local DetectedUnit = DetectedUnitData -- Unit#UNIT local TargetUnit = DetectedUnitData -- Unit#UNIT
self:E( DetectedUnit ) self:E( TargetUnit )
local DetectedUnitName = DetectedUnit:GetName() local TargetUnitName = TargetUnit:GetName()
local UnitType = DetectedUnit:GetTypeName() local TargetUnitType = TargetUnit:GetTypeName()
-- Determine if the set has radar targets. If it does, construct a SEAD task. MT[#MT+1] = self:EvaluateTaskSEAD( self.Mission, DetectedArea )
local RadarCount = UnitSet:HasRadar( Unit.RadarType.AS ) MT[#MT+1] = self:EvaluateTaskCAS( self.Mission, DetectedArea )
if RadarCount > 0 then
local DetectedZone = DetectedZones[DetectedID]
local Task = TASK_SEAD:New( self.Mission, UnitSet, DetectedZone, UnitSet )
self.Mission:AddTask( Task )
MT[#MT+1] = "SEAD task added."
end
end end
DetectedMsg[#DetectedMsg+1] = " - Group #" .. DetectedID .. ": " .. self:GetDetectedItemsText( UnitSet ) .. ". " .. table.concat( MT, "," ) DetectedMsg[#DetectedMsg+1] = " - Group #" .. DetectedAreaID .. ": " .. self:GetDetectedItemsText( TargetSetUnit ) .. ". " .. table.concat( MT, "," ) .. " tasks addded."
end end
self.CommandCenter:MessageToGroup( "Reporting tasks for target groups:\n" .. table.concat( DetectedMsg, "\n" ), self:GetReportDisplayTime(), TaskGroup ) self.CommandCenter:MessageToGroup( "Reporting tasks for target groups:\n" .. table.concat( DetectedMsg, "\n" ), self:GetReportDisplayTime(), TaskGroup )
self.Mission:FillMissionMenu( TaskGroup ) self.Mission:CreateTaskMenus( TaskGroup )
return true return true
end end

View File

@ -112,7 +112,7 @@ end
--- Fill mission menu for the Group. --- Fill mission menu for the Group.
-- @param #MISSION self -- @param #MISSION self
-- @return #MISSION self -- @return #MISSION self
function MISSION:FillMissionMenu( TaskGroup ) function MISSION:CreateTaskMenus( TaskGroup )
local MissionMenu = self:GetMissionMenu() local MissionMenu = self:GetMissionMenu()
local TaskMenus = self.TaskMenus local TaskMenus = self.TaskMenus
@ -142,6 +142,9 @@ function MISSION:FillMissionMenu( TaskGroup )
end end
TaskMenus[TaskMenuID].MenuType = TaskTypeMenus[TaskType] TaskMenus[TaskMenuID].MenuType = TaskTypeMenus[TaskType]
if TaskMenus[TaskMenuID].Menu then
TaskMenus[TaskMenuID].Menu:Remove()
end
TaskMenus[TaskMenuID].Menu = MENU_GROUP_COMMAND:New( TaskGroup, TaskName .. "." .. TaskID, TaskMenus[TaskMenuID].MenuType, self.AssignTaskToGroup, { self = self, Task = Task, TaskGroup = TaskGroup } ) TaskMenus[TaskMenuID].Menu = MENU_GROUP_COMMAND:New( TaskGroup, TaskName .. "." .. TaskID, TaskMenus[TaskMenuID].MenuType, self.AssignTaskToGroup, { self = self, Task = Task, TaskGroup = TaskGroup } )
end end

View File

@ -45,13 +45,14 @@ Include.File( "PatrolZone" )
Include.File( "AIBalancer" ) Include.File( "AIBalancer" )
Include.File( "AirbasePolice" ) Include.File( "AirbasePolice" )
Include.File( "Detection" ) Include.File( "Detection" )
Include.File( "FAC" ) Include.File( "DetectionManager" )
Include.File( "StateMachine" ) Include.File( "StateMachine" )
Include.File( "Process" ) Include.File( "Process" )
Include.File( "Process_Assign" ) Include.File( "Process_Assign" )
Include.File( "Process_Route" ) Include.File( "Process_Route" )
Include.File( "Process_SEAD" ) Include.File( "Process_SEAD" )
Include.File( "Task" ) Include.File( "Task" )
Include.File( "Task_CAS" )
Include.File( "Task_SEAD" ) Include.File( "Task_SEAD" )
-- The order of the declarations is important here. Don't touch it. -- The order of the declarations is important here. Don't touch it.

View File

@ -0,0 +1,142 @@
--- @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( Task, ProcessUnit ) ) -- #PROCESS_CAS
self.TargetSetUnit = TargetSetUnit
self.Fsm = STATEMACHINE_PROCESS:New( self, {
initial = 'Assigned',
events = {
{ name = 'Await', 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 = {
onAwait = self.OnAwait,
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:OnAwait( Fsm, Event, From, To )
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
self:NextEvent( Fsm.Await )
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.IniUnit then
self:NextEvent( self.Fsm.HitTarget, Event )
end
end

View File

@ -224,9 +224,13 @@
--- SET_BASE class --- SET_BASE class
-- @type SET_BASE -- @type SET_BASE
-- @field #table Filter
-- @field #table Set
-- @field #table List
-- @extends Base#BASE -- @extends Base#BASE
SET_BASE = { SET_BASE = {
ClassName = "SET_BASE", ClassName = "SET_BASE",
Filter = {},
Set = {}, Set = {},
List = {}, List = {},
} }
@ -280,7 +284,7 @@ end
-- @param Base#BASE Object -- @param Base#BASE Object
-- @return Base#BASE The added BASE Object. -- @return Base#BASE The added BASE Object.
function SET_BASE:Add( ObjectName, Object ) function SET_BASE:Add( ObjectName, Object )
self:E( ObjectName ) self:F2( ObjectName )
local t = { _ = Object } local t = { _ = Object }
@ -304,7 +308,7 @@ end
-- @param #SET_BASE self -- @param #SET_BASE self
-- @param #string ObjectName -- @param #string ObjectName
function SET_BASE:Remove( ObjectName ) function SET_BASE:Remove( ObjectName )
self:E( ObjectName ) self:F2( ObjectName )
local t = self.Set[ObjectName] local t = self.Set[ObjectName]
@ -345,6 +349,18 @@ function SET_BASE:Count()
return self.List.Count return self.List.Count
end 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 OtherSet
-- @return #SET_BASE
function SET_BASE:CopyFilter( OtherSet )
local OtherFilter = routines.utils.deepCopy( OtherSet.Filter )
self.Filter = OtherFilter
return self
end
--- Define the SET iterator **"yield interval"** and the **"time interval"**. --- Define the SET iterator **"yield interval"** and the **"time interval"**.
-- @param #SET_BASE self -- @param #SET_BASE self
@ -1184,6 +1200,22 @@ function SET_UNIT:FilterPrefixes( Prefixes )
return self return self
end 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
@ -1310,6 +1342,23 @@ function SET_UNIT:HasRadar( RadarType )
end 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
----- Iterate the SET_UNIT and call an interator function for each **alive** player, providing the Unit of the player and optional parameters. ----- Iterate the SET_UNIT and call an interator function for each **alive** player, providing the Unit of the player and optional parameters.
@ -1401,6 +1450,17 @@ function SET_UNIT:IsIncludeObject( MUnit )
MUnitInclude = MUnitInclude and MUnitPrefix MUnitInclude = MUnitInclude and MUnitPrefix
end 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 ) then
MUnitRadar = true
end
end
MUnitInclude = MUnitInclude and MUnitRadar
end
self:T2( MUnitInclude ) self:T2( MUnitInclude )
return MUnitInclude return MUnitInclude
end end

View File

@ -0,0 +1,105 @@
--- @module Task_CAS
--- The TASK_CAS class
-- @type TASK_CAS
-- @extends Task#TASK_BASE
TASK_CAS = {
ClassName = "TASK_CAS",
}
--- Instantiates a new TASK_CAS.
-- @param #TASK_CAS self
-- @param Mission#MISSION Mission
-- @param Set#SET_UNIT UnitSetTargets
-- @param Zone#ZONE_BASE TargetZone
-- @return #TASK_CAS self
function TASK_CAS:New( Mission, TargetSetUnit, TargetZone )
local self = BASE:Inherit( self, TASK_BASE:New( Mission, "CAS Attack", "CAS", "A2G" ) )
self:F()
self.TargetSetUnit = TargetSetUnit
self.TargetZone = TargetZone
_EVENTDISPATCHER:OnBirth( self._EventAssignUnit, self )
_EVENTDISPATCHER:OnPlayerEnterUnit(self._EventAssignUnit, self )
_EVENTDISPATCHER:OnPlayerLeaveUnit(self._EventUnAssignUnit, self )
_EVENTDISPATCHER:OnCrash(self._EventUnAssignUnit, self )
_EVENTDISPATCHER:OnDead(self._EventUnAssignUnit, self )
_EVENTDISPATCHER:OnPilotDead(self._EventUnAssignUnit, self )
return self
end
--- Assign the @{Task} to a @{Unit}.
-- @param #TASK_CAS self
-- @param Unit#UNIT TaskUnit
-- @return #TASK_CAS self
function TASK_CAS:AssignToUnit( TaskUnit )
self:F( TaskUnit:GetName() )
local ProcessAssign = self:AddProcess( TaskUnit, PROCESS_ASSIGN:New( self, TaskUnit, self.TaskBriefing ) )
local ProcessRoute = self:AddProcess( TaskUnit, PROCESS_ROUTE:New( self, TaskUnit, self.TargetZone ) )
local ProcessSEAD = self:AddProcess( TaskUnit, PROCESS_SEAD:New( self, TaskUnit, self.TargetSetUnit ) )
local Process = self:AddStateMachine( TaskUnit, STATEMACHINE_TASK:New( self, {
initial = 'None',
events = {
{ name = 'Next', from = 'None', to = 'Planned' },
{ name = 'Next', from = 'Planned', to = 'Assigned' },
{ name = 'Reject', from = 'Planned', to = 'Rejected' },
{ name = 'Next', from = 'Assigned', to = 'Success' },
{ name = 'Fail', from = 'Assigned', to = 'Failed' },
{ name = 'Fail', from = 'Arrived', to = 'Failed' }
},
callbacks = {
onNext = self.OnNext,
onRemove = self.OnRemove,
},
subs = {
Assign = { onstateparent = 'Planned', oneventparent = 'Next', fsm = ProcessAssign.Fsm, event = 'Menu', returnevents = { 'Next', 'Reject' } },
Route = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessRoute.Fsm, event = 'Route' },
Sead = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessSEAD.Fsm, event = 'Await', returnevents = { 'Next' } }
}
} ) )
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:_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

View File

@ -7,7 +7,7 @@ TASK_SEAD = {
ClassName = "TASK_SEAD", ClassName = "TASK_SEAD",
} }
--- Instantiates a new TASK_SEAD. Should never be used. Interface Class. --- Instantiates a new TASK_SEAD.
-- @param #TASK_SEAD self -- @param #TASK_SEAD self
-- @param Mission#MISSION Mission -- @param Mission#MISSION Mission
-- @param Set#SET_UNIT UnitSetTargets -- @param Set#SET_UNIT UnitSetTargets

View File

@ -586,12 +586,62 @@ end
function UNIT:IsAir() function UNIT:IsAir()
self:F2() self:F2()
local UnitDescriptor = self.DCSUnit:getDesc() local DCSUnit = self:GetDCSObject()
self:T3( { UnitDescriptor.category, Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
local IsAirResult = ( UnitDescriptor.category == Unit.Category.AIRPLANE ) or ( UnitDescriptor.category == Unit.Category.HELICOPTER ) if DCSUnit then
local UnitDescriptor = DCSUnit:getDesc()
self:T3( { UnitDescriptor.category, Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
self:T3( IsAirResult ) local IsAirResult = ( UnitDescriptor.category == Unit.Category.AIRPLANE ) or ( UnitDescriptor.category == Unit.Category.HELICOPTER )
return IsAirResult
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 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 end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -83,13 +83,14 @@ COPY /b Moose.lua + %1\PatrolZone.lua Moose.lua
COPY /b Moose.lua + %1\AIBalancer.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\AirbasePolice.lua Moose.lua
COPY /b Moose.lua + %1\Detection.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\StateMachine.lua Moose.lua
COPY /b Moose.lua + %1\Process.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_Assign.lua Moose.lua
COPY /b Moose.lua + %1\Process_Route.lua Moose.lua COPY /b Moose.lua + %1\Process_Route.lua Moose.lua
COPY /b Moose.lua + %1\Process_SEAD.lua Moose.lua COPY /b Moose.lua + %1\Process_SEAD.lua Moose.lua
COPY /b Moose.lua + %1\Task.lua Moose.lua COPY /b Moose.lua + %1\Task.lua Moose.lua
COPY /b Moose.lua + %1\Task_CAS.lua Moose.lua
COPY /b Moose.lua + %1\Task_SEAD.lua Moose.lua COPY /b Moose.lua + %1\Task_SEAD.lua Moose.lua
COPY /b Moose.lua + "Moose Create Static\Moose_Trace_Off.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 FACGroup = GROUP:FindByName( "FAC Group" )
local FACDetection = DETECTION_UNITGROUPS:New( FACGroup, 1000, 250 ):SmokeDetectedZones():FlareDetectedUnits() local FACDetection = DETECTION_UNITGROUPS:New( FACGroup, 1000, 250 ):FlareDetectedZones():FlareDetectedUnits()

View File

@ -6,12 +6,12 @@ Mission:AddScoring( Scoring )
local FACGroup = GROUP:FindByName( "FAC" ) local FACGroup = GROUP:FindByName( "FAC" )
local FACDetection = DETECTION_UNITGROUPS:New( FACGroup, 1000, 250 ) local FACDetection = DETECTION_UNITGROUPS:New( FACGroup, 6000, 1000 )
local SEAD_Attack = SET_GROUP:New():FilterCoalitions( "red" ):FilterPrefixes( "SEAD Attack" ):FilterStart() local AttackGroups = SET_GROUP:New():FilterCoalitions( "red" ):FilterPrefixes( "SEAD Attack" ):FilterStart()
local CommandCenter = GROUP:FindByName( "HQ" ) local CommandCenter = GROUP:FindByName( "HQ" )
local TaskAssign = TASK_DISPATCHER:New( Mission, CommandCenter, SEAD_Attack, FACDetection ) local TaskAssign = TASK_DISPATCHER:New( Mission, CommandCenter, AttackGroups, FACDetection )