From 0f9591464a67d9ff87e207d734033318b1649482 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 15 Mar 2019 09:57:50 +0100 Subject: [PATCH 01/24] First version --- Moose Development/Moose/Core/Zone.lua | 4 +- .../Moose/Functional/Detection.lua | 647 +++++++++++++++++- 2 files changed, 636 insertions(+), 15 deletions(-) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 2c00f48f5..70fb83ca3 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -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 ) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index c3eb65ccd..31f148f36 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -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,10 +540,11 @@ do -- DETECTION_BASE self.DetectedObjects[DetectionObjectName].Distance = 10000000 end - for DetectionGroupID, DetectionGroupData in pairs( self.DetectionSetGroup:GetSet() ) do + + 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:F( { DetectionGroup = DetectionData:GetName() } ) + self:__Detection( DetectDelay, DetectionData, DetectionTimeStamp ) -- Process each detection asynchronously. self.DetectionCount = self.DetectionCount + 1 DetectDelay = DetectDelay + 1 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 + @@ -2819,3 +2820,623 @@ do -- DETECTION_AREAS end end + +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 + + --- Detect units within the battle zone for a list of @{Wrapper.Group}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 DetectionSetZoneRadius The @{Set} of ZONE_RADIUS. + -- @param DCS#Coalition.side DetectionCoalition The coalition of the detection. + -- @return #DETECTION_ZONES + function DETECTION_ZONES:New( DetectionSetZoneRadius, DetectionCoalition ) + + -- Inherits from DETECTION_BASE + local self = BASE:Inherit( self, DETECTION_BASE:New() ) + + self.DetectionSetZoneRadius = DetectionSetZoneRadius + 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:GetDetectedSet( 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 + + 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 ..." ) + --self:F( { DetectedObjects = self.DetectedObjects } ) + + -- First go through all detected sets, and check if there are new detected units, match all existing detected units and identify undetected units. + -- Regroup when needed, split groups when needed. + for DetectedItemID, DetectedItemData in pairs( self.DetectedItems ) do + + local DetectedItem = DetectedItemData -- #DETECTION_BASE.DetectedItem + + if DetectedItem then + + self:T2( { "Detected Item ID: ", DetectedItemID } ) + + local Zone = DetectedItem.Zone -- Core.Zone#ZONE_RADIUS + + -- Scan the zone + Zone:Scan( { Object.Category.UNIT }, { Unit.Category.GROUND_UNIT } ) + + local ZoneUnits = Zone: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 + DetectedItem.Set: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 = DetectedItem.Set + local DetectedFirstUnit = DetectedSet:GetFirst() + local DetectedZone = DetectedItem.Zone + + -- 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.ZoneUNIT:SmokeRed() + 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:F( { DetectedObjects = self.DetectedObjects } ) + + self.DetectionRun = self.DetectionRun + 1 + + local HasDetectedObjects = false + + if Detection:IsAlive() then + + --self:T( { "DetectionGroup is Alive", DetectionGroup:GetName() } ) + + local DetectionGroupName = Detection:GetName() + local DetectionUnit = Detection:GetUnit(1) + + local DetectedUnits = {} + + local DetectedTargets = Detection:GetDetectedTargets( + self.DetectVisual, + self.DetectOptical, + self.DetectRadar, + self.DetectIRST, + self.DetectRWR, + self.DetectDLINK + ) + + self:F( { DetectedTargets = DetectedTargets } ) + + for DetectionObjectID, Detection in pairs( DetectedTargets ) do + local DetectedObject = Detection.object -- DCS#Object + + if DetectedObject and DetectedObject:isExist() and DetectedObject.id_ < 50000000 then -- and ( DetectedObject:getCategory() == Object.Category.UNIT or DetectedObject:getCategory() == Object.Category.STATIC ) then + local DetectedObjectName = DetectedObject:getName() + if not self.DetectedObjects[DetectedObjectName] then + self.DetectedObjects[DetectedObjectName] = self.DetectedObjects[DetectedObjectName] or {} + self.DetectedObjects[DetectedObjectName].Name = DetectedObjectName + self.DetectedObjects[DetectedObjectName].Object = DetectedObject + end + end + end + + for DetectionObjectName, DetectedObjectData in pairs( self.DetectedObjects ) do + + local DetectedObject = DetectedObjectData.Object + + if DetectedObject:isExist() then + + local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity = DetectionUnit:IsTargetDetected( + DetectedObject, + self.DetectVisual, + self.DetectOptical, + self.DetectRadar, + self.DetectIRST, + self.DetectRWR, + self.DetectDLINK + ) + + --self:T2( { TargetIsDetected = TargetIsDetected, TargetIsVisible = TargetIsVisible, TargetLastTime = TargetLastTime, TargetKnowType = TargetKnowType, TargetKnowDistance = TargetKnowDistance, TargetLastPos = TargetLastPos, TargetLastVelocity = TargetLastVelocity } ) + + -- Only process if the target is visible. Detection also returns invisible units. + --if Detection.visible == true then + + local DetectionAccepted = true + + local DetectedObjectName = DetectedObject:getName() + local DetectedObjectType = DetectedObject:getTypeName() + + local DetectedObjectVec3 = DetectedObject:getPoint() + local DetectedObjectVec2 = { x = DetectedObjectVec3.x, y = DetectedObjectVec3.z } + local DetectionGroupVec3 = Detection:GetVec3() + local DetectionGroupVec2 = { x = DetectionGroupVec3.x, y = DetectionGroupVec3.z } + + local Distance = ( ( DetectedObjectVec3.x - DetectionGroupVec3.x )^2 + + ( DetectedObjectVec3.y - DetectionGroupVec3.y )^2 + + ( DetectedObjectVec3.z - DetectionGroupVec3.z )^2 + ) ^ 0.5 / 1000 + + local DetectedUnitCategory = DetectedObject:getDesc().category + + --self:F( { "Detected Target:", DetectionGroupName, DetectedObjectName, DetectedObjectType, Distance, DetectedUnitCategory } ) + + -- Calculate Acceptance + + DetectionAccepted = self._.FilterCategories[DetectedUnitCategory] ~= nil and DetectionAccepted or false + + -- if Distance > 15000 then + -- if DetectedUnitCategory == Unit.Category.GROUND_UNIT or DetectedUnitCategory == Unit.Category.SHIP then + -- if DetectedObject:hasSensors( Unit.SensorType.RADAR, Unit.RadarType.AS ) == false then + -- DetectionAccepted = false + -- end + -- end + -- end + + if self.AcceptRange and Distance * 1000 > self.AcceptRange then + DetectionAccepted = false + end + + if self.AcceptZones then + local AnyZoneDetection = false + for AcceptZoneID, AcceptZone in pairs( self.AcceptZones ) do + local AcceptZone = AcceptZone -- Core.Zone#ZONE_BASE + if AcceptZone:IsVec2InZone( DetectedObjectVec2 ) then + AnyZoneDetection = true + end + end + if not AnyZoneDetection then + DetectionAccepted = false + end + end + + if self.RejectZones then + for RejectZoneID, RejectZone in pairs( self.RejectZones ) do + local RejectZone = RejectZone -- Core.Zone#ZONE_BASE + if RejectZone:IsPointVec2InZone( DetectedObjectVec2 ) == true then + DetectionAccepted = false + end + end + end + + -- Calculate additional probabilities + + if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.DistanceProbability then + local DistanceFactor = Distance / 4 + local DistanceProbabilityReversed = ( 1 - self.DistanceProbability ) * DistanceFactor + local DistanceProbability = 1 - DistanceProbabilityReversed + DistanceProbability = DistanceProbability * 30 / 300 + local Probability = math.random() -- Selects a number between 0 and 1 + --self:T( { Probability, DistanceProbability } ) + if Probability > DistanceProbability then + DetectionAccepted = false + end + end + + if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.AlphaAngleProbability then + local NormalVec2 = { x = DetectedObjectVec2.x - DetectionGroupVec2.x, y = DetectedObjectVec2.y - DetectionGroupVec2.y } + local AlphaAngle = math.atan2( NormalVec2.y, NormalVec2.x ) + local Sinus = math.sin( AlphaAngle ) + local AlphaAngleProbabilityReversed = ( 1 - self.AlphaAngleProbability ) * ( 1 - Sinus ) + local AlphaAngleProbability = 1 - AlphaAngleProbabilityReversed + + AlphaAngleProbability = AlphaAngleProbability * 30 / 300 + + local Probability = math.random() -- Selects a number between 0 and 1 + --self:T( { Probability, AlphaAngleProbability } ) + if Probability > AlphaAngleProbability then + DetectionAccepted = false + end + + end + + if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.ZoneProbability then + + for ZoneDataID, ZoneData in pairs( self.ZoneProbability ) do + self:F({ZoneData}) + local ZoneObject = ZoneData[1] -- Core.Zone#ZONE_BASE + local ZoneProbability = ZoneData[2] -- #number + ZoneProbability = ZoneProbability * 30 / 300 + + if ZoneObject:IsPointVec2InZone( DetectedObjectVec2 ) == true then + local Probability = math.random() -- Selects a number between 0 and 1 + --self:T( { Probability, ZoneProbability } ) + if Probability > ZoneProbability then + DetectionAccepted = false + break + end + end + end + end + + if DetectionAccepted then + + HasDetectedObjects = true + + self.DetectedObjects[DetectedObjectName] = self.DetectedObjects[DetectedObjectName] or {} + self.DetectedObjects[DetectedObjectName].Name = DetectedObjectName + + if TargetIsDetected and TargetIsDetected == true then + self.DetectedObjects[DetectedObjectName].IsDetected = TargetIsDetected + end + + if TargetIsDetected and TargetIsVisible and TargetIsVisible == true then + self.DetectedObjects[DetectedObjectName].IsVisible = TargetIsDetected and TargetIsVisible + end + + if TargetIsDetected and not self.DetectedObjects[DetectedObjectName].KnowType then + self.DetectedObjects[DetectedObjectName].KnowType = TargetIsDetected and TargetKnowType + end + self.DetectedObjects[DetectedObjectName].KnowDistance = TargetKnowDistance -- Detection.distance -- TargetKnowDistance + self.DetectedObjects[DetectedObjectName].LastTime = ( TargetIsDetected and TargetIsVisible == false ) and TargetLastTime + self.DetectedObjects[DetectedObjectName].LastPos = ( TargetIsDetected and TargetIsVisible == false ) and TargetLastPos + self.DetectedObjects[DetectedObjectName].LastVelocity = ( TargetIsDetected and TargetIsVisible == false ) and TargetLastVelocity + + if not self.DetectedObjects[DetectedObjectName].Distance or ( Distance and self.DetectedObjects[DetectedObjectName].Distance > Distance ) then + self.DetectedObjects[DetectedObjectName].Distance = Distance + end + + self.DetectedObjects[DetectedObjectName].DetectionTimeStamp = DetectionTimeStamp + + self:F( { DetectedObject = self.DetectedObjects[DetectedObjectName] } ) + + local DetectedUnit = UNIT:FindByName( DetectedObjectName ) + + DetectedUnits[DetectedObjectName] = DetectedUnit + else + -- if beyond the DetectionRange then nullify... + self:F( { DetectedObject = "No more detection for " .. DetectedObjectName } ) + if self.DetectedObjects[DetectedObjectName] then + self.DetectedObjects[DetectedObjectName] = nil + end + end + + --self:T2( self.DetectedObjects ) + else + -- The previously detected object does not exist anymore, delete from the cache. + self:F( "Removing from DetectedObjects: " .. DetectionObjectName ) + self.DetectedObjects[DetectionObjectName] = nil + end + end + + if HasDetectedObjects then + self:__Detected( 0.1, DetectedUnits ) + end + + end + + if self.DetectionCount > 0 and self.DetectionRun == self.DetectionCount then + + -- First check if all DetectedObjects were detected. + -- This is important. When there are DetectedObjects in the list, but were not detected, + -- And these remain undetected for more than 60 seconds, then these DetectedObjects will be flagged as not Detected. + -- IsDetected = false! + -- This is used in A2A_TASK_DISPATCHER to initiate fighter sweeping! The TASK_A2A_INTERCEPT tasks will be replaced with TASK_A2A_SWEEP tasks. + for DetectedObjectName, DetectedObject in pairs( self.DetectedObjects ) do + if self.DetectedObjects[DetectedObjectName].IsDetected == true and self.DetectedObjects[DetectedObjectName].DetectionTimeStamp + 300 <= DetectionTimeStamp then + self.DetectedObjects[DetectedObjectName].IsDetected = false + end + end + + 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 + + + end + + +end From 044b5cba7ca7ff8dfbf11d6a4306ec33896c3ef6 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 15 Mar 2019 11:01:06 +0100 Subject: [PATCH 02/24] Updates --- .../Moose/Functional/Detection.lua | 322 +++--------------- 1 file changed, 45 insertions(+), 277 deletions(-) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 31f148f36..9367f4493 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -1550,9 +1550,9 @@ 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 ) + local DetectedItem = self:AddDetectedItem( ItemPrefix, DetectedItemKey, Set ) DetectedItem.Zone = Zone @@ -2742,7 +2742,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 ) ) @@ -2867,15 +2867,15 @@ do -- DETECTION_ZONES --- DETECTION_ZONES constructor. -- @param #DETECTION_ZONES self - -- @param Core.Set#SET_ZONE_RADIUS DetectionSetZoneRadius The @{Set} of ZONE_RADIUS. + -- @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( DetectionSetZoneRadius, DetectionCoalition ) + function DETECTION_ZONES:New( DetectionSetZone, DetectionCoalition ) -- Inherits from DETECTION_BASE local self = BASE:Inherit( self, DETECTION_BASE:New() ) - self.DetectionSetZoneRadius = DetectionSetZoneRadius + self.DetectionSetZone = DetectionSetZone self.DetectionCoalition = DetectionCoalition self._SmokeDetectedUnits = false @@ -3081,33 +3081,37 @@ do -- DETECTION_ZONES self:F( "Checking Detected Items for new Detected Units ..." ) - --self:F( { DetectedObjects = self.DetectedObjects } ) + + local DetectedUnits = SET_UNIT:New() -- First go through all detected sets, and check if there are new detected units, match all existing detected units and identify undetected units. -- Regroup when needed, split groups when needed. - for DetectedItemID, DetectedItemData in pairs( self.DetectedItems ) do + for ZoneName, DetectionZone in pairs( self.DetectionSetZones:GetSet() ) do - local DetectedItem = DetectedItemData -- #DETECTION_BASE.DetectedItem + local DetectedItem = self:GetDetectedItemByKey( ZoneName ) + + if DetectedItem == nil then + DetectedItem = self:AddDetectedItemZone( "ZONE", ZoneName, nil, DetectionZone ) + end + + local DetectedItemSetUnit = self - if DetectedItem then + -- Scan the zone + DetectionZone:Scan( { Object.Category.UNIT }, { Unit.Category.GROUND_UNIT } ) - self:T2( { "Detected Item ID: ", DetectedItemID } ) - - local Zone = DetectedItem.Zone -- Core.Zone#ZONE_RADIUS - - -- Scan the zone - Zone:Scan( { Object.Category.UNIT }, { Unit.Category.GROUND_UNIT } ) - - local ZoneUnits = Zone: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 - DetectedItem.Set:AddUnit( ZoneUnit ) + 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 DetectedUnits:FindUnit( UnitName ) ~= nil then + DetectedItemSetUnit:AddUnit( ZoneUnit ) + DetectedUnits:AddUnit( ZoneUnit ) end end end + end @@ -3177,266 +3181,30 @@ do -- DETECTION_ZONES 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:F( { DetectedObjects = self.DetectedObjects } ) - - self.DetectionRun = self.DetectionRun + 1 - - local HasDetectedObjects = false - - if Detection:IsAlive() then - - --self:T( { "DetectionGroup is Alive", DetectionGroup:GetName() } ) - - local DetectionGroupName = Detection:GetName() - local DetectionUnit = Detection:GetUnit(1) - - local DetectedUnits = {} - - local DetectedTargets = Detection:GetDetectedTargets( - self.DetectVisual, - self.DetectOptical, - self.DetectRadar, - self.DetectIRST, - self.DetectRWR, - self.DetectDLINK - ) - - self:F( { DetectedTargets = DetectedTargets } ) - - for DetectionObjectID, Detection in pairs( DetectedTargets ) do - local DetectedObject = Detection.object -- DCS#Object - - if DetectedObject and DetectedObject:isExist() and DetectedObject.id_ < 50000000 then -- and ( DetectedObject:getCategory() == Object.Category.UNIT or DetectedObject:getCategory() == Object.Category.STATIC ) then - local DetectedObjectName = DetectedObject:getName() - if not self.DetectedObjects[DetectedObjectName] then - self.DetectedObjects[DetectedObjectName] = self.DetectedObjects[DetectedObjectName] or {} - self.DetectedObjects[DetectedObjectName].Name = DetectedObjectName - self.DetectedObjects[DetectedObjectName].Object = DetectedObject - end - end - end - - for DetectionObjectName, DetectedObjectData in pairs( self.DetectedObjects ) do - - local DetectedObject = DetectedObjectData.Object - - if DetectedObject:isExist() then - - local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity = DetectionUnit:IsTargetDetected( - DetectedObject, - self.DetectVisual, - self.DetectOptical, - self.DetectRadar, - self.DetectIRST, - self.DetectRWR, - self.DetectDLINK - ) - - --self:T2( { TargetIsDetected = TargetIsDetected, TargetIsVisible = TargetIsVisible, TargetLastTime = TargetLastTime, TargetKnowType = TargetKnowType, TargetKnowDistance = TargetKnowDistance, TargetLastPos = TargetLastPos, TargetLastVelocity = TargetLastVelocity } ) - - -- Only process if the target is visible. Detection also returns invisible units. - --if Detection.visible == true then - - local DetectionAccepted = true - - local DetectedObjectName = DetectedObject:getName() - local DetectedObjectType = DetectedObject:getTypeName() - - local DetectedObjectVec3 = DetectedObject:getPoint() - local DetectedObjectVec2 = { x = DetectedObjectVec3.x, y = DetectedObjectVec3.z } - local DetectionGroupVec3 = Detection:GetVec3() - local DetectionGroupVec2 = { x = DetectionGroupVec3.x, y = DetectionGroupVec3.z } - - local Distance = ( ( DetectedObjectVec3.x - DetectionGroupVec3.x )^2 + - ( DetectedObjectVec3.y - DetectionGroupVec3.y )^2 + - ( DetectedObjectVec3.z - DetectionGroupVec3.z )^2 - ) ^ 0.5 / 1000 - - local DetectedUnitCategory = DetectedObject:getDesc().category - - --self:F( { "Detected Target:", DetectionGroupName, DetectedObjectName, DetectedObjectType, Distance, DetectedUnitCategory } ) - - -- Calculate Acceptance - - DetectionAccepted = self._.FilterCategories[DetectedUnitCategory] ~= nil and DetectionAccepted or false - - -- if Distance > 15000 then - -- if DetectedUnitCategory == Unit.Category.GROUND_UNIT or DetectedUnitCategory == Unit.Category.SHIP then - -- if DetectedObject:hasSensors( Unit.SensorType.RADAR, Unit.RadarType.AS ) == false then - -- DetectionAccepted = false - -- end - -- end - -- end - - if self.AcceptRange and Distance * 1000 > self.AcceptRange then - DetectionAccepted = false - end - - if self.AcceptZones then - local AnyZoneDetection = false - for AcceptZoneID, AcceptZone in pairs( self.AcceptZones ) do - local AcceptZone = AcceptZone -- Core.Zone#ZONE_BASE - if AcceptZone:IsVec2InZone( DetectedObjectVec2 ) then - AnyZoneDetection = true - end - end - if not AnyZoneDetection then - DetectionAccepted = false - end - end - - if self.RejectZones then - for RejectZoneID, RejectZone in pairs( self.RejectZones ) do - local RejectZone = RejectZone -- Core.Zone#ZONE_BASE - if RejectZone:IsPointVec2InZone( DetectedObjectVec2 ) == true then - DetectionAccepted = false - end - end - end - - -- Calculate additional probabilities - - if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.DistanceProbability then - local DistanceFactor = Distance / 4 - local DistanceProbabilityReversed = ( 1 - self.DistanceProbability ) * DistanceFactor - local DistanceProbability = 1 - DistanceProbabilityReversed - DistanceProbability = DistanceProbability * 30 / 300 - local Probability = math.random() -- Selects a number between 0 and 1 - --self:T( { Probability, DistanceProbability } ) - if Probability > DistanceProbability then - DetectionAccepted = false - end - end - - if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.AlphaAngleProbability then - local NormalVec2 = { x = DetectedObjectVec2.x - DetectionGroupVec2.x, y = DetectedObjectVec2.y - DetectionGroupVec2.y } - local AlphaAngle = math.atan2( NormalVec2.y, NormalVec2.x ) - local Sinus = math.sin( AlphaAngle ) - local AlphaAngleProbabilityReversed = ( 1 - self.AlphaAngleProbability ) * ( 1 - Sinus ) - local AlphaAngleProbability = 1 - AlphaAngleProbabilityReversed - - AlphaAngleProbability = AlphaAngleProbability * 30 / 300 - - local Probability = math.random() -- Selects a number between 0 and 1 - --self:T( { Probability, AlphaAngleProbability } ) - if Probability > AlphaAngleProbability then - DetectionAccepted = false - end - - end - - if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.ZoneProbability then - - for ZoneDataID, ZoneData in pairs( self.ZoneProbability ) do - self:F({ZoneData}) - local ZoneObject = ZoneData[1] -- Core.Zone#ZONE_BASE - local ZoneProbability = ZoneData[2] -- #number - ZoneProbability = ZoneProbability * 30 / 300 - - if ZoneObject:IsPointVec2InZone( DetectedObjectVec2 ) == true then - local Probability = math.random() -- Selects a number between 0 and 1 - --self:T( { Probability, ZoneProbability } ) - if Probability > ZoneProbability then - DetectionAccepted = false - break - end - end - end - end - - if DetectionAccepted then - - HasDetectedObjects = true - - self.DetectedObjects[DetectedObjectName] = self.DetectedObjects[DetectedObjectName] or {} - self.DetectedObjects[DetectedObjectName].Name = DetectedObjectName - - if TargetIsDetected and TargetIsDetected == true then - self.DetectedObjects[DetectedObjectName].IsDetected = TargetIsDetected - end - - if TargetIsDetected and TargetIsVisible and TargetIsVisible == true then - self.DetectedObjects[DetectedObjectName].IsVisible = TargetIsDetected and TargetIsVisible - end - - if TargetIsDetected and not self.DetectedObjects[DetectedObjectName].KnowType then - self.DetectedObjects[DetectedObjectName].KnowType = TargetIsDetected and TargetKnowType - end - self.DetectedObjects[DetectedObjectName].KnowDistance = TargetKnowDistance -- Detection.distance -- TargetKnowDistance - self.DetectedObjects[DetectedObjectName].LastTime = ( TargetIsDetected and TargetIsVisible == false ) and TargetLastTime - self.DetectedObjects[DetectedObjectName].LastPos = ( TargetIsDetected and TargetIsVisible == false ) and TargetLastPos - self.DetectedObjects[DetectedObjectName].LastVelocity = ( TargetIsDetected and TargetIsVisible == false ) and TargetLastVelocity - - if not self.DetectedObjects[DetectedObjectName].Distance or ( Distance and self.DetectedObjects[DetectedObjectName].Distance > Distance ) then - self.DetectedObjects[DetectedObjectName].Distance = Distance - end - - self.DetectedObjects[DetectedObjectName].DetectionTimeStamp = DetectionTimeStamp - - self:F( { DetectedObject = self.DetectedObjects[DetectedObjectName] } ) - - local DetectedUnit = UNIT:FindByName( DetectedObjectName ) - - DetectedUnits[DetectedObjectName] = DetectedUnit - else - -- if beyond the DetectionRange then nullify... - self:F( { DetectedObject = "No more detection for " .. DetectedObjectName } ) - if self.DetectedObjects[DetectedObjectName] then - self.DetectedObjects[DetectedObjectName] = nil - end - end - - --self:T2( self.DetectedObjects ) - else - -- The previously detected object does not exist anymore, delete from the cache. - self:F( "Removing from DetectedObjects: " .. DetectionObjectName ) - self.DetectedObjects[DetectionObjectName] = nil - end - end - - if HasDetectedObjects then - self:__Detected( 0.1, DetectedUnits ) - end - - end - - if self.DetectionCount > 0 and self.DetectionRun == self.DetectionCount then - - -- First check if all DetectedObjects were detected. - -- This is important. When there are DetectedObjects in the list, but were not detected, - -- And these remain undetected for more than 60 seconds, then these DetectedObjects will be flagged as not Detected. - -- IsDetected = false! - -- This is used in A2A_TASK_DISPATCHER to initiate fighter sweeping! The TASK_A2A_INTERCEPT tasks will be replaced with TASK_A2A_SWEEP tasks. - for DetectedObjectName, DetectedObject in pairs( self.DetectedObjects ) do - if self.DetectedObjects[DetectedObjectName].IsDetected == true and self.DetectedObjects[DetectedObjectName].DetectionTimeStamp + 300 <= DetectionTimeStamp then - self.DetectedObjects[DetectedObjectName].IsDetected = false - 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: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 + 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 - - self:__Detect( self.RefreshTimeInterval ) end + + self:__Detect( self.RefreshTimeInterval ) end - end + end From 3b520ab0c413b9fcf230caa8c502160b646e58db Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 15 Mar 2019 12:39:06 +0100 Subject: [PATCH 03/24] New detection method based on zones and scanning. --- .../Moose/AI/AI_A2A_Dispatcher.lua | 2 +- Moose Development/Moose/Core/Set.lua | 2 +- .../Moose/Functional/Designate.lua | 10 +- .../Moose/Functional/Detection.lua | 416 +----------------- .../Moose/Functional/DetectionZones.lua | 403 +++++++++++++++++ Moose Development/Moose/Functional/Escort.lua | 8 +- Moose Development/Moose/Modules.lua | 1 + 7 files changed, 431 insertions(+), 411 deletions(-) create mode 100644 Moose Development/Moose/Functional/DetectionZones.lua diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 9b9370bb3..7396cb7a6 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -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() diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index e4e2c3edf..eb210335a 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -148,7 +148,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. diff --git a/Moose Development/Moose/Functional/Designate.lua b/Moose Development/Moose/Functional/Designate.lua index b8b1c24bb..7d6f09d26 100644 --- a/Moose Development/Moose/Functional/Designate.lua +++ b/Moose Development/Moose/Functional/Designate.lua @@ -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 @@ -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 diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 9367f4493..d44edf334 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -541,11 +541,11 @@ do -- DETECTION_BASE end + self.DetectionCount = self.DetectionSet:Count() for DetectionID, DetectionData in pairs( self.DetectionSet:GetSet() ) do --self:F( { DetectionGroupData } ) self:F( { DetectionGroup = DetectionData:GetName() } ) self:__Detection( DetectDelay, DetectionData, DetectionTimeStamp ) -- Process each detection asynchronously. - self.DetectionCount = self.DetectionCount + 1 DetectDelay = DetectDelay + 1 end end @@ -839,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 @@ -1552,6 +1552,8 @@ do -- DETECTION_BASE -- @return #DETECTION_BASE.DetectedItem function DETECTION_BASE:AddDetectedItemZone( ItemPrefix, DetectedItemKey, Set, Zone ) + self:F( { ItemPrefix, DetectedItemKey, Set, Zone } ) + local DetectedItem = self:AddDetectedItem( ItemPrefix, DetectedItemKey, Set ) DetectedItem.Zone = Zone @@ -1662,7 +1664,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 @@ -1811,13 +1813,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. @@ -1829,7 +1831,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 @@ -2034,7 +2036,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 ) @@ -2269,7 +2271,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 @@ -2287,7 +2289,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 ) @@ -2409,7 +2411,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 ) @@ -2774,7 +2776,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 @@ -2821,390 +2823,4 @@ do -- DETECTION_AREAS end -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 - - --- Detect units within the battle zone for a list of @{Wrapper.Group}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() ) - - 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:GetDetectedSet( 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 - - 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 detected sets, and check if there are new detected units, match all existing detected units and identify undetected units. - -- Regroup when needed, split groups when needed. - for ZoneName, DetectionZone in pairs( self.DetectionSetZones:GetSet() ) do - - local DetectedItem = self:GetDetectedItemByKey( ZoneName ) - - if DetectedItem == nil then - DetectedItem = self:AddDetectedItemZone( "ZONE", ZoneName, nil, DetectionZone ) - end - - local DetectedItemSetUnit = self - - -- Scan the zone - DetectionZone:Scan( { Object.Category.UNIT }, { Unit.Category.GROUND_UNIT } ) - - 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 DetectedUnits:FindUnit( UnitName ) ~= nil then - 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 = DetectedItem.Set - local DetectedFirstUnit = DetectedSet:GetFirst() - local DetectedZone = DetectedItem.Zone - -- 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.ZoneUNIT:SmokeRed() - 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: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 diff --git a/Moose Development/Moose/Functional/DetectionZones.lua b/Moose Development/Moose/Functional/DetectionZones.lua new file mode 100644 index 000000000..614dce0ec --- /dev/null +++ b/Moose Development/Moose/Functional/DetectionZones.lua @@ -0,0 +1,403 @@ +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 + + 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 detected sets, and check if there are new detected units, match all existing detected units and identify undetected units. + -- Regroup when needed, split groups when needed. + for 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 } ) + + 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 \ No newline at end of file diff --git a/Moose Development/Moose/Functional/Escort.lua b/Moose Development/Moose/Functional/Escort.lua index 89d77425c..43686ba06 100644 --- a/Moose Development/Moose/Functional/Escort.lua +++ b/Moose Development/Moose/Functional/Escort.lua @@ -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 = {} diff --git a/Moose Development/Moose/Modules.lua b/Moose Development/Moose/Modules.lua index 5909ab54a..162e605fd 100644 --- a/Moose Development/Moose/Modules.lua +++ b/Moose Development/Moose/Modules.lua @@ -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' ) From 87a44f7f7f430eba90bfb2746e7e4f3bcc2ff2fd Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 15 Mar 2019 13:08:48 +0100 Subject: [PATCH 04/24] Still need to fix that index issue. --- .../Moose/AI/AI_A2G_Dispatcher.lua | 2 ++ .../Moose/Functional/Detection.lua | 4 ++- .../Moose/Functional/DetectionZones.lua | 32 +++++++++---------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua index 0e64be634..d87424f98 100644 --- a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua @@ -3983,7 +3983,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( { Target = DefenderTask.Target } ) local AttackerItem = Detection:GetDetectedItemByIndex( DefenderTask.Target.Index ) if not AttackerItem then self:F( { "Removing obsolete Target:", DefenderTask.Target.Index } ) diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index d44edf334..e07c092be 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -1627,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 diff --git a/Moose Development/Moose/Functional/DetectionZones.lua b/Moose Development/Moose/Functional/DetectionZones.lua index 614dce0ec..0b10e2b44 100644 --- a/Moose Development/Moose/Functional/DetectionZones.lua +++ b/Moose Development/Moose/Functional/DetectionZones.lua @@ -127,22 +127,22 @@ do -- DETECTION_ZONES 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 - +-- 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 From fb23ac1d55fc32f74b7768a187d6b2c498a53069 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 16 Mar 2019 09:51:09 +0100 Subject: [PATCH 05/24] Updates to make the tasking work correctly. --- Moose Development/Moose/AI/AI_A2G_Dispatcher.lua | 2 +- Moose Development/Moose/Core/Set.lua | 14 ++++++++++++++ Moose Development/Moose/Functional/Detection.lua | 16 ++++++---------- .../Moose/Functional/DetectionZones.lua | 11 +++++------ .../Moose/Tasking/Task_A2G_Dispatcher.lua | 7 ++++--- 5 files changed, 30 insertions(+), 20 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua index d87424f98..fad800e7d 100644 --- a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua @@ -3985,7 +3985,7 @@ do -- AI_A2G_DISPATCHER else -- TODO: prio 1, what is this index stuff again, simplify it. if DefenderTask.Target then - self:F( { Target = DefenderTask.Target } ) + 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 } ) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index eb210335a..4399c92f7 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -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 diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index e07c092be..6bebb8c5d 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -1524,18 +1524,14 @@ do -- DETECTION_BASE local DetectedItem = {} 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 - + + self.DetectedItems[DetectedItemKey] = DetectedItem + + local DetectedItemIndex = DetectedItemKey or self.DetectedItemMax + self.DetectedItemsByIndex[DetectedItemIndex] = DetectedItem + DetectedItem.Index = DetectedItemIndex 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 diff --git a/Moose Development/Moose/Functional/DetectionZones.lua b/Moose Development/Moose/Functional/DetectionZones.lua index 0b10e2b44..c44ef9efe 100644 --- a/Moose Development/Moose/Functional/DetectionZones.lua +++ b/Moose Development/Moose/Functional/DetectionZones.lua @@ -261,8 +261,8 @@ do -- DETECTION_ZONES local DetectedUnits = SET_UNIT:New() - -- First go through all detected sets, and check if there are new detected units, match all existing detected units and identify undetected units. - -- Regroup when needed, split groups when needed. + -- 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 ) @@ -276,6 +276,8 @@ do -- DETECTION_ZONES -- 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() @@ -289,11 +291,8 @@ do -- DETECTION_ZONES 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. diff --git a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua index 499efcf89..b7ae6ba17 100644 --- a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua @@ -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 From cff4f60923a692130acbbd66a8032e1ae32634de Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 16 Mar 2019 12:13:39 +0100 Subject: [PATCH 06/24] Improvements on reporting. --- Moose Development/Moose/Tasking/TaskInfo.lua | 57 +++++++------------ .../Moose/Tasking/Task_Capture_Dispatcher.lua | 10 +++- .../Moose/Tasking/Task_Capture_Zone.lua | 11 ++-- 3 files changed, 37 insertions(+), 41 deletions(-) diff --git a/Moose Development/Moose/Tasking/TaskInfo.lua b/Moose Development/Moose/Tasking/TaskInfo.lua index 95c14ee58..0e7c54885 100644 --- a/Moose Development/Moose/Tasking/TaskInfo.lua +++ b/Moose Development/Moose/Tasking/TaskInfo.lua @@ -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 diff --git a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua index d37ad7d5d..c38ed065f 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua @@ -246,6 +246,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 +258,32 @@ 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.OnEnterSuccess( Task, From, Event, To ) self:Success( Task ) + CaptureZone.Task:UpdateTaskInfo() end function CaptureZone.Task.OnEnterCancelled( Task, From, Event, To ) self:Cancelled( Task ) + CaptureZone.Task:UpdateTaskInfo() end - + function CaptureZone.Task.OnEnterFailed( Task, From, Event, To ) self:Failed( Task ) + CaptureZone.Task:UpdateTaskInfo() end function CaptureZone.Task.OnEnterAborted( Task, From, Event, To ) self:Aborted( Task ) + 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 ) + CaptureZone.Task:UpdateTaskInfo() end end diff --git a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua index 8a56784ea..589a35c3c 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua @@ -219,12 +219,13 @@ 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( DetectedItem ) + 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", true ) + self.TaskInfo:AddCoordinate( ZoneCoordinate, 1, "SOD", true ) + self.TaskInfo:AddText( "Zone Name", self.ZoneGoal:GetZoneName(), 10, "MOD", true ) + self.TaskInfo:AddText( "Zone Coalition", self.ZoneGoal:GetCoalitionName(), 11, "MOD", true ) end From 837361e899e28628c34b8a470d0db0c028538ea4 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 16 Mar 2019 12:57:14 +0100 Subject: [PATCH 07/24] Updates --- Moose Development/Moose/Tasking/Task_Capture_Zone.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua index 589a35c3c..79d4817df 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua @@ -226,6 +226,8 @@ do -- TASK_CAPTURE_ZONE self.TaskInfo:AddCoordinate( ZoneCoordinate, 1, "SOD", true ) self.TaskInfo:AddText( "Zone Name", self.ZoneGoal:GetZoneName(), 10, "MOD", true ) self.TaskInfo:AddText( "Zone Coalition", self.ZoneGoal:GetCoalitionName(), 11, "MOD", true ) + --local ThreatLevel, ThreatText = self.TargetSetUnit:CalculateThreatLevelA2G() + --self.TaskInfo:AddThreat( ThreatText, ThreatLevel, 10, "MOD", true ) end From 0ea5c7fa48bc0e9ca17274d8bec45c30f5a0cfcd Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sun, 17 Mar 2019 07:33:28 +0100 Subject: [PATCH 08/24] Updated bug in Detection and other classes. Now only alive units are considered when broadcasting a message to a SET_GROUP. Made DESIGNATE crash in certain cases. --- Moose Development/Moose/Functional/Designate.lua | 2 +- Moose Development/Moose/Functional/Detection.lua | 10 +++++----- Moose Development/Moose/Wrapper/Positionable.lua | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Functional/Designate.lua b/Moose Development/Moose/Functional/Designate.lua index 7d6f09d26..a11aa21b8 100644 --- a/Moose Development/Moose/Functional/Designate.lua +++ b/Moose Development/Moose/Functional/Designate.lua @@ -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 diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 6bebb8c5d..76b3d0274 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -1524,12 +1524,12 @@ do -- DETECTION_BASE local DetectedItem = {} self.DetectedItemCount = self.DetectedItemCount + 1 self.DetectedItemMax = self.DetectedItemMax + 1 - + + + DetectedItemKey = DetectedItemKey or self.DetectedItemMax self.DetectedItems[DetectedItemKey] = DetectedItem - - local DetectedItemIndex = DetectedItemKey or self.DetectedItemMax - self.DetectedItemsByIndex[DetectedItemIndex] = DetectedItem - DetectedItem.Index = DetectedItemIndex + self.DetectedItemsByIndex[DetectedItemKey] = DetectedItem + DetectedItem.Index = DetectedItemKey DetectedItem.Set = Set or SET_UNIT:New():FilterDeads():FilterCrashes() DetectedItem.ItemID = ItemPrefix .. "." .. self.DetectedItemMax diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 70d7a3c15..09d17a92c 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -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 From ece7fc3ea9dfe5a10e634e308975a4604ba1e8bd Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sun, 17 Mar 2019 08:20:42 +0100 Subject: [PATCH 09/24] Threat level report for TASK_CAPTURE_ZONE --- .../Moose/AI/AI_A2G_Dispatcher.lua | 20 ++++++++++++++++--- Moose Development/Moose/Core/Zone.lua | 14 +++++++++++++ .../Moose/Tasking/DetectionManager.lua | 2 ++ Moose Development/Moose/Tasking/TaskInfo.lua | 2 +- .../Moose/Tasking/Task_Capture_Zone.lua | 7 ++++--- 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua index fad800e7d..2a568b220 100644 --- a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua @@ -3467,6 +3467,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 +3578,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 diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 70fb83ca3..8c6d420e6 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -704,6 +704,20 @@ 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 + SetUnit:AddUnit( UNIT:FindByName(UnitObject:getName() ) ) + end + end + + return SetUnit +end + + function ZONE_RADIUS:CountScannedCoalitions() local Count = 0 diff --git a/Moose Development/Moose/Tasking/DetectionManager.lua b/Moose Development/Moose/Tasking/DetectionManager.lua index 04eab84a8..b641ac1c3 100644 --- a/Moose Development/Moose/Tasking/DetectionManager.lua +++ b/Moose Development/Moose/Tasking/DetectionManager.lua @@ -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 ) diff --git a/Moose Development/Moose/Tasking/TaskInfo.lua b/Moose Development/Moose/Tasking/TaskInfo.lua index 0e7c54885..8f2d6231a 100644 --- a/Moose Development/Moose/Tasking/TaskInfo.lua +++ b/Moose Development/Moose/Tasking/TaskInfo.lua @@ -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 diff --git a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua index 79d4817df..aa41cd7de 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua @@ -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 @@ -226,8 +226,9 @@ do -- TASK_CAPTURE_ZONE self.TaskInfo:AddCoordinate( ZoneCoordinate, 1, "SOD", true ) self.TaskInfo:AddText( "Zone Name", self.ZoneGoal:GetZoneName(), 10, "MOD", true ) self.TaskInfo:AddText( "Zone Coalition", self.ZoneGoal:GetCoalitionName(), 11, "MOD", true ) - --local ThreatLevel, ThreatText = self.TargetSetUnit:CalculateThreatLevelA2G() - --self.TaskInfo:AddThreat( ThreatText, ThreatLevel, 10, "MOD", true ) + local SetUnit = self.ZoneGoal.Zone:GetScannedSetUnit() + local ThreatLevel, ThreatText = SetUnit:CalculateThreatLevelA2G() + self.TaskInfo:AddThreat( ThreatText, ThreatLevel, 20, "MOD", true ) end From 02a486e457e2eb5b0c09c2c6e2e817e93bac1eb5 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Mon, 18 Mar 2019 18:04:08 +0100 Subject: [PATCH 10/24] In progress. --- .../Moose/AI/AI_A2G_Dispatcher.lua | 6 ++++++ .../Moose/Functional/ZoneCaptureCoalition.lua | 6 +++--- .../Moose/Tasking/Task_Capture_Dispatcher.lua | 21 +++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua index 2a568b220..034b2ba06 100644 --- a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua @@ -1148,6 +1148,12 @@ do -- AI_A2G_DISPATCHER end + --- Locks the DefenseItem from being defended. + -- @param #AI_A2G_DISPATCHER self + -- @param #string DefenseItemKey The key of the defense item. + + + --- @param #AI_A2G_DISPATCHER self function AI_A2G_DISPATCHER:ResourcePark( DefenderSquadron ) diff --git a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua index 6d36beae0..32a860aa8 100644 --- a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua +++ b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua @@ -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 diff --git a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua index c38ed065f..514c355d0 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua @@ -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,18 @@ 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 + + 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. @@ -259,6 +274,11 @@ do -- TASK_CAPTURE_DISPATCHER Mission:AddTask( CaptureZone.Task ) TaskReport:Add( TaskName ) CaptureZone.Task:UpdateTaskInfo() + + function CaptureZone.Task.OnEnterAssigned( Task, From, Event, To ) + self.AI_A2G_Dispatcher:Unlock( Task.TaskZoneName ) -- This will unlock the zone to be defended by AI. + CaptureZone.Task:UpdateTaskInfo() + end function CaptureZone.Task.OnEnterSuccess( Task, From, Event, To ) self:Success( Task ) @@ -267,6 +287,7 @@ do -- TASK_CAPTURE_DISPATCHER function CaptureZone.Task.OnEnterCancelled( Task, From, Event, To ) self:Cancelled( Task ) + self.AI_A2G_Dispatcher:Unlock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI. CaptureZone.Task:UpdateTaskInfo() end From 70e7857b627a7a7055ca9c1bf0bcc484c0f38f08 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Mon, 18 Mar 2019 19:53:12 +0100 Subject: [PATCH 11/24] Implemented the linking of TASK_CAPTURE_DISPATCHER and AI_A2G_DISPATCHER. --- .../Moose/AI/AI_A2G_Dispatcher.lua | 193 ++++++++++-------- .../Moose/Functional/Detection.lua | 66 ++++++ .../Moose/Tasking/Task_Capture_Dispatcher.lua | 21 +- 3 files changed, 193 insertions(+), 87 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua index 034b2ba06..825d2e124 100644 --- a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua @@ -1126,7 +1126,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 @@ -1150,9 +1150,30 @@ do -- AI_A2G_DISPATCHER --- Locks the DefenseItem from being defended. -- @param #AI_A2G_DISPATCHER self - -- @param #string DefenseItemKey The key of the defense item. + -- @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 + --- @param #AI_A2G_DISPATCHER self @@ -4032,100 +4053,102 @@ do -- AI_A2G_DISPATCHER -- Now that all obsolete tasks are removed, loop through the detected targets. for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) 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 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 + + self:F( { "Target ID", DetectedItem.ItemID } ) + DetectedSet:Flush( self ) + + local DetectedID = DetectedItem.ID + local DetectionIndex = DetectedItem.Index + local DetectedItemChanged = DetectedItem.Changed - if EvaluateDistance <= self.DefenseRadius then + local AttackCoordinate = self.Detection:GetDetectedItemCoordinate( DetectedItem ) - local DistanceProbability = ( self.DefenseRadius / EvaluateDistance * self.DefenseReactivity ) - local DefenseProbability = math.random() + -- 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 ) - self:F( { DistanceProbability = DistanceProbability, DefenseProbability = DefenseProbability } ) + if EvaluateDistance <= self.DefenseRadius then - if DefenseProbability <= DistanceProbability / ( 300 / 30 ) then - EngageCoordinate = DefenseCoordinate - break + 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 - 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 ) + + 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 + + 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 + + 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 ) + end 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 and DefendersMissing > 0 then - self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } ) - self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "CAS", EngageCoordinate ) - 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 - 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 ) - 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 ) ) ) - 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 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 diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index 76b3d0274..99f98848b 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -1536,6 +1536,10 @@ do -- DETECTION_BASE DetectedItem.ID = self.DetectedItemMax DetectedItem.Removed = false + if self.Locking then + self:LockDetectedItem( DetectedItem ) + end + return DetectedItem end @@ -1725,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 diff --git a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua index 514c355d0..3fc4a86c8 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua @@ -233,6 +233,7 @@ do -- TASK_CAPTURE_DISPATCHER 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 @@ -276,34 +277,50 @@ do -- TASK_CAPTURE_DISPATCHER CaptureZone.Task:UpdateTaskInfo() function CaptureZone.Task.OnEnterAssigned( Task, From, Event, To ) - self.AI_A2G_Dispatcher:Unlock( Task.TaskZoneName ) -- This will unlock the zone to be defended by AI. + 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 ) + 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 ) - self.AI_A2G_Dispatcher:Unlock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI. + 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 From d9d9235fba2dfdb86929faf248733a4799b6a577 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 19 Mar 2019 19:34:28 +0100 Subject: [PATCH 12/24] Great new additions: - Defense tactics (SetDefenseApproach) now can be: AI_A2G_DISPATCHER.DefenseApproach.Random -- random detected item AI_A2G_DISPATCHER.DefenseApproach.Distance -- shortest distance between defense point and detected item. --- .../Moose/AI/AI_A2G_Dispatcher.lua | 100 ++++++++++++++---- 1 file changed, 81 insertions(+), 19 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua index 825d2e124..557c9bc13 100644 --- a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua @@ -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. @@ -1175,6 +1182,26 @@ do -- AI_A2G_DISPATCHER 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 ) @@ -3927,7 +3954,7 @@ do -- AI_A2G_DISPATCHER end end - return nil, nil, nil + return 0, 0, 0 end @@ -3960,7 +3987,7 @@ do -- AI_A2G_DISPATCHER end end - return nil, nil, nil + return 0, 0, 0 end @@ -3993,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 @@ -4049,9 +4094,11 @@ 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 if not self.Detection:IsDetectedItemLocked( DetectedItem ) == true then local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem @@ -4060,6 +4107,8 @@ do -- AI_A2G_DISPATCHER local DetectedZone = DetectedItem.Zone self:F( { "Target ID", DetectedItem.ItemID } ) + + self:F( { DefenseLimit = self.DefenseLimitmit, DefenseTotal = DefenseTotal } ) DetectedSet:Flush( self ) local DetectedID = DetectedItem.ID @@ -4086,17 +4135,24 @@ do -- AI_A2G_DISPATCHER self:F( { DistanceProbability = DistanceProbability, DefenseProbability = DefenseProbability } ) - if DefenseProbability <= DistanceProbability / ( 300 / 30 ) then + 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 - if EngageCoordinate then + 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 and DefendersMissing > 0 then + if DefendersMissing > 0 then self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } ) self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "SEAD", EngageCoordinate ) end @@ -4104,7 +4160,7 @@ do -- AI_A2G_DISPATCHER 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 + if DefendersMissing > 0 then self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } ) self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "CAS", EngageCoordinate ) end @@ -4112,20 +4168,26 @@ do -- AI_A2G_DISPATCHER 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 + if DefendersMissing > 0 then self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } ) self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "BAI", EngageCoordinate ) 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 + + for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do + local Defender = Defender -- Wrapper.Group#GROUP + 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 From 3f8468dcc7354caeea50715c6c97e0946ebc6aeb Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 19 Mar 2019 21:50:34 +0100 Subject: [PATCH 13/24] Fixed shortest distance to airbase. --- Moose Development/Moose/Tasking/Task_A2A.lua | 2 +- Moose Development/Moose/Tasking/Task_A2G.lua | 3 ++- .../Moose/Tasking/Task_Capture_Zone.lua | 14 ++++++++------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task_A2A.lua b/Moose Development/Moose/Tasking/Task_A2A.lua index bb91c02bb..0f11ba4c9 100644 --- a/Moose Development/Moose/Tasking/Task_A2A.lua +++ b/Moose Development/Moose/Tasking/Task_A2A.lua @@ -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 diff --git a/Moose Development/Moose/Tasking/Task_A2G.lua b/Moose Development/Moose/Tasking/Task_A2G.lua index af0d25160..bb2e2f816 100644 --- a/Moose Development/Moose/Tasking/Task_A2G.lua +++ b/Moose Development/Moose/Tasking/Task_A2G.lua @@ -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 diff --git a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua index aa41cd7de..dae324456 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua @@ -221,14 +221,16 @@ do -- TASK_CAPTURE_ZONE -- @param #TASK_CAPTURE_ZONE self function TASK_CAPTURE_ZONE:UpdateTaskInfo( DetectedItem ) + self:F({"Update"}) + local ZoneCoordinate = self.ZoneGoal:GetZone():GetCoordinate() - self.TaskInfo:AddTaskName( 0, "MSOD", true ) - self.TaskInfo:AddCoordinate( ZoneCoordinate, 1, "SOD", true ) - self.TaskInfo:AddText( "Zone Name", self.ZoneGoal:GetZoneName(), 10, "MOD", true ) - self.TaskInfo:AddText( "Zone Coalition", self.ZoneGoal:GetCoalitionName(), 11, "MOD", true ) + self.TaskInfo:AddTaskName( 0, "MSOD" ) + self.TaskInfo:AddCoordinate( ZoneCoordinate, 1, "SOD" ) + self.TaskInfo:AddText( "Zone Name", self.ZoneGoal:GetZoneName(), 10, "MOD" ) + self.TaskInfo:AddText( "Zone Coalition", self.ZoneGoal:GetCoalitionName(), 11, "MOD" ) local SetUnit = self.ZoneGoal.Zone:GetScannedSetUnit() local ThreatLevel, ThreatText = SetUnit:CalculateThreatLevelA2G() - self.TaskInfo:AddThreat( ThreatText, ThreatLevel, 20, "MOD", true ) + self.TaskInfo:AddThreat( ThreatText, ThreatLevel, 20, "MOD" ) end @@ -276,7 +278,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 From 985282ba555a24d53f4d4f0992c29daf715f9dd6 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Wed, 20 Mar 2019 18:03:24 +0100 Subject: [PATCH 14/24] Debug --- Moose Development/Moose/Wrapper/Group.lua | 3 +++ Moose Development/Moose/Wrapper/Unit.lua | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index a790deddd..afe7667f2 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -2107,8 +2107,11 @@ do -- Players local PlayerNames = {} + self:F({Group = self:GetName()}) + local Units = self:GetUnits() for UnitID, UnitData in pairs( Units ) do + self:F({UnitData:GetName()}) local Unit = UnitData -- Wrapper.Unit#UNIT local PlayerName = Unit:GetPlayerName() if PlayerName and PlayerName ~= "" then diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 91d157515..51b5f2ecb 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -324,13 +324,16 @@ 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 if DCSUnit then + self:F({self:GetName()}) + local PlayerName = DCSUnit:getPlayerName() + self:F({PlayerName = PlayerName}) -- TODO Workaround DCS-BUG-3 - https://github.com/FlightControl-Master/MOOSE/issues/696 -- if PlayerName == nil or PlayerName == "" then -- local PlayerCategory = DCSUnit:getDesc().category From 964a6d07088b3000da95239b0df5d3643a29c8c6 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Wed, 20 Mar 2019 18:15:37 +0100 Subject: [PATCH 15/24] Debug --- Moose Development/Moose/Tasking/Task.lua | 2 +- Moose Development/Moose/Wrapper/Group.lua | 3 --- Moose Development/Moose/Wrapper/Unit.lua | 3 --- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index a99012590..797de7d61 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -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 diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index afe7667f2..a790deddd 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -2107,11 +2107,8 @@ do -- Players local PlayerNames = {} - self:F({Group = self:GetName()}) - local Units = self:GetUnits() for UnitID, UnitData in pairs( Units ) do - self:F({UnitData:GetName()}) local Unit = UnitData -- Wrapper.Unit#UNIT local PlayerName = Unit:GetPlayerName() if PlayerName and PlayerName ~= "" then diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 51b5f2ecb..363e42e08 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -330,10 +330,7 @@ function UNIT:GetPlayerName() if DCSUnit then - self:F({self:GetName()}) - local PlayerName = DCSUnit:getPlayerName() - self:F({PlayerName = PlayerName}) -- TODO Workaround DCS-BUG-3 - https://github.com/FlightControl-Master/MOOSE/issues/696 -- if PlayerName == nil or PlayerName == "" then -- local PlayerCategory = DCSUnit:getDesc().category From d9fb9c49282a9754e3edffe4dd26c55a2871322c Mon Sep 17 00:00:00 2001 From: FlightControl Date: Wed, 20 Mar 2019 18:36:55 +0100 Subject: [PATCH 16/24] Report Mission fix --- Moose Development/Moose/Tasking/CommandCenter.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index 5c98fc1e0..ef35a5a24 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -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 From e996a30333eb392d2f2c364bda27c733f84c9166 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 21 Mar 2019 05:21:16 +0100 Subject: [PATCH 17/24] Updates --- .../Moose/Wrapper/Positionable.lua | 30 +++++++++++++++++ Moose Development/Moose/Wrapper/Static.lua | 32 ------------------- Moose Development/Moose/Wrapper/Unit.lua | 31 ------------------ 3 files changed, 30 insertions(+), 63 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 09d17a92c..400c2d3be 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -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 \ No newline at end of file diff --git a/Moose Development/Moose/Wrapper/Static.lua b/Moose Development/Moose/Wrapper/Static.lua index fb3d73296..68c224922 100644 --- a/Moose Development/Moose/Wrapper/Static.lua +++ b/Moose Development/Moose/Wrapper/Static.lua @@ -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 diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 363e42e08..9dc6d4d6c 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -807,37 +807,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. From ca65154ecddd6dc8e3d61435b37c9886e4ec6d3b Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 21 Mar 2019 05:49:48 +0100 Subject: [PATCH 18/24] Fixes --- Moose Development/Moose/Core/Zone.lua | 5 ++++- .../Moose/Tasking/Task_Capture_Zone.lua | 16 ++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 8c6d420e6..7e137253d 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -710,7 +710,10 @@ function ZONE_RADIUS:GetScannedSetUnit() if self.ScanData then for ObjectID, UnitObject in pairs( self.ScanData.Units ) do - SetUnit:AddUnit( UNIT:FindByName(UnitObject:getName() ) ) + local UnitObject = UnitObject -- DCS#Unit + if UnitObject:isExist() then + SetUnit:AddUnit( UNIT:FindByName( UnitObject:getName() ) ) + end end end diff --git a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua index dae324456..71b96a8d7 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua @@ -211,7 +211,7 @@ do -- TASK_CAPTURE_ZONE "Capture Zone " .. self.TaskZoneName ) - self:UpdateTaskInfo() + self:UpdateTaskInfo( true ) return self end @@ -219,18 +219,18 @@ do -- TASK_CAPTURE_ZONE --- Instantiates a new TASK_CAPTURE_ZONE. -- @param #TASK_CAPTURE_ZONE self - function TASK_CAPTURE_ZONE:UpdateTaskInfo( DetectedItem ) + function TASK_CAPTURE_ZONE:UpdateTaskInfo( Persist ) - self:F({"Update"}) + Persist = Persist or false local ZoneCoordinate = self.ZoneGoal:GetZone():GetCoordinate() - self.TaskInfo:AddTaskName( 0, "MSOD" ) - self.TaskInfo:AddCoordinate( ZoneCoordinate, 1, "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, "MOD" ) + self.TaskInfo:AddThreat( ThreatText, ThreatLevel, 20, "MSOD", Persist ) end From e8b74f0fc7a56f4cffca9a217433090f3db0e7b7 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 21 Mar 2019 06:03:13 +0100 Subject: [PATCH 19/24] handling static in scan --- Moose Development/Moose/Core/Zone.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 7e137253d..871404e96 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -712,7 +712,15 @@ function ZONE_RADIUS:GetScannedSetUnit() for ObjectID, UnitObject in pairs( self.ScanData.Units ) do local UnitObject = UnitObject -- DCS#Unit if UnitObject:isExist() then - SetUnit:AddUnit( UNIT:FindByName( UnitObject:getName() ) ) + 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 From 565a3062cb8cebd8799830a53062654e62cc80bf Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 21 Mar 2019 06:11:59 +0100 Subject: [PATCH 20/24] Fixing goal state machine rule --- Moose Development/Moose/Tasking/Task.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 797de7d61..6a26a3d6f 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -432,7 +432,7 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing ) self:AddTransition( "Assigned", "Fail", "Failed" ) self:AddTransition( { "Planned", "Assigned" }, "Abort", "Aborted" ) self:AddTransition( "Assigned", "Cancel", "Cancelled" ) - self:AddTransition( "Assigned", "Goal", "*" ) + self:AddTransition( "*", "Goal", "*" ) self.Fsm = {} From 310ba9bb8a51853ef149013d4082775965ef3bb9 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 21 Mar 2019 06:18:48 +0100 Subject: [PATCH 21/24] Reverse --- Moose Development/Moose/Tasking/Task.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 6a26a3d6f..797de7d61 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -432,7 +432,7 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing ) self:AddTransition( "Assigned", "Fail", "Failed" ) self:AddTransition( { "Planned", "Assigned" }, "Abort", "Aborted" ) self:AddTransition( "Assigned", "Cancel", "Cancelled" ) - self:AddTransition( "*", "Goal", "*" ) + self:AddTransition( "Assigned", "Goal", "*" ) self.Fsm = {} From b1e99dc31782ae9b054defbe7fefe46b2844b2f2 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 21 Mar 2019 06:31:13 +0100 Subject: [PATCH 22/24] Goal --- Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua | 2 +- Moose Development/Moose/Tasking/Task_Capture_Zone.lua | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua index 3fc4a86c8..74dff588e 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua @@ -284,7 +284,7 @@ do -- TASK_CAPTURE_DISPATCHER 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 diff --git a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua index 71b96a8d7..10645599a 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua @@ -212,6 +212,8 @@ do -- TASK_CAPTURE_ZONE ) self:UpdateTaskInfo( true ) + + self:SetGoalTotal( 1 ) return self end @@ -261,6 +263,7 @@ do -- TASK_CAPTURE_ZONE Scoring:_AddMissionGoalScore( self.Mission, PlayerName, "Zone " .. self.ZoneGoal:GetZoneName() .." captured", PlayerContribution * 200 / TotalContributions ) end end + self:AddProgress( PlayerName, "Zone " .. self.ZoneGoal:GetZoneName() .." captured", timer.getTime() , 1 ) end end From 9856a8625dfa5ff60719a8af691a1b7a8cbdca47 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Thu, 21 Mar 2019 06:57:04 +0100 Subject: [PATCH 23/24] Goal --- Moose Development/Moose/Core/Goal.lua | 1 + .../Moose/Tasking/CommandCenter.lua | 16 ++++++++++------ .../Moose/Tasking/Task_Capture_Zone.lua | 3 +-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Moose Development/Moose/Core/Goal.lua b/Moose Development/Moose/Core/Goal.lua index 4165e7f3f..ac1f616b9 100644 --- a/Moose Development/Moose/Core/Goal.lua +++ b/Moose Development/Moose/Core/Goal.lua @@ -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 diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index ef35a5a24..dcef1bb72 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -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 diff --git a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua index 10645599a..e39e8b2c9 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua @@ -253,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 } ) @@ -263,7 +262,7 @@ do -- TASK_CAPTURE_ZONE Scoring:_AddMissionGoalScore( self.Mission, PlayerName, "Zone " .. self.ZoneGoal:GetZoneName() .." captured", PlayerContribution * 200 / TotalContributions ) end end - self:AddProgress( PlayerName, "Zone " .. self.ZoneGoal:GetZoneName() .." captured", timer.getTime() , 1 ) + self:Success() end end From aa8498ce0b867b8401622b0448be2a225f2a6e14 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 22 Mar 2019 22:05:25 +0100 Subject: [PATCH 24/24] AIRBOSS v0.9.9.6 --- Moose Development/Moose/Ops/Airboss.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 8d3623ddf..8d18d4e53 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -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