diff --git a/Moose Development/Moose/Ops/Intelligence.lua b/Moose Development/Moose/Ops/Intelligence.lua index 0f71a234e..6e900790f 100644 --- a/Moose Development/Moose/Ops/Intelligence.lua +++ b/Moose Development/Moose/Ops/Intelligence.lua @@ -26,6 +26,7 @@ -- @field #table filterCategoryGroup Filter for group categories. -- @field Core.Set#SET_ZONE acceptzoneset Set of accept zones. If defined, only contacts in these zones are considered. -- @field Core.Set#SET_ZONE rejectzoneset Set of reject zones. Contacts in these zones are not considered, even if they are in accept zones. +-- @field Core.Set#SET_ZONE conflictzoneset Set of conflict zones. Contacts in these zones are considered, even if they are not in accept zones or if they are in reject zones. -- @field #table Contacts Table of detected items. -- @field #table ContactsLost Table of lost detected items. -- @field #table ContactsUnknown Table of new detected items. @@ -159,13 +160,12 @@ INTEL.Ctype={ --- INTEL class version. -- @field #string version -INTEL.version="0.3.5" +INTEL.version="0.3.6" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- TODO: Make forget times user input. Currently these are hard coded. -- TODO: Add min cluster size. Only create new clusters if they have a certain group size. -- TODO: process detected set asynchroniously for better performance. -- DONE: Add statics. @@ -266,6 +266,7 @@ function INTEL:New(DetectionSet, Coalition, Alias) self:SetForgetTime() self:SetAcceptZones() self:SetRejectZones() + self:SetConflictZones() ------------------------ --- Pseudo Functions --- @@ -416,7 +417,7 @@ function INTEL:RemoveAcceptZone(AcceptZone) end --- Set reject zones. Contacts detected in this/these zone(s) are rejected and not reported by the detection. --- Note that reject zones overrule accept zones, i.e. if a unit is inside and accept zone and inside a reject zone, it is rejected. +-- Note that reject zones overrule accept zones, i.e. if a unit is inside an accept zone and inside a reject zone, it is rejected. -- @param #INTEL self -- @param Core.Set#SET_ZONE RejectZoneSet Set of reject zone(s). -- @return #INTEL self @@ -426,7 +427,7 @@ function INTEL:SetRejectZones(RejectZoneSet) end --- Add a reject zone. Contacts detected in this zone are rejected and not reported by the detection. --- Note that reject zones overrule accept zones, i.e. if a unit is inside and accept zone and inside a reject zone, it is rejected. +-- Note that reject zones overrule accept zones, i.e. if a unit is inside an accept zone and inside a reject zone, it is rejected. -- @param #INTEL self -- @param Core.Zone#ZONE RejectZone Add a zone to the reject zone set. -- @return #INTEL self @@ -444,6 +445,36 @@ function INTEL:RemoveRejectZone(RejectZone) return self end +--- Set conflict zones. Contacts detected in this/these zone(s) are reported by the detection. +-- Note that conflict zones overrule all other zones, i.e. if a unit is outside of an accept zone and inside a reject zone, it is still reported if inside a conflict zone. +-- @param #INTEL self +-- @param Core.Set#SET_ZONE ConflictZoneSet Set of conflict zone(s). +-- @return #INTEL self +function INTEL:SetConflictZones(ConflictZoneSet) + self.conflictzoneset=ConflictZoneSet or SET_ZONE:New() + return self +end + +--- Add a conflict zone. Contacts detected in this zone are conflicted and not reported by the detection. +-- Note that conflict zones overrule all other zones, i.e. if a unit is outside of an accept zone and inside a reject zone, it is still reported if inside a conflict zone. +-- @param #INTEL self +-- @param Core.Zone#ZONE ConflictZone Add a zone to the conflict zone set. +-- @return #INTEL self +function INTEL:AddConflictZone(ConflictZone) + self.conflictzoneset:AddZone(ConflictZone) + return self +end + +--- Remove a conflict zone from the conflict zone set. +-- Note that conflict zones overrule all other zones, i.e. if a unit is outside of an accept zone and inside a reject zone, it is still reported if inside a conflict zone. +-- @param #INTEL self +-- @param Core.Zone#ZONE ConflictZone Remove a zone from the conflict zone set. +-- @return #INTEL self +function INTEL:RemoveConflictZone(ConflictZone) + self.conflictzoneset:Remove(ConflictZone:GetName(), true) + return self +end + --- **OBSOLETE, will be removed in next version!** Set forget contacts time interval. -- Previously known contacts that are not detected any more, are "lost" after this time. -- This avoids fast oscillations between a contact being detected and undetected. @@ -481,6 +512,33 @@ function INTEL:SetFilterCategory(Categories) return self end +--- Method to make the radar detection less accurate, e.g. for WWII scenarios. +-- @param #INTEL self +-- @param #number minheight Minimum flight height to be detected, in meters AGL (above ground) +-- @param #number thresheight Threshold to escape the radar if flying below minheight, defaults to 90 (90% escape chance) +-- @param #number thresblur Threshold to be detected by the radar overall, defaults to 85 (85% chance to be found) +-- @param #number closing Closing-in in km - the limit of km from which on it becomes increasingly difficult to escape radar detection if flying towards the radar position. Should be about 1/3 of the radar detection radius in kilometers, defaults to 20. +-- @return #INTEL self +function INTEL:SetRadarBlur(minheight,thresheight,thresblur,closing) + self.RadarBlur = true + self.RadarBlurMinHeight = minheight or 250 -- meters + self.RadarBlurThresHeight = thresheight or 90 -- 10% chance to find a low flying group + self.RadarBlurThresBlur = thresblur or 85 -- 25% chance to escape the radar overall + self.RadarBlurClosing = closing or 20 -- 20km + self.RadarBlurClosingSquare = self.RadarBlurClosing * self.RadarBlurClosing + return self +end + +--- Set the accept range in kilometers from each of the recce. Only object closer than this range will be detected. +-- @param #INTEL self +-- @param #number Range Range in kilometers +-- @return #INTEL self +function INTEL:SetAcceptRange(Range) + self.RadarAcceptRange = true + self.RadarAcceptRangeKilometers = Range or 75 + return self +end + --- Filter group categories. Valid categories are: -- -- * Group.Category.AIRPLANE @@ -780,7 +838,19 @@ function INTEL:UpdateIntel() local remove={} for unitname,_unit in pairs(DetectedUnits) do local unit=_unit --Wrapper.Unit#UNIT - + + local inconflictzone=false + -- Check if unit is in any of the conflict zones. + if self.conflictzoneset:Count()>0 then + for _,_zone in pairs(self.conflictzoneset.Set) do + local zone=_zone --Core.Zone#ZONE + if unit:IsInZone(zone) then + inconflictzone=true + break + end + end + end + -- Check if unit is in any of the accept zones. if self.acceptzoneset:Count()>0 then local inzone=false @@ -793,7 +863,7 @@ function INTEL:UpdateIntel() end -- Unit is not in accept zone ==> remove! - if not inzone then + if (not inzone) and (not inconflictzone) then table.insert(remove, unitname) end end @@ -810,7 +880,7 @@ function INTEL:UpdateIntel() end -- Unit is inside a reject zone ==> remove! - if inzone then + if inzone and (not inconflictzone) then table.insert(remove, unitname) end end @@ -1037,7 +1107,7 @@ function INTEL:CreateDetectedItems(DetectedGroups, DetectedStatics, RecceDetecti end --- (Internal) Return the detected target groups of the controllable as a @{SET_GROUP}. --- The optional parametes specify the detection methods that can be applied. +-- The optional parameters specify the detection methods that can be applied. -- If no detection method is given, the detection will use all the available methods by default. -- @param #INTEL self -- @param Wrapper.Unit#UNIT Unit The unit detecting. @@ -1053,6 +1123,7 @@ function INTEL:GetDetectedUnits(Unit, DetectedUnits, RecceDetecting, DetectVisua -- Get detected DCS units. local reccename = Unit:GetName() + local detectedtargets=Unit:GetDetectedTargets(DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK) for DetectionObjectID, Detection in pairs(detectedtargets or {}) do @@ -1071,11 +1142,47 @@ function INTEL:GetDetectedUnits(Unit, DetectedUnits, RecceDetecting, DetectVisua if status then local unit=UNIT:FindByName(name) - + if unit and unit:IsAlive() then - DetectedUnits[name]=unit - RecceDetecting[name]=reccename - self:T(string.format("Unit %s detect by %s", name, reccename)) + local DetectionAccepted = true + + if self.RadarAcceptRange then + local reccecoord = Unit:GetCoordinate() + local coord = unit:GetCoordinate() + local dist = math.floor(coord:Get2DDistance(reccecoord)/1000) -- km + if dist > self.RadarAcceptRangeKilometers then DetectionAccepted = false end + end + + if self.RadarBlur then + local reccecoord = Unit:GetCoordinate() + local coord = unit:GetCoordinate() + local dist = math.floor(coord:Get2DDistance(reccecoord)/1000) -- km + local AGL = unit:GetAltitude(true) + local minheight = self.RadarBlurMinHeight or 250 -- meters + local thresheight = self.RadarBlurThresHeight or 90 -- 10% chance to find a low flying group + local thresblur = self.RadarBlurThresBlur or 85 -- 25% chance to escape the radar overall + --local dist = math.floor(Distance) + if dist <= self.RadarBlurClosing then + thresheight = (((dist*dist)/self.RadarBlurClosingSquare)*thresheight) + thresblur = (((dist*dist)/self.RadarBlurClosingSquare)*thresblur) + end + local fheight = math.floor(math.random(1,10000)/100) + local fblur = math.floor(math.random(1,10000)/100) + if fblur > thresblur then DetectionAccepted = false end + if AGL <= minheight and fheight < thresheight then DetectionAccepted = false end + if self.debug or self.verbose > 1 then + MESSAGE:New("Radar Blur",10):ToLogIf(self.debug):ToAllIf(self.verbose>1) + MESSAGE:New("Unit "..name.." is at "..math.floor(AGL).."m. Distance "..math.floor(dist).."km.",10):ToLogIf(self.debug):ToAllIf(self.verbose>1) + MESSAGE:New(string.format("fheight = %d/%d | fblur = %d/%d",fheight,thresheight,fblur,thresblur),10):ToLogIf(self.debug):ToAllIf(self.verbose>1) + MESSAGE:New("Detection Accepted = "..tostring(DetectionAccepted),10):ToLogIf(self.debug):ToAllIf(self.verbose>1) + end + end + + if DetectionAccepted then + DetectedUnits[name]=unit + RecceDetecting[name]=reccename + self:T(string.format("Unit %s detect by %s", name, reccename)) + end else if self.detectStatics then local static=STATIC:FindByName(name, false) @@ -1093,7 +1200,6 @@ function INTEL:GetDetectedUnits(Unit, DetectedUnits, RecceDetecting, DetectVisua end end end - end -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------