Merge branch 'FF/Develop' of https://github.com/FlightControl-Master/MOOSE into FF/Develop

This commit is contained in:
funkyfranky 2019-03-27 16:24:17 +01:00
commit e4935d8717
24 changed files with 919 additions and 280 deletions

View File

@ -1688,7 +1688,7 @@ do -- AI_A2A_DISPATCHER
-- Add the CAP to the EWR network.
local RecceSet = self.Detection:GetDetectionSetGroup()
local RecceSet = self.Detection:GetDetectionSet()
RecceSet:FilterPrefixes( DefenderSquadron.TemplatePrefixes )
RecceSet:FilterStart()

View File

@ -919,7 +919,7 @@ do -- AI_A2G_DISPATCHER
AI_A2G_DISPATCHER.Takeoff = GROUP.Takeoff
--- Defnes Landing location.
-- @field Landing
-- @field #AI_A2G_DISPATCHER.Landing
AI_A2G_DISPATCHER.Landing = {
NearAirbase = 1,
AtRunway = 2,
@ -950,7 +950,12 @@ do -- AI_A2G_DISPATCHER
AI_A2G_DISPATCHER.DefenseQueue = {}
--- Defense approach types
-- @type #AI_A2G_DISPATCHER.DefenseApproach
AI_A2G_DISPATCHER.DefenseApproach = {
Random = 1,
Distance = 2,
}
--- AI_A2G_DISPATCHER constructor.
-- This is defining the A2G DISPATCHER for one coaliton.
@ -996,6 +1001,8 @@ do -- AI_A2G_DISPATCHER
-- self.Detection:SetRefreshTimeInterval( 30 )
self:SetDefenseRadius()
self:SetDefenseLimit( nil )
self:SetDefenseApproach( AI_A2G_DISPATCHER.DefenseApproach.Random )
self:SetIntercept( 300 ) -- A default intercept delay time of 300 seconds.
self:SetDisengageRadius( 300000 ) -- The default Disengage Radius is 300 km.
@ -1126,7 +1133,7 @@ do -- AI_A2G_DISPATCHER
self.TakeoffScheduleID = self:ScheduleRepeat( 10, 10, 0, nil, self.ResourceTakeoff, self )
self:__Start( 5 )
self:__Start( 1 )
return self
end
@ -1148,6 +1155,53 @@ do -- AI_A2G_DISPATCHER
end
--- Locks the DefenseItem from being defended.
-- @param #AI_A2G_DISPATCHER self
-- @param #string DetectedItemIndex The index of the detected item.
function AI_A2G_DISPATCHER:Lock( DetectedItemIndex )
self:F( { DetectedItemIndex = DetectedItemIndex } )
local DetectedItem = self.Detection:GetDetectedItemByIndex( DetectedItemIndex )
if DetectedItem then
self:F( { Locked = DetectedItem } )
self.Detection:LockDetectedItem( DetectedItem )
end
end
--- Unlocks the DefenseItem from being defended.
-- @param #AI_A2G_DISPATCHER self
-- @param #string DetectedItemIndex The index of the detected item.
function AI_A2G_DISPATCHER:Unlock( DetectedItemIndex )
self:F( { DetectedItemIndex = DetectedItemIndex } )
self:F( { Index = self.Detection.DetectedItemsByIndex } )
local DetectedItem = self.Detection:GetDetectedItemByIndex( DetectedItemIndex )
if DetectedItem then
self:F( { Unlocked = DetectedItem } )
self.Detection:UnlockDetectedItem( DetectedItem )
end
end
--- Sets maximum zones to be engaged at one time by defenders.
-- @param #AI_A2G_DISPATCHER self
-- @param #number DefenseLimit The maximum amount of detected items to be engaged at the same time.
function AI_A2G_DISPATCHER:SetDefenseLimit( DefenseLimit )
self:F( { DefenseLimit = DefenseLimit } )
self.DefenseLimit = DefenseLimit
end
--- Sets the method of the tactical approach of the defenses.
-- @param #AI_A2G_DISPATCHER self
-- @param #number DefenseApproach Use the structure AI_A2G_DISPATCHER.DefenseApproach to set the defense approach.
-- The default defense approach is AI_A2G_DISPATCHER.DefenseApproach.Random.
function AI_A2G_DISPATCHER:SetDefenseApproach( DefenseApproach )
self:F( { DefenseApproach = DefenseApproach } )
self._DefenseApproach = DefenseApproach
end
--- @param #AI_A2G_DISPATCHER self
function AI_A2G_DISPATCHER:ResourcePark( DefenderSquadron )
@ -3467,6 +3521,20 @@ do -- AI_A2G_DISPATCHER
end
end
function Fsm:onafterPatrolRoute( Defender, From, Event, To, AttackSetUnit )
self:F({"Defender PatrolRoute", Defender:GetName()})
self:GetParent(self).onafterPatrolRoute( self, Defender, From, Event, To, AttackSetUnit )
local DefenderName = Defender:GetName()
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( Defender )
if Squadron then
Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " returning." )
end
Dispatcher:ClearDefenderTaskTarget( Defender )
end
function Fsm:onafterRTB( Defender, From, Event, To )
self:F({"Defender RTB", Defender:GetName()})
self:GetParent(self).onafterRTB( self, Defender, From, Event, To )
@ -3564,15 +3632,15 @@ do -- AI_A2G_DISPATCHER
end
end
function Fsm:OnAfterEngageRoute( Defender, From, Event, To, AttackSetUnit )
function Fsm:onafterEngageRoute( Defender, From, Event, To, AttackSetUnit )
self:F({"Engage Route", Defender:GetName()})
--self:GetParent(self).onafterBirth( self, Defender, From, Event, To )
self:GetParent(self).onafterEngageRoute( self, Defender, From, Event, To, AttackSetUnit )
local DefenderName = Defender:GetName()
local Dispatcher = Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( Defender )
if FirstUnit then
if Squadron then
local FirstUnit = AttackSetUnit:GetFirst()
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
@ -3886,7 +3954,7 @@ do -- AI_A2G_DISPATCHER
end
end
return nil, nil, nil
return 0, 0, 0
end
@ -3919,7 +3987,7 @@ do -- AI_A2G_DISPATCHER
end
end
return nil, nil, nil
return 0, 0, 0
end
@ -3952,11 +4020,29 @@ do -- AI_A2G_DISPATCHER
end
end
return nil, nil, nil
return 0, 0, 0
end
--- Assigns A2G AI Tasks in relation to the detected items.
-- @param #AI_A2G_DISPATCHER self
function AI_A2G_DISPATCHER:Order( DetectedItem )
local AttackCoordinate = self.Detection:GetDetectedItemCoordinate( DetectedItem )
local ShortestDistance = 999999999
for DefenseCoordinateName, DefenseCoordinate in pairs( self.DefenseCoordinates ) do
local DefenseCoordinate = DefenseCoordinate -- Core.Point#COORDINATE
local EvaluateDistance = AttackCoordinate:Get2DDistance( DefenseCoordinate )
if EvaluateDistance <= ShortestDistance then
ShortestDistance = EvaluateDistance
end
end
return ShortestDistance
end
--- Assigns A2G AI Tasks in relation to the detected items.
-- @param #AI_A2G_DISPATCHER self
@ -3983,7 +4069,9 @@ do -- AI_A2G_DISPATCHER
self:ClearDefenderTask( DefenderGroup )
end
else
-- TODO: prio 1, what is this index stuff again, simplify it.
if DefenderTask.Target then
self:F( { TargetIndex = DefenderTask.Target.Index } )
local AttackerItem = Detection:GetDetectedItemByIndex( DefenderTask.Target.Index )
if not AttackerItem then
self:F( { "Removing obsolete Target:", DefenderTask.Target.Index } )
@ -4006,104 +4094,123 @@ do -- AI_A2G_DISPATCHER
local DefenderGroupCount = 0
local DefendersTotal = 0
local DefenseTotal = 0
-- Now that all obsolete tasks are removed, loop through the detected targets.
for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do
--for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do
for DetectedItemID, DetectedItem in UTILS.spairs( Detection:GetDetectedItems(), function( t, a, b ) return self:Order(t[a]) < self:Order(t[b]) end ) do
local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem
local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT
local DetectedCount = DetectedSet:Count()
local DetectedZone = DetectedItem.Zone
self:F( { "Target ID", DetectedItem.ItemID } )
DetectedSet:Flush( self )
local DetectedID = DetectedItem.ID
local DetectionIndex = DetectedItem.Index
local DetectedItemChanged = DetectedItem.Changed
local AttackCoordinate = self.Detection:GetDetectedItemCoordinate( DetectedItem )
-- Calculate if for this DetectedItem if a defense needs to be initiated.
-- This calculation is based on the distance between the defense point and the attackers, and the defensiveness parameter.
-- The attackers closest to the defense coordinates will be handled first, or course!
local EngageCoordinate = nil
for DefenseCoordinateName, DefenseCoordinate in pairs( self.DefenseCoordinates ) do
local DefenseCoordinate = DefenseCoordinate -- Core.Point#COORDINATE
local EvaluateDistance = AttackCoordinate:Get2DDistance( DefenseCoordinate )
if EvaluateDistance <= self.DefenseRadius then
local DistanceProbability = ( self.DefenseRadius / EvaluateDistance * self.DefenseReactivity )
local DefenseProbability = math.random()
self:F( { DistanceProbability = DistanceProbability, DefenseProbability = DefenseProbability } )
if DefenseProbability <= DistanceProbability / ( 300 / 30 ) then
EngageCoordinate = DefenseCoordinate
break
end
end
end
if EngageCoordinate then
do
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_SEAD( DetectedItem ) -- Returns a SET_UNIT with the SEAD targets to be engaged...
if DefendersMissing and DefendersMissing > 0 then
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "SEAD", EngageCoordinate )
end
end
if not self.Detection:IsDetectedItemLocked( DetectedItem ) == true then
local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem
local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT
local DetectedCount = DetectedSet:Count()
local DetectedZone = DetectedItem.Zone
do
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_CAS( DetectedItem ) -- Returns a SET_UNIT with the CAS targets to be engaged...
if DefendersMissing and DefendersMissing > 0 then
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "CAS", EngageCoordinate )
end
end
self:F( { "Target ID", DetectedItem.ItemID } )
self:F( { DefenseLimit = self.DefenseLimitmit, DefenseTotal = DefenseTotal } )
DetectedSet:Flush( self )
do
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_BAI( DetectedItem ) -- Returns a SET_UNIT with the CAS targets to be engaged...
if DefendersMissing and DefendersMissing > 0 then
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "BAI", EngageCoordinate )
local DetectedID = DetectedItem.ID
local DetectionIndex = DetectedItem.Index
local DetectedItemChanged = DetectedItem.Changed
local AttackCoordinate = self.Detection:GetDetectedItemCoordinate( DetectedItem )
-- Calculate if for this DetectedItem if a defense needs to be initiated.
-- This calculation is based on the distance between the defense point and the attackers, and the defensiveness parameter.
-- The attackers closest to the defense coordinates will be handled first, or course!
local EngageCoordinate = nil
for DefenseCoordinateName, DefenseCoordinate in pairs( self.DefenseCoordinates ) do
local DefenseCoordinate = DefenseCoordinate -- Core.Point#COORDINATE
local EvaluateDistance = AttackCoordinate:Get2DDistance( DefenseCoordinate )
if EvaluateDistance <= self.DefenseRadius then
local DistanceProbability = ( self.DefenseRadius / EvaluateDistance * self.DefenseReactivity )
local DefenseProbability = math.random()
self:F( { DistanceProbability = DistanceProbability, DefenseProbability = DefenseProbability } )
if self._DefenseApproach == AI_A2G_DISPATCHER.DefenseApproach.Random then
if DefenseProbability <= DistanceProbability / ( 300 / 30 ) then
EngageCoordinate = DefenseCoordinate
break
end
end
if self._DefenseApproach == AI_A2G_DISPATCHER.DefenseApproach.Distance then
EngageCoordinate = DefenseCoordinate
break
end
end
end
end
-- do
-- local DefendersMissing, Friendlies = self:Evaluate_CAS( DetectedItem )
-- if DefendersMissing and DefendersMissing > 0 then
-- self:F( { DefendersMissing = DefendersMissing } )
-- self:CAS( DetectedItem, DefendersMissing, Friendlies )
-- end
-- end
if self.TacticalDisplay then
-- Show tactical situation
local ThreatLevel = DetectedItem.Set:CalculateThreatLevelA2G()
Report:Add( string.format( " - %1s%s ( %4s ): ( #%d - %4s ) %s" , ( DetectedItem.IsDetected == true ) and "!" or " ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "", ThreatLevel ) ) )
if EngageCoordinate and DefenseTotal < self.DefenseLimit then
do
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_SEAD( DetectedItem ) -- Returns a SET_UNIT with the SEAD targets to be engaged...
if DefendersMissing > 0 then
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "SEAD", EngageCoordinate )
end
end
do
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_CAS( DetectedItem ) -- Returns a SET_UNIT with the CAS targets to be engaged...
if DefendersMissing > 0 then
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "CAS", EngageCoordinate )
end
end
do
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_BAI( DetectedItem ) -- Returns a SET_UNIT with the CAS targets to be engaged...
if DefendersMissing > 0 then
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "BAI", EngageCoordinate )
end
end
end
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
local Defender = Defender -- Wrapper.Group#GROUP
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
if Defender:IsAlive() then
DefenderGroupCount = DefenderGroupCount + 1
local Fuel = Defender:GetFuelMin() * 100
local Damage = Defender:GetLife() / Defender:GetLife0() * 100
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
Defender:GetName(),
DefenderTask.Type,
DefenderTask.Fsm:GetState(),
Defender:GetSize(),
Fuel,
Damage,
Defender:HasTask() == true and "Executing" or "Idle" ) )
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
DefenseTotal = DefenseTotal + 1
end
end
for DefenseQueueID, DefenseQueueItem in pairs( self.DefenseQueue ) do
local DefenseQueueItem = DefenseQueueItem -- #AI_A2G_DISPATCHER.DefenseQueueItem
if DefenseQueueItem.AttackerDetection.Index == DetectedItem.Index then
DefenseTotal = DefenseTotal + 1
end
end
if self.TacticalDisplay then
-- Show tactical situation
local ThreatLevel = DetectedItem.Set:CalculateThreatLevelA2G()
Report:Add( string.format( " - %1s%s ( %4s ): ( #%d - %4s ) %s" , ( DetectedItem.IsDetected == true ) and "!" or " ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "", ThreatLevel ) ) )
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
local Defender = Defender -- Wrapper.Group#GROUP
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
if Defender:IsAlive() then
DefenderGroupCount = DefenderGroupCount + 1
local Fuel = Defender:GetFuelMin() * 100
local Damage = Defender:GetLife() / Defender:GetLife0() * 100
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
Defender:GetName(),
DefenderTask.Type,
DefenderTask.Fsm:GetState(),
Defender:GetSize(),
Fuel,
Damage,
Defender:HasTask() == true and "Executing" or "Idle" ) )
end
end
end
end
end
end
end

View File

@ -142,6 +142,7 @@ do -- Goal
-- @param #GOAL self
-- @param #string PlayerName The name of the player.
function GOAL:AddPlayerContribution( PlayerName )
self:F({PlayerName})
self.Players[PlayerName] = self.Players[PlayerName] or 0
self.Players[PlayerName] = self.Players[PlayerName] + 1
self.TotalContributions = self.TotalContributions + 1

View File

@ -130,6 +130,20 @@ do -- SET_BASE
return self
end
--- Clear the Objects in the Set.
-- @param #SET_BASE self
-- @return #SET_BASE self
function SET_BASE:Clear()
for Name, Object in pairs( self.Set ) do
self:Remove( Name )
end
return self
end
--- Finds an @{Core.Base#BASE} object based on the object Name.
-- @param #SET_BASE self
@ -148,7 +162,7 @@ do -- SET_BASE
function SET_BASE:GetSet()
self:F2()
return self.Set
return self.Set or {}
end
--- Gets a list of the Names of the Objects in the Set.

View File

@ -631,8 +631,8 @@ end
-- * @{ZONE_RADIUS.IsNoneInZone}(): Scan if the zone is empty.
-- @{#ZONE_RADIUS.
-- @param #ZONE_RADIUS self
-- @param ObjectCategories
-- @param UnitCategories
-- @param ObjectCategories An array of categories of the objects to find in the zone.
-- @param UnitCategories An array of unit categories of the objects to find in the zone.
-- @usage
-- self.Zone:Scan()
-- local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
@ -704,6 +704,31 @@ function ZONE_RADIUS:GetScannedUnits()
end
function ZONE_RADIUS:GetScannedSetUnit()
local SetUnit = SET_UNIT:New()
if self.ScanData then
for ObjectID, UnitObject in pairs( self.ScanData.Units ) do
local UnitObject = UnitObject -- DCS#Unit
if UnitObject:isExist() then
local FoundUnit = UNIT:FindByName( UnitObject:getName() )
if FoundUnit then
SetUnit:AddUnit( FoundUnit )
else
local FoundStatic = STATIC:FindByName( UnitObject:getName() )
if FoundStatic then
SetUnit:AddUnit( FoundStatic )
end
end
end
end
end
return SetUnit
end
function ZONE_RADIUS:CountScannedCoalitions()
local Count = 0

View File

@ -469,7 +469,7 @@ do -- DESIGNATE
self.CC = CC
self.Detection = Detection
self.AttackSet = AttackSet
self.RecceSet = Detection:GetDetectionSetGroup()
self.RecceSet = Detection:GetDetectionSet()
self.Recces = {}
self.Designating = {}
self:SetDesignateName()
@ -1182,7 +1182,7 @@ do -- DESIGNATE
local DetectedItem = self.Detection:GetDetectedItemByIndex( Index )
local TargetSetUnit = self.Detection:GetDetectedSet( DetectedItem )
local TargetSetUnit = self.Detection:GetDetectedItemSet( DetectedItem )
local MarkingCount = 0
local MarkedTypes = {}
@ -1352,7 +1352,7 @@ do -- DESIGNATE
end
local DetectedItem = self.Detection:GetDetectedItemByIndex( Index )
local TargetSetUnit = self.Detection:GetDetectedSet( DetectedItem )
local TargetSetUnit = self.Detection:GetDetectedItemSet( DetectedItem )
local Recces = self.Recces
@ -1377,7 +1377,7 @@ do -- DESIGNATE
function DESIGNATE:onafterSmoke( From, Event, To, Index, Color )
local DetectedItem = self.Detection:GetDetectedItemByIndex( Index )
local TargetSetUnit = self.Detection:GetDetectedSet( DetectedItem )
local TargetSetUnit = self.Detection:GetDetectedItemSet( DetectedItem )
local TargetSetUnitCount = TargetSetUnit:Count()
local MarkedCount = 0
@ -1393,7 +1393,7 @@ do -- DESIGNATE
self:F( "Smoking ..." )
local RecceGroup = self.RecceSet:FindNearestGroupFromPointVec2(SmokeUnit:GetPointVec2())
local RecceUnit = RecceGroup:GetUnit( 1 )
local RecceUnit = RecceGroup:GetUnit( 1 ) -- Wrapper.Unit#UNIT
if RecceUnit then
@ -1422,7 +1422,7 @@ do -- DESIGNATE
function DESIGNATE:onafterIlluminate( From, Event, To, Index )
local DetectedItem = self.Detection:GetDetectedItemByIndex( Index )
local TargetSetUnit = self.Detection:GetDetectedSet( DetectedItem )
local TargetSetUnit = self.Detection:GetDetectedItemSet( DetectedItem )
local TargetUnit = TargetSetUnit:GetFirst()
if TargetUnit then

View File

@ -305,9 +305,9 @@ do -- DETECTION_BASE
--- DETECTION constructor.
-- @param #DETECTION_BASE self
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
-- @param Core.Set#SET_BASE DetectionSet The @{Set} that is used to detect the units.
-- @return #DETECTION_BASE self
function DETECTION_BASE:New( DetectionSetGroup )
function DETECTION_BASE:New( DetectionSet )
-- Inherits from BASE
local self = BASE:Inherit( self, FSM:New() ) -- #DETECTION_BASE
@ -316,7 +316,7 @@ do -- DETECTION_BASE
self.DetectedItemMax = 0
self.DetectedItems = {}
self.DetectionSetGroup = DetectionSetGroup
self.DetectionSet = DetectionSet
self.RefreshTimeInterval = 30
@ -398,7 +398,7 @@ do -- DETECTION_BASE
-- @param #string To The To State string.
self:AddTransition( "Detecting", "Detect", "Detecting" )
self:AddTransition( "Detecting", "DetectionGroup", "Detecting" )
self:AddTransition( "Detecting", "Detection", "Detecting" )
--- OnBefore Transition Handler for Event Detect.
-- @function [parent=#DETECTION_BASE] OnBeforeDetect
@ -540,11 +540,12 @@ do -- DETECTION_BASE
self.DetectedObjects[DetectionObjectName].Distance = 10000000
end
for DetectionGroupID, DetectionGroupData in pairs( self.DetectionSetGroup:GetSet() ) do
self.DetectionCount = self.DetectionSet:Count()
for DetectionID, DetectionData in pairs( self.DetectionSet:GetSet() ) do
--self:F( { DetectionGroupData } )
self:F( { DetectionGroup = DetectionGroupData:GetName() } )
self:__DetectionGroup( DetectDelay, DetectionGroupData, DetectionTimeStamp ) -- Process each detection asynchronously.
self.DetectionCount = self.DetectionCount + 1
self:F( { DetectionGroup = DetectionData:GetName() } )
self:__Detection( DetectDelay, DetectionData, DetectionTimeStamp ) -- Process each detection asynchronously.
DetectDelay = DetectDelay + 1
end
end
@ -555,7 +556,7 @@ do -- DETECTION_BASE
-- @param #string To The To State string.
-- @param Wrapper.Group#GROUP DetectionGroup The Group detecting.
-- @param #number DetectionTimeStamp Time stamp of detection event.
function DETECTION_BASE:onafterDetectionGroup( From, Event, To, DetectionGroup, DetectionTimeStamp )
function DETECTION_BASE:onafterDetection( From, Event, To, Detection, DetectionTimeStamp )
--self:F( { DetectedObjects = self.DetectedObjects } )
@ -563,16 +564,16 @@ do -- DETECTION_BASE
local HasDetectedObjects = false
if DetectionGroup:IsAlive() then
if Detection:IsAlive() then
--self:T( { "DetectionGroup is Alive", DetectionGroup:GetName() } )
local DetectionGroupName = DetectionGroup:GetName()
local DetectionUnit = DetectionGroup:GetUnit(1)
local DetectionGroupName = Detection:GetName()
local DetectionUnit = Detection:GetUnit(1)
local DetectedUnits = {}
local DetectedTargets = DetectionGroup:GetDetectedTargets(
local DetectedTargets = Detection:GetDetectedTargets(
self.DetectVisual,
self.DetectOptical,
self.DetectRadar,
@ -624,7 +625,7 @@ do -- DETECTION_BASE
local DetectedObjectVec3 = DetectedObject:getPoint()
local DetectedObjectVec2 = { x = DetectedObjectVec3.x, y = DetectedObjectVec3.z }
local DetectionGroupVec3 = DetectionGroup:GetVec3()
local DetectionGroupVec3 = Detection:GetVec3()
local DetectionGroupVec2 = { x = DetectionGroupVec3.x, y = DetectionGroupVec3.z }
local Distance = ( ( DetectedObjectVec3.x - DetectionGroupVec3.x )^2 +
@ -838,7 +839,7 @@ do -- DETECTION_BASE
local DetectedItems = self:GetDetectedItems()
for DetectedItemIndex, DetectedItem in pairs( DetectedItems ) do
local DetectedSet = self:GetDetectedSet( DetectedItem )
local DetectedSet = self:GetDetectedItemSet( DetectedItem )
if DetectedSet then
DetectedSet:RemoveUnitsByName( UnitName )
end
@ -1524,21 +1525,21 @@ do -- DETECTION_BASE
self.DetectedItemCount = self.DetectedItemCount + 1
self.DetectedItemMax = self.DetectedItemMax + 1
if DetectedItemKey then
self.DetectedItems[DetectedItemKey] = DetectedItem
else
self.DetectedItems[self.DetectedItemMax] = DetectedItem
end
self.DetectedItemsByIndex[self.DetectedItemMax] = DetectedItem
DetectedItemKey = DetectedItemKey or self.DetectedItemMax
self.DetectedItems[DetectedItemKey] = DetectedItem
self.DetectedItemsByIndex[DetectedItemKey] = DetectedItem
DetectedItem.Index = DetectedItemKey
DetectedItem.Set = Set or SET_UNIT:New():FilterDeads():FilterCrashes()
DetectedItem.Index = DetectedItemKey or self.DetectedItemMax
DetectedItem.ItemID = ItemPrefix .. "." .. self.DetectedItemMax
DetectedItem.ID = self.DetectedItemMax
DetectedItem.Removed = false
if self.Locking then
self:LockDetectedItem( DetectedItem )
end
return DetectedItem
end
@ -1549,9 +1550,11 @@ do -- DETECTION_BASE
-- @param Core.Set#SET_UNIT Set (optional) The Set of Units to be added.
-- @param Core.Zone#ZONE_UNIT Zone (optional) The Zone to be added where the Units are located.
-- @return #DETECTION_BASE.DetectedItem
function DETECTION_BASE:AddDetectedItemZone( DetectedItemKey, Set, Zone )
function DETECTION_BASE:AddDetectedItemZone( ItemPrefix, DetectedItemKey, Set, Zone )
local DetectedItem = self:AddDetectedItem( "AREA", DetectedItemKey, Set )
self:F( { ItemPrefix, DetectedItemKey, Set, Zone } )
local DetectedItem = self:AddDetectedItem( ItemPrefix, DetectedItemKey, Set )
DetectedItem.Zone = Zone
@ -1624,7 +1627,9 @@ do -- DETECTION_BASE
-- @return #DETECTION_BASE.DetectedItem
function DETECTION_BASE:GetDetectedItemByIndex( Index )
self:F( { DetectedItemsByIndex = self.DetectedItemsByIndex } )
self:I( { DetectedItemsByIndex = self.DetectedItemsByIndex } )
self:I( { self.DetectedItemsByIndex } )
local DetectedItem = self.DetectedItemsByIndex[Index]
if DetectedItem then
@ -1661,7 +1666,7 @@ do -- DETECTION_BASE
-- @param #DETECTION_BASE self
-- @param #DETECTION_BASE.DetectedItem DetectedItem
-- @return Core.Set#SET_UNIT DetectedSet
function DETECTION_BASE:GetDetectedSet( DetectedItem )
function DETECTION_BASE:GetDetectedItemSet( DetectedItem )
local DetectedSetUnit = DetectedItem and DetectedItem.Set
if DetectedSetUnit then
@ -1724,6 +1729,68 @@ do -- DETECTION_BASE
end
--- Lock the detected items when created and lock all existing detected items.
-- @param #DETECTION_BASE self
-- @return #DETECTION_BASE
function DETECTION_BASE:LockDetectedItems()
for DetectedItemID, DetectedItem in pairs( self.DetectedItems ) do
self:LockDetectedItem( DetectedItem )
end
self.Locking = true
return self
end
--- Unlock the detected items when created and unlock all existing detected items.
-- @param #DETECTION_BASE self
-- @return #DETECTION_BASE
function DETECTION_BASE:UnlockDetectedItems()
for DetectedItemID, DetectedItem in pairs( self.DetectedItems ) do
self:UnlockDetectedItem( DetectedItem )
end
self.Locking = nil
return self
end
--- Validate if the detected item is locked.
-- @param #DETECTION_BASE self
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
-- @return #boolean
function DETECTION_BASE:IsDetectedItemLocked( DetectedItem )
return self.Locking and DetectedItem.Locked == true
end
--- Lock a detected item.
-- @param #DETECTION_BASE self
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
-- @return #DETECTION_BASE
function DETECTION_BASE:LockDetectedItem( DetectedItem )
DetectedItem.Locked = true
return self
end
--- Unlock a detected item.
-- @param #DETECTION_BASE self
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
-- @return #DETECTION_BASE
function DETECTION_BASE:UnlockDetectedItem( DetectedItem )
DetectedItem.Locked = nil
return self
end
--- Set the detected item coordinate.
-- @param #DETECTION_BASE self
@ -1810,13 +1877,13 @@ do -- DETECTION_BASE
return nil
end
--- Get the detection Groups.
--- Get the Detection Set.
-- @param #DETECTION_BASE self
-- @return Core.Set#SET_GROUP
function DETECTION_BASE:GetDetectionSetGroup()
-- @return Core.Set#SET_BASE
function DETECTION_BASE:GetDetectionSet()
local DetectionSetGroup = self.DetectionSetGroup
return DetectionSetGroup
local DetectionSet = self.DetectionSet
return DetectionSet
end
--- Find the nearest Recce of the DetectedItem.
@ -1828,7 +1895,7 @@ do -- DETECTION_BASE
local NearestRecce = nil
local DistanceRecce = 1000000000 -- Units are not further than 1000000 km away from an area :-)
for RecceGroupName, RecceGroup in pairs( self.DetectionSetGroup:GetSet() ) do
for RecceGroupName, RecceGroup in pairs( self.DetectionSet:GetSet() ) do
if RecceGroup and RecceGroup:IsAlive() then
for RecceUnit, RecceUnit in pairs( RecceGroup:GetUnits() ) do
if RecceUnit:IsActive() then
@ -2033,7 +2100,7 @@ do -- DETECTION_UNITS
local DetectedFirstUnitCoord = DetectedFirstUnit:GetCoordinate()
self:SetDetectedItemCoordinate( DetectedItem, DetectedFirstUnitCoord, DetectedFirstUnit )
self:ReportFriendliesNearBy( { DetectedItem = DetectedItem, ReportSetGroup = self.DetectionSetGroup } ) -- Fill the Friendlies table
self:ReportFriendliesNearBy( { DetectedItem = DetectedItem, ReportSetGroup = self.DetectionSet } ) -- Fill the Friendlies table
self:SetDetectedItemThreatLevel( DetectedItem )
self:NearestRecce( DetectedItem )
@ -2268,7 +2335,7 @@ do -- DETECTION_TYPES
local DetectedUnitCoord = DetectedFirstUnit:GetCoordinate()
self:SetDetectedItemCoordinate( DetectedItem, DetectedUnitCoord, DetectedFirstUnit )
self:ReportFriendliesNearBy( { DetectedItem = DetectedItem, ReportSetGroup = self.DetectionSetGroup } ) -- Fill the Friendlies table
self:ReportFriendliesNearBy( { DetectedItem = DetectedItem, ReportSetGroup = self.DetectionSet } ) -- Fill the Friendlies table
self:SetDetectedItemThreatLevel( DetectedItem )
self:NearestRecce( DetectedItem )
end
@ -2286,7 +2353,7 @@ do -- DETECTION_TYPES
function DETECTION_TYPES:DetectedItemReportSummary( DetectedItem, AttackGroup, Settings )
self:F( { DetectedItem = DetectedItem } )
local DetectedSet = self:GetDetectedSet( DetectedItem )
local DetectedSet = self:GetDetectedItemSet( DetectedItem )
local DetectedItemID = self:GetDetectedItemID( DetectedItem )
self:T( DetectedItem )
@ -2408,7 +2475,7 @@ do -- DETECTION_AREAS
local DetectedItemID = self:GetDetectedItemID( DetectedItem )
if DetectedItem then
local DetectedSet = self:GetDetectedSet( DetectedItem )
local DetectedSet = self:GetDetectedItemSet( DetectedItem )
local ReportSummaryItem
local DetectedZone = self:GetDetectedItemZone( DetectedItem )
@ -2741,7 +2808,7 @@ do -- DETECTION_AREAS
if AddedToDetectionArea == false then
-- New detection area
local DetectedItem = self:AddDetectedItemZone( nil,
local DetectedItem = self:AddDetectedItemZone( "AREA", nil,
SET_UNIT:New():FilterDeads():FilterCrashes(),
ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange )
)
@ -2773,7 +2840,7 @@ do -- DETECTION_AREAS
-- If there were friendlies nearby, and now there aren't any friendlies nearby, we flag the area as "changed".
-- This is for the A2G dispatcher to detect if there is a change in the tactical situation.
local OldFriendliesNearbyGround = self:IsFriendliesNearBy( DetectedItem, Unit.Category.GROUND_UNIT )
self:ReportFriendliesNearBy( { DetectedItem = DetectedItem, ReportSetGroup = self.DetectionSetGroup } ) -- Fill the Friendlies table
self:ReportFriendliesNearBy( { DetectedItem = DetectedItem, ReportSetGroup = self.DetectionSet } ) -- Fill the Friendlies table
local NewFriendliesNearbyGround = self:IsFriendliesNearBy( DetectedItem, Unit.Category.GROUND_UNIT )
if OldFriendliesNearbyGround ~= NewFriendliesNearbyGround then
DetectedItem.Changed = true
@ -2819,3 +2886,5 @@ do -- DETECTION_AREAS
end
end

View File

@ -0,0 +1,402 @@
do -- DETECTION_ZONES
--- @type DETECTION_ZONES
-- @field DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
-- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
-- @extends Functional.Detection#DETECTION_BASE
--- (old, to be revised ) Detect units within the battle zone for a list of @{Core.Zone}s detecting targets following (a) detection method(s),
-- and will build a list (table) of @{Core.Set#SET_UNIT}s containing the @{Wrapper.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.
--
-- ## 4.1) Retrieve the Detected Unit Sets and Detected Zones
--
-- The methods to manage the DetectedItems[].Set(s) are implemented in @{Functional.Detection#DECTECTION_BASE} and
-- the methods to manage the DetectedItems[].Zone(s) is implemented in @{Functional.Detection#DETECTION_ZONES}.
--
-- Retrieve the DetectedItems[].Set with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned.
--
-- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZones}().
-- To understand the amount of zones created, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZoneCount}().
-- If you want to obtain a specific zone from the DetectedZones, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZone}() with a given index.
--
-- ## 4.4) Flare or Smoke detected units
--
-- Use the methods @{Functional.Detection#DETECTION_ZONES.FlareDetectedUnits}() or @{Functional.Detection#DETECTION_ZONES.SmokeDetectedUnits}() to flare or smoke the detected units when a new detection has taken place.
--
-- ## 4.5) Flare or Smoke or Bound detected zones
--
-- Use the methods:
--
-- * @{Functional.Detection#DETECTION_ZONES.FlareDetectedZones}() to flare in a color
-- * @{Functional.Detection#DETECTION_ZONES.SmokeDetectedZones}() to smoke in a color
-- * @{Functional.Detection#DETECTION_ZONES.SmokeDetectedZones}() to bound with a tire with a white flag
--
-- the detected zones when a new detection has taken place.
--
-- @field #DETECTION_ZONES
DETECTION_ZONES = {
ClassName = "DETECTION_ZONES",
DetectionZoneRange = nil,
}
--- DETECTION_ZONES constructor.
-- @param #DETECTION_ZONES self
-- @param Core.Set#SET_ZONE_RADIUS DetectionSetZone The @{Set} of ZONE_RADIUS.
-- @param DCS#Coalition.side DetectionCoalition The coalition of the detection.
-- @return #DETECTION_ZONES
function DETECTION_ZONES:New( DetectionSetZone, DetectionCoalition )
-- Inherits from DETECTION_BASE
local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionSetZone ) )
self.DetectionSetZone = DetectionSetZone
self.DetectionCoalition = DetectionCoalition
self._SmokeDetectedUnits = false
self._FlareDetectedUnits = false
self._SmokeDetectedZones = false
self._FlareDetectedZones = false
self._BoundDetectedZones = false
return self
end
--- Report summary of a detected item using a given numeric index.
-- @param #DETECTION_ZONES self
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
-- @param Wrapper.Group#GROUP AttackGroup The group to get the settings for.
-- @param Core.Settings#SETTINGS Settings (Optional) Message formatting settings to use.
-- @return Core.Report#REPORT The report of the detection items.
function DETECTION_ZONES:DetectedItemReportSummary( DetectedItem, AttackGroup, Settings )
self:F( { DetectedItem = DetectedItem } )
local DetectedItemID = self:GetDetectedItemID( DetectedItem )
if DetectedItem then
local DetectedSet = self:GetDetectedItemSet( DetectedItem )
local ReportSummaryItem
local DetectedZone = self:GetDetectedItemZone( DetectedItem )
local DetectedItemCoordinate = DetectedZone:GetCoordinate()
local DetectedItemCoordText = DetectedItemCoordinate:ToString( AttackGroup, Settings )
local ThreatLevelA2G = self:GetDetectedItemThreatLevel( DetectedItem )
local DetectedItemsCount = DetectedSet:Count()
local DetectedItemsTypes = DetectedSet:GetTypeNames()
local Report = REPORT:New()
Report:Add(DetectedItemID .. ", " .. DetectedItemCoordText)
Report:Add( string.format( "Threat: [%s]", string.rep( "", ThreatLevelA2G ), string.rep( "", 10-ThreatLevelA2G ) ) )
Report:Add( string.format("Type: %2d of %s", DetectedItemsCount, DetectedItemsTypes ) )
Report:Add( string.format("Detected: %s", DetectedItem.IsDetected and "yes" or "no" ) )
return Report
end
return nil
end
--- Report detailed of a detection result.
-- @param #DETECTION_ZONES self
-- @param Wrapper.Group#GROUP AttackGroup The group to generate the report for.
-- @return #string
function DETECTION_ZONES:DetectedReportDetailed( AttackGroup ) --R2.1 Fixed missing report
self:F()
local Report = REPORT:New()
for DetectedItemIndex, DetectedItem in pairs( self.DetectedItems ) do
local DetectedItem = DetectedItem -- #DETECTION_BASE.DetectedItem
local ReportSummary = self:DetectedItemReportSummary( DetectedItem, AttackGroup )
Report:SetTitle( "Detected areas:" )
Report:Add( ReportSummary:Text() )
end
local ReportText = Report:Text()
return ReportText
end
--- Calculate the optimal intercept point of the DetectedItem.
-- @param #DETECTION_ZONES self
-- @param #DETECTION_BASE.DetectedItem DetectedItem
function DETECTION_ZONES:CalculateIntercept( DetectedItem )
local DetectedCoord = DetectedItem.Coordinate
-- local DetectedSpeed = DetectedCoord:GetVelocity()
-- local DetectedHeading = DetectedCoord:GetHeading()
--
-- if self.Intercept then
-- local DetectedSet = DetectedItem.Set
-- -- todo: speed
--
-- local TranslateDistance = DetectedSpeed * self.InterceptDelay
--
-- local InterceptCoord = DetectedCoord:Translate( TranslateDistance, DetectedHeading )
--
-- DetectedItem.InterceptCoord = InterceptCoord
-- else
-- DetectedItem.InterceptCoord = DetectedCoord
-- end
DetectedItem.InterceptCoord = DetectedCoord
end
--- Smoke the detected units
-- @param #DETECTION_ZONES self
-- @return #DETECTION_ZONES self
function DETECTION_ZONES:SmokeDetectedUnits()
self:F2()
self._SmokeDetectedUnits = true
return self
end
--- Flare the detected units
-- @param #DETECTION_ZONES self
-- @return #DETECTION_ZONES self
function DETECTION_ZONES:FlareDetectedUnits()
self:F2()
self._FlareDetectedUnits = true
return self
end
--- Smoke the detected zones
-- @param #DETECTION_ZONES self
-- @return #DETECTION_ZONES self
function DETECTION_ZONES:SmokeDetectedZones()
self:F2()
self._SmokeDetectedZones = true
return self
end
--- Flare the detected zones
-- @param #DETECTION_ZONES self
-- @return #DETECTION_ZONES self
function DETECTION_ZONES:FlareDetectedZones()
self:F2()
self._FlareDetectedZones = true
return self
end
--- Bound the detected zones
-- @param #DETECTION_ZONES self
-- @return #DETECTION_ZONES self
function DETECTION_ZONES:BoundDetectedZones()
self:F2()
self._BoundDetectedZones = true
return self
end
--- Make text documenting the changes of the detected zone.
-- @param #DETECTION_ZONES self
-- @param #DETECTION_BASE.DetectedItem DetectedItem
-- @return #string The Changes text
function DETECTION_ZONES:GetChangeText( DetectedItem )
self:F( DetectedItem )
local MT = {}
for ChangeCode, ChangeData in pairs( DetectedItem.Changes ) do
if ChangeCode == "AA" then
MT[#MT+1] = "Detected new area " .. ChangeData.ID .. ". The center target is a " .. ChangeData.ItemUnitType .. "."
end
if ChangeCode == "RAU" then
MT[#MT+1] = "Changed area " .. ChangeData.ID .. ". Removed the center target."
end
if ChangeCode == "AAU" then
MT[#MT+1] = "Changed area " .. ChangeData.ID .. ". The new center target is a " .. ChangeData.ItemUnitType .. "."
end
if ChangeCode == "RA" then
MT[#MT+1] = "Removed old area " .. ChangeData.ID .. ". No more targets in this area."
end
if ChangeCode == "AU" then
local MTUT = {}
for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do
if ChangeUnitType ~= "ID" then
MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType
end
end
MT[#MT+1] = "Detected for area " .. ChangeData.ID .. " new target(s) " .. table.concat( MTUT, ", " ) .. "."
end
if ChangeCode == "RU" then
local MTUT = {}
for ChangeUnitType, ChangeUnitCount in pairs( ChangeData ) do
if ChangeUnitType ~= "ID" then
MTUT[#MTUT+1] = ChangeUnitCount .. " of " .. ChangeUnitType
end
end
MT[#MT+1] = "Removed for area " .. ChangeData.ID .. " invisible or destroyed target(s) " .. table.concat( MTUT, ", " ) .. "."
end
end
return table.concat( MT, "\n" )
end
--- Make a DetectionSet table. This function will be overridden in the derived clsses.
-- @param #DETECTION_ZONES self
-- @return #DETECTION_ZONES self
function DETECTION_ZONES:CreateDetectionItems()
self:F( "Checking Detected Items for new Detected Units ..." )
local DetectedUnits = SET_UNIT:New()
-- First go through all zones, and check if there are new Zones.
-- New Zones become a new DetectedItem.
for ZoneName, DetectionZone in pairs( self.DetectionSetZone:GetSet() ) do
local DetectedItem = self:GetDetectedItemByKey( ZoneName )
if DetectedItem == nil then
DetectedItem = self:AddDetectedItemZone( "ZONE", ZoneName, nil, DetectionZone )
end
local DetectedItemSetUnit = self:GetDetectedItemSet( DetectedItem )
-- Scan the zone
DetectionZone:Scan( { Object.Category.UNIT }, { Unit.Category.GROUND_UNIT } )
-- For all the units in the zone,
-- check if they are of the same coalition to be included.
local ZoneUnits = DetectionZone:GetScannedUnits()
for DCSUnitID, DCSUnit in pairs( ZoneUnits ) do
local UnitName = DCSUnit:getName()
local ZoneUnit = UNIT:FindByName( UnitName )
local ZoneUnitCoalition = ZoneUnit:GetCoalition()
if ZoneUnitCoalition == self.DetectionCoalition then
if DetectedItemSetUnit:FindUnit( UnitName ) == nil and DetectedUnits:FindUnit( UnitName ) == nil then
self:F( "Adding " .. UnitName )
DetectedItemSetUnit:AddUnit( ZoneUnit )
DetectedUnits:AddUnit( ZoneUnit )
end
end
end
end
-- Now all the tests should have been build, now make some smoke and flares...
-- We also report here the friendlies within the detected areas.
for DetectedItemID, DetectedItemData in pairs( self.DetectedItems ) do
local DetectedItem = DetectedItemData -- #DETECTION_BASE.DetectedItem
local DetectedSet = self:GetDetectedItemSet( DetectedItem )
local DetectedFirstUnit = DetectedSet:GetFirst()
local DetectedZone = self:GetDetectedItemZone( DetectedItem )
-- Set the last known coordinate to the detection item.
local DetectedZoneCoord = DetectedZone:GetCoordinate()
self:SetDetectedItemCoordinate( DetectedItem, DetectedZoneCoord, DetectedFirstUnit )
self:CalculateIntercept( DetectedItem )
-- We search for friendlies nearby.
-- If there weren't any friendlies nearby, and now there are friendlies nearby, we flag the area as "changed".
-- If there were friendlies nearby, and now there aren't any friendlies nearby, we flag the area as "changed".
-- This is for the A2G dispatcher to detect if there is a change in the tactical situation.
local OldFriendliesNearbyGround = self:IsFriendliesNearBy( DetectedItem, Unit.Category.GROUND_UNIT )
self:ReportFriendliesNearBy( { DetectedItem = DetectedItem, ReportSetGroup = self.DetectionSetGroup } ) -- Fill the Friendlies table
local NewFriendliesNearbyGround = self:IsFriendliesNearBy( DetectedItem, Unit.Category.GROUND_UNIT )
if OldFriendliesNearbyGround ~= NewFriendliesNearbyGround then
DetectedItem.Changed = true
end
self:SetDetectedItemThreatLevel( DetectedItem ) -- Calculate A2G threat level
--self:NearestRecce( DetectedItem )
if DETECTION_ZONES._SmokeDetectedUnits or self._SmokeDetectedUnits then
DetectedZone:SmokeZone( SMOKECOLOR.Red, 30 )
end
--DetectedSet:Flush( self )
DetectedSet:ForEachUnit(
--- @param Wrapper.Unit#UNIT DetectedUnit
function( DetectedUnit )
if DetectedUnit:IsAlive() then
--self:T( "Detected Set #" .. DetectedItem.ID .. ":" .. DetectedUnit:GetName() )
if DETECTION_ZONES._FlareDetectedUnits or self._FlareDetectedUnits then
DetectedUnit:FlareGreen()
end
if DETECTION_ZONES._SmokeDetectedUnits or self._SmokeDetectedUnits then
DetectedUnit:SmokeGreen()
end
end
end
)
if DETECTION_ZONES._FlareDetectedZones or self._FlareDetectedZones then
DetectedZone:FlareZone( SMOKECOLOR.White, 30, math.random( 0,90 ) )
end
if DETECTION_ZONES._SmokeDetectedZones or self._SmokeDetectedZones then
DetectedZone:SmokeZone( SMOKECOLOR.White, 30 )
end
if DETECTION_ZONES._BoundDetectedZones or self._BoundDetectedZones then
self.CountryID = DetectedSet:GetFirst():GetCountry()
DetectedZone:BoundZone( 12, self.CountryID )
end
end
end
--- @param #DETECTION_ZONES self
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @param Detection The element on which the detection is based.
-- @param #number DetectionTimeStamp Time stamp of detection event.
function DETECTION_ZONES:onafterDetection( From, Event, To, Detection, DetectionTimeStamp )
self.DetectionRun = self.DetectionRun + 1
if self.DetectionCount > 0 and self.DetectionRun == self.DetectionCount then
self:CreateDetectionItems() -- Polymorphic call to Create/Update the DetectionItems list for the DETECTION_ class grouping method.
for DetectedItemID, DetectedItem in pairs( self.DetectedItems ) do
self:UpdateDetectedItemDetection( DetectedItem )
self:CleanDetectionItem( DetectedItem, DetectedItemID ) -- Any DetectionItem that has a Set with zero elements in it, must be removed from the DetectionItems list.
if DetectedItem then
self:__DetectedItem( 0.1, DetectedItem )
end
end
self:__Detect( self.RefreshTimeInterval )
end
end
--- Set IsDetected flag for the DetectedItem, which can have more units.
-- @param #DETECTION_ZONES self
-- @return #DETECTION_ZONES.DetectedItem DetectedItem
-- @return #boolean true if at least one UNIT is detected from the DetectedSet, false if no UNIT was detected from the DetectedSet.
function DETECTION_ZONES:UpdateDetectedItemDetection( DetectedItem )
local IsDetected = true
DetectedItem.IsDetected = true
return IsDetected
end
end

View File

@ -872,7 +872,7 @@ function ESCORT:_AttackTarget( DetectedItem )
EscortGroup:OptionROTPassiveDefense()
EscortGroup:SetState( EscortGroup, "Escort", self )
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
local DetectedSet = self.Detection:GetDetectedItemSet( DetectedItem )
local Tasks = {}
@ -895,7 +895,7 @@ function ESCORT:_AttackTarget( DetectedItem )
else
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
local DetectedSet = self.Detection:GetDetectedItemSet( DetectedItem )
local Tasks = {}
@ -934,7 +934,7 @@ function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItem )
EscortGroupAttack:OptionROEOpenFire()
EscortGroupAttack:OptionROTVertical()
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
local DetectedSet = self.Detection:GetDetectedItemSet( DetectedItem )
local Tasks = {}
@ -956,7 +956,7 @@ function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItem )
)
else
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
local DetectedSet = self.Detection:GetDetectedItemSet( DetectedItem )
local Tasks = {}

View File

@ -356,11 +356,11 @@ do -- ZONE_CAPTURE_COALITION
-- ZoneCaptureCoalition = ZONE_CAPTURE_COALITION:New( AttackZone, coalition.side.RED ) -- Create a new ZONE_CAPTURE_COALITION object of zone AttackZone with ownership RED coalition.
-- ZoneCaptureCoalition:__Guard( 1 ) -- Start the Guarding of the AttackZone.
--
function ZONE_CAPTURE_COALITION:New( Zone, Coalition )
function ZONE_CAPTURE_COALITION:New( Zone, Coalition, UnitCategories )
local self = BASE:Inherit( self, ZONE_GOAL_COALITION:New( Zone, Coalition ) ) -- #ZONE_CAPTURE_COALITION
local self = BASE:Inherit( self, ZONE_GOAL_COALITION:New( Zone, Coalition, UnitCategories ) ) -- #ZONE_CAPTURE_COALITION
self:F( { Zone = Zone, Coalition = Coalition } )
self:F( { Zone = Zone, Coalition = Coalition, UnitCategories = UnitCategories } )
do

View File

@ -48,6 +48,7 @@ __Moose.Include( 'Scripts/Moose/Functional/Escort.lua' )
__Moose.Include( 'Scripts/Moose/Functional/MissileTrainer.lua' )
__Moose.Include( 'Scripts/Moose/Functional/ATC_Ground.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Detection.lua' )
__Moose.Include( 'Scripts/Moose/Functional/DetectionZones.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Designate.lua' )
__Moose.Include( 'Scripts/Moose/Functional/RAT.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Range.lua' )

View File

@ -73,8 +73,9 @@
-- * [[MOOSE] Airboss - Groove Test A-4E Community Mod](https://www.youtube.com/watch?v=ZbjD7FHiaHo)
-- * [[MOOSE] Airboss - Groove Test: On-the-fly LSO Grading](https://www.youtube.com/watch?v=Xgs1hwDcPyM)
-- * [[MOOSE] Airboss - Carrier Auto Steam Into Wind](https://www.youtube.com/watch?v=IsU8dYgsp90)
-- * [[MOOSE] Airboss - CASE I Walkthrough by TG](https://www.youtube.com/watch?v=o1UrP4Q6PMM)
-- * [[MOOSE] Airboss - CASE I Walkthrough in the F/A-18C by TG](https://www.youtube.com/watch?v=o1UrP4Q6PMM)
-- * [[MOOSE] Airboss - New LSO/Marshal Voice Overs by Raynor](https://www.youtube.com/watch?v=_Suo68bRu8k)
-- * [[MOOSE] Airboss - CASE I, "Until We Go Down" featuring the F-14B by Pikes](https://www.youtube.com/watch?v=ojgHDSw3Doc)
--
-- ### Lex explaining Boat Ops:
--
@ -1663,7 +1664,7 @@ AIRBOSS.MenuF10Root=nil
--- Airboss class version.
-- @field #string version
AIRBOSS.version="0.9.9.6w"
AIRBOSS.version="0.9.9.6"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@ -4204,6 +4205,9 @@ function AIRBOSS:SetVoiceOversLSOByFF(mizfolder)
-- Default is the general folder.
self.soundfolderLSO=self.soundfolder
end
-- Report for duty.
self:I(self.lid..string.format("LSO FF reporting for duty! Soundfolder=%s", tostring(self.soundfolderLSO)))
self.LSOCall.BOLTER.duration=0.75
self.LSOCall.CALLTHEBALL.duration=0.60

View File

@ -212,7 +212,7 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
if EventGroup and self:HasGroup( EventGroup ) then
local CommandCenterMenu = MENU_GROUP:New( EventGroup, self:GetText() )
local MenuReporting = MENU_GROUP:New( EventGroup, "Missions Reports", CommandCenterMenu )
local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Status Report", MenuReporting, self.ReportMissionsStatus, self, EventGroup )
local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Status Report", MenuReporting, self.ReportSummary, self, EventGroup )
local MenuMissionsDetails = MENU_GROUP_COMMAND:New( EventGroup, "Missions Players Report", MenuReporting, self.ReportMissionsPlayers, self, EventGroup )
self:ReportSummary( EventGroup )
local PlayerUnit = EventData.IniUnit
@ -507,14 +507,18 @@ function COMMANDCENTER:AssignTask( TaskGroup )
end
local Task = Tasks[ math.random( 1, #Tasks ) ] -- Tasking.Task#TASK
if Task then
self:I( "Assigning task " .. Task:GetName() .. " using auto assign method " .. self.AutoAssignMethod .. " to " .. TaskGroup:GetName() .. " with task priority " .. AssignPriority )
if not self.AutoAcceptTasks == true then
Task:SetAutoAssignMethod( ACT_ASSIGN_MENU_ACCEPT:New( Task.TaskBriefing ) )
self:I( "Assigning task " .. Task:GetName() .. " using auto assign method " .. self.AutoAssignMethod .. " to " .. TaskGroup:GetName() .. " with task priority " .. AssignPriority )
if not self.AutoAcceptTasks == true then
Task:SetAutoAssignMethod( ACT_ASSIGN_MENU_ACCEPT:New( Task.TaskBriefing ) )
end
Task:AssignToGroup( TaskGroup )
end
Task:AssignToGroup( TaskGroup )
end

View File

@ -239,6 +239,8 @@ do -- DETECTION MANAGER
-- @param #string Message The message to be sent.
-- @return #DETECTION_MANGER self
function DETECTION_MANAGER:MessageToPlayers( Message )
self:F( { Message = Message } )
if self.CC then
self.CC:MessageToCoalition( Message )

View File

@ -1808,7 +1808,7 @@ function TASK:GetPlayerNames() --R2.1 Get a map of the players.
if PlayerGroup:IsAlive() == true then
if self:IsGroupAssigned( PlayerGroup ) then
local PlayerNames = PlayerGroup:GetPlayerNames()
for PlayerNameID, PlayerName in pairs( PlayerNames ) do
for PlayerNameID, PlayerName in pairs( PlayerNames or {} ) do
PlayerNameMap[PlayerName] = PlayerGroup
end
end

View File

@ -162,7 +162,7 @@ end
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
-- @return #TASKINFO self
function TASKINFO:AddThreat( ThreatText, ThreatLevel, Order, Detail, Keep )
self:AddInfo( "Threat", ThreatText .. " [" .. string.rep( "", ThreatLevel ) .. string.rep( "", 10 - ThreatLevel ) .. "]", Order, Detail, Keep )
self:AddInfo( "Threat", " [" .. string.rep( "", ThreatLevel ) .. string.rep( "", 10 - ThreatLevel ) .. "]:" .. ThreatText, Order, Detail, Keep )
return self
end
@ -306,65 +306,51 @@ function TASKINFO:Report( Report, Detail, ReportGroup, Task )
for Key, Data in UTILS.spairs( self.Info.Set, function( t, a, b ) return t[a].Order < t[b].Order end ) do
self:F( { Key = Key, Detail = Detail, Data = Data } )
if Data.Detail:find( Detail ) then
local Text = ""
if Key == "TaskName" then
if Key == "TaskName" then
Key = nil
Text = Data.Data
end
if Key == "Coordinate" then
elseif Key == "Coordinate" then
local Coordinate = Data.Data -- Core.Point#COORDINATE
Text = Coordinate:ToString( ReportGroup:GetUnit(1), nil, Task )
end
if Key == "Threat" then
elseif Key == "Threat" then
local DataText = Data.Data -- #string
Text = DataText
end
if Key == "Counting" then
elseif Key == "Counting" then
local DataText = Data.Data -- #string
Text = DataText
end
if Key == "Targets" then
elseif Key == "Targets" then
local DataText = Data.Data -- #string
Text = DataText
end
if Key == "QFE" then
elseif Key == "QFE" then
local Coordinate = Data.Data -- Core.Point#COORDINATE
Text = Coordinate:ToStringPressure( ReportGroup:GetUnit(1), nil, Task )
end
if Key == "Temperature" then
elseif Key == "Temperature" then
local Coordinate = Data.Data -- Core.Point#COORDINATE
Text = Coordinate:ToStringTemperature( ReportGroup:GetUnit(1), nil, Task )
end
if Key == "Wind" then
elseif Key == "Wind" then
local Coordinate = Data.Data -- Core.Point#COORDINATE
Text = Coordinate:ToStringWind( ReportGroup:GetUnit(1), nil, Task )
end
if Key == "Cargo" then
elseif Key == "Cargo" then
local DataText = Data.Data -- #string
Text = DataText
elseif Key == "Friendlies" then
local DataText = Data.Data -- #string
Text = DataText
elseif Key == "Players" then
local DataText = Data.Data -- #string
Text = DataText
else
local DataText = Data.Data -- #string
Text = DataText
end
if Key == "Friendlies" then
local DataText = Data.Data -- #string
Text = DataText
end
if Key == "Players" then
local DataText = Data.Data -- #string
Text = DataText
end
if Line < math.floor( Data.Order / 10 ) then
if Line == 0 then
if Text ~= "" then
Report:AddIndent( LineReport:Text( ", " ), "-" )
end
Report:AddIndent( LineReport:Text( ", " ), "-" )
else
if Text ~= "" then
Report:AddIndent( LineReport:Text( ", " ) )
end
Report:AddIndent( LineReport:Text( ", " ) )
end
LineReport = REPORT:New()
Line = math.floor( Data.Order / 10 )
@ -373,8 +359,9 @@ function TASKINFO:Report( Report, Detail, ReportGroup, Task )
if Text ~= "" then
LineReport:Add( ( Key and ( Key .. ":" ) or "" ) .. Text )
end
end
end
Report:AddIndent( LineReport:Text( ", " ) )
end

View File

@ -362,7 +362,7 @@ do -- TASK_A2A
return math.random( 1, 9 )
elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Distance then
local Coordinate = self.TaskInfo:GetData( "Coordinate" )
local Distance = TaskGroup:GetCoordinate():Get2DDistance( CommandCenter:GetPositionable():GetCoordinate() )
local Distance = Coordinate:Get2DDistance( CommandCenter:GetPositionable():GetCoordinate() )
return math.floor( Distance )
elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Priority then
return 1

View File

@ -367,7 +367,8 @@ do -- TASK_A2G
return math.random( 1, 9 )
elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Distance then
local Coordinate = self.TaskInfo:GetData( "Coordinate" )
local Distance = TaskGroup:GetCoordinate():Get2DDistance( CommandCenter:GetPositionable():GetCoordinate() )
local Distance = Coordinate:Get2DDistance( CommandCenter:GetPositionable():GetCoordinate() )
self:F({Distance=Distance})
return math.floor( Distance )
elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Priority then
return 1

View File

@ -633,7 +633,7 @@ do -- TASK_A2G_DISPATCHER
--DetectedSet:Flush( self )
local DetectedItemID = DetectedItem.ID
local TaskIndex = DetectedItem.ID
local TaskIndex = DetectedItem.Index
local DetectedItemChanged = DetectedItem.Changed
self:F( { DetectedItemChanged = DetectedItemChanged, DetectedItemID = DetectedItemID, TaskIndex = TaskIndex } )
@ -649,6 +649,7 @@ do -- TASK_A2G_DISPATCHER
if TargetSetUnit then
if Task:IsInstanceOf( TASK_A2G_SEAD ) then
Task:SetTargetSetUnit( TargetSetUnit )
Task:SetDetection( Detection, DetectedItem )
Task:UpdateTaskInfo( DetectedItem )
TargetsReport:Add( Detection:GetChangeText( DetectedItem ) )
else
@ -659,7 +660,7 @@ do -- TASK_A2G_DISPATCHER
if TargetSetUnit then
if Task:IsInstanceOf( TASK_A2G_CAS ) then
Task:SetTargetSetUnit( TargetSetUnit )
Task:SetDetection( Detection, TaskIndex )
Task:SetDetection( Detection, DetectedItem )
Task:UpdateTaskInfo( DetectedItem )
TargetsReport:Add( Detection:GetChangeText( DetectedItem ) )
else
@ -671,7 +672,7 @@ do -- TASK_A2G_DISPATCHER
if TargetSetUnit then
if Task:IsInstanceOf( TASK_A2G_BAI ) then
Task:SetTargetSetUnit( TargetSetUnit )
Task:SetDetection( Detection, TaskIndex )
Task:SetDetection( Detection, DetectedItem )
Task:UpdateTaskInfo( DetectedItem )
TargetsReport:Add( Detection:GetChangeText( DetectedItem ) )
else

View File

@ -168,7 +168,10 @@ do -- TASK_CAPTURE_DISPATCHER
Zones = {},
ZoneCount = 0,
}
TASK_CAPTURE_DISPATCHER.AI_A2G_Dispatcher = nil -- AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER
--- TASK_CAPTURE_DISPATCHER constructor.
-- @param #TASK_CAPTURE_DISPATCHER self
@ -223,6 +226,19 @@ do -- TASK_CAPTURE_DISPATCHER
end
--- Link an AI_A2G_DISPATCHER to the TASK_CAPTURE_DISPATCHER.
-- @param #TASK_CAPTURE_DISPATCHER self
-- @param AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER AI_A2G_Dispatcher The AI Dispatcher to be linked to the tasking.
-- @return Tasking.Task_Capture_Zone#TASK_CAPTURE_ZONE
function TASK_CAPTURE_DISPATCHER:Link_AI_A2G_Dispatcher( AI_A2G_Dispatcher )
self.AI_A2G_Dispatcher = AI_A2G_Dispatcher -- AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER
AI_A2G_Dispatcher.Detection:LockDetectedItems()
return self
end
--- Assigns tasks to the @{Core.Set#SET_GROUP}.
-- @param #TASK_CAPTURE_DISPATCHER self
-- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop.
@ -246,6 +262,7 @@ do -- TASK_CAPTURE_DISPATCHER
-- Here we need to check if the pilot is still existing.
-- Task = self:RemoveTask( TaskIndex )
end
end
-- Now that all obsolete tasks are removed, loop through the Zone tasks.
@ -257,25 +274,54 @@ do -- TASK_CAPTURE_DISPATCHER
CaptureZone.Task.TaskPrefix = CaptureZone.TaskPrefix -- We keep the TaskPrefix for further reference!
Mission:AddTask( CaptureZone.Task )
TaskReport:Add( TaskName )
CaptureZone.Task:UpdateTaskInfo()
function CaptureZone.Task.OnEnterAssigned( Task, From, Event, To )
if self.AI_A2G_Dispatcher then
self.AI_A2G_Dispatcher:Unlock( Task.TaskZoneName ) -- This will unlock the zone to be defended by AI.
end
CaptureZone.Task:UpdateTaskInfo()
end
function CaptureZone.Task.OnEnterSuccess( Task, From, Event, To )
self:Success( Task )
--self:Success( Task )
if self.AI_A2G_Dispatcher then
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
end
CaptureZone.Task:UpdateTaskInfo()
end
function CaptureZone.Task.OnEnterCancelled( Task, From, Event, To )
self:Cancelled( Task )
if self.AI_A2G_Dispatcher then
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
end
CaptureZone.Task:UpdateTaskInfo()
end
function CaptureZone.Task.OnEnterFailed( Task, From, Event, To )
self:Failed( Task )
if self.AI_A2G_Dispatcher then
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
end
CaptureZone.Task:UpdateTaskInfo()
end
function CaptureZone.Task.OnEnterAborted( Task, From, Event, To )
self:Aborted( Task )
if self.AI_A2G_Dispatcher then
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
end
CaptureZone.Task:UpdateTaskInfo()
end
-- Now broadcast the onafterCargoPickedUp event to the Task Cargo Dispatcher.
function CaptureZone.Task.OnAfterCaptured( Task, From, Event, To, TaskUnit )
self:Captured( Task, Task.TaskPrefix, TaskUnit )
if self.AI_A2G_Dispatcher then
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
end
CaptureZone.Task:UpdateTaskInfo()
end
end

View File

@ -47,7 +47,7 @@ do -- TASK_ZONE_GOAL
-- @param Tasking.Mission#MISSION Mission
-- @param Core.Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned.
-- @param #string TaskName The name of the Task.
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal
-- @param Core.ZoneGoalCoalition#ZONE_GOAL_COALITION ZoneGoal
-- @return #TASK_ZONE_GOAL self
function TASK_ZONE_GOAL:New( Mission, SetGroup, TaskName, ZoneGoal, TaskType, TaskBriefing )
local self = BASE:Inherit( self, TASK:New( Mission, SetGroup, TaskName, TaskType, TaskBriefing ) ) -- #TASK_ZONE_GOAL
@ -211,7 +211,9 @@ do -- TASK_CAPTURE_ZONE
"Capture Zone " .. self.TaskZoneName
)
self:UpdateTaskInfo()
self:UpdateTaskInfo( true )
self:SetGoalTotal( 1 )
return self
end
@ -219,12 +221,18 @@ do -- TASK_CAPTURE_ZONE
--- Instantiates a new TASK_CAPTURE_ZONE.
-- @param #TASK_CAPTURE_ZONE self
function TASK_CAPTURE_ZONE:UpdateTaskInfo()
function TASK_CAPTURE_ZONE:UpdateTaskInfo( Persist )
Persist = Persist or false
local ZoneCoordinate = self.ZoneGoal:GetZone():GetCoordinate()
self.TaskInfo:AddCoordinate( ZoneCoordinate, 0, "SOD" )
self.TaskInfo:AddText( "Zone Name", self.ZoneGoal:GetZoneName(), 10, "MOD" )
self.TaskInfo:AddText( "Zone Coalition", self.ZoneGoal:GetCoalitionName(), 11, "MOD" )
self.TaskInfo:AddTaskName( 0, "MSOD", Persist )
self.TaskInfo:AddCoordinate( ZoneCoordinate, 1, "SOD", Persist )
self.TaskInfo:AddText( "Zone Name", self.ZoneGoal:GetZoneName(), 10, "MOD", Persist )
self.TaskInfo:AddText( "Zone Coalition", self.ZoneGoal:GetCoalitionName(), 11, "MOD", Persist )
local SetUnit = self.ZoneGoal.Zone:GetScannedSetUnit()
local ThreatLevel, ThreatText = SetUnit:CalculateThreatLevelA2G()
self.TaskInfo:AddThreat( ThreatText, ThreatLevel, 20, "MSOD", Persist )
end
@ -245,7 +253,6 @@ do -- TASK_CAPTURE_ZONE
if self.ZoneGoal then
if self.ZoneGoal.Goal:IsAchieved() then
self:Success()
local TotalContributions = self.ZoneGoal.Goal:GetTotalContributions()
local PlayerContributions = self.ZoneGoal.Goal:GetPlayerContributions()
self:F( { TotalContributions = TotalContributions, PlayerContributions = PlayerContributions } )
@ -255,6 +262,7 @@ do -- TASK_CAPTURE_ZONE
Scoring:_AddMissionGoalScore( self.Mission, PlayerName, "Zone " .. self.ZoneGoal:GetZoneName() .." captured", PlayerContribution * 200 / TotalContributions )
end
end
self:Success()
end
end
@ -272,7 +280,7 @@ do -- TASK_CAPTURE_ZONE
return math.random( 1, 9 )
elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Distance then
local Coordinate = self.TaskInfo:GetCoordinate()
local Distance = TaskGroup:GetCoordinate():Get2DDistance( CommandCenter:GetPositionable():GetCoordinate() )
local Distance = Coordinate:Get2DDistance( CommandCenter:GetPositionable():GetCoordinate() )
return math.floor( Distance )
elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Priority then
return 1

View File

@ -1101,7 +1101,7 @@ function POSITIONABLE:MessageToSetGroup( Message, Duration, MessageSetGroup, Nam
local DCSObject = self:GetDCSObject()
if DCSObject then
if DCSObject:isExist() then
MessageSetGroup:ForEachGroup(
MessageSetGroup:ForEachGroupAlive(
function( MessageGroup )
self:GetMessage( Message, Duration, Name ):ToGroup( MessageGroup )
end
@ -1479,3 +1479,33 @@ function POSITIONABLE:SmokeBlue()
end
--- Returns true if the unit is within a @{Zone}.
-- @param #STPOSITIONABLEATIC self
-- @param Core.Zone#ZONE_BASE Zone The zone to test.
-- @return #boolean Returns true if the unit is within the @{Core.Zone#ZONE_BASE}
function POSITIONABLE:IsInZone( Zone )
self:F2( { self.PositionableName, Zone } )
if self:IsAlive() then
local IsInZone = Zone:IsVec3InZone( self:GetVec3() )
return IsInZone
end
return false
end
--- Returns true if the unit is not within a @{Zone}.
-- @param #POSITIONABLE self
-- @param Core.Zone#ZONE_BASE Zone The zone to test.
-- @return #boolean Returns true if the unit is not within the @{Core.Zone#ZONE_BASE}
function POSITIONABLE:IsNotInZone( Zone )
self:F2( { self.PositionableName, Zone } )
if self:IsAlive() then
local IsNotInZone = not Zone:IsVec3InZone( self:GetVec3() )
return IsNotInZone
else
return false
end
end

View File

@ -214,35 +214,3 @@ function STATIC:ReSpawnAt( Coordinate, Heading )
SpawnStatic:ReSpawnAt( Coordinate, Heading )
end
--- Returns true if the unit is within a @{Zone}.
-- @param #STATIC self
-- @param Core.Zone#ZONE_BASE Zone The zone to test.
-- @return #boolean Returns true if the unit is within the @{Core.Zone#ZONE_BASE}
function STATIC:IsInZone( Zone )
self:F2( { self.StaticName, Zone } )
if self:IsAlive() then
local IsInZone = Zone:IsVec3InZone( self:GetVec3() )
return IsInZone
end
return false
end
--- Returns true if the unit is not within a @{Zone}.
-- @param #STATIC self
-- @param Core.Zone#ZONE_BASE Zone The zone to test.
-- @return #boolean Returns true if the unit is not within the @{Core.Zone#ZONE_BASE}
function STATIC:IsNotInZone( Zone )
self:F2( { self.StaticName, Zone } )
if self:IsAlive() then
local IsInZone = not Zone:IsVec3InZone( self:GetVec3() )
self:T( { IsInZone } )
return IsInZone
else
return false
end
end

View File

@ -348,7 +348,7 @@ end
-- @return #string Player Name
-- @return #nil The DCS Unit is not existing or alive.
function UNIT:GetPlayerName()
self:F2( self.UnitName )
self:F( self.UnitName )
local DCSUnit = self:GetDCSObject() -- DCS#Unit
@ -831,37 +831,6 @@ end
-- Is functions
--- Returns true if the unit is within a @{Zone}.
-- @param #UNIT self
-- @param Core.Zone#ZONE_BASE Zone The zone to test.
-- @return #boolean Returns true if the unit is within the @{Core.Zone#ZONE_BASE}
function UNIT:IsInZone( Zone )
self:F2( { self.UnitName, Zone } )
if self:IsAlive() then
local IsInZone = Zone:IsVec3InZone( self:GetVec3() )
return IsInZone
end
return false
end
--- Returns true if the unit is not within a @{Zone}.
-- @param #UNIT self
-- @param Core.Zone#ZONE_BASE Zone The zone to test.
-- @return #boolean Returns true if the unit is not within the @{Core.Zone#ZONE_BASE}
function UNIT:IsNotInZone( Zone )
self:F2( { self.UnitName, Zone } )
if self:IsAlive() then
local IsInZone = not Zone:IsVec3InZone( self:GetVec3() )
self:T( { IsInZone } )
return IsInZone
else
return false
end
end
--- Returns true if there is an **other** DCS Unit within a radius of the current 2D point of the DCS Unit.