Merge branch 'develop' into FF/Ops

This commit is contained in:
Frank
2021-03-03 00:03:52 +01:00
7 changed files with 434 additions and 154 deletions

View File

@@ -966,7 +966,7 @@ function AIRWING:CheckTANKER()
local altitude=patrol.altitude+1000*patrol.noccupied
local mission=AUFTRAG:NewTANKER(patrol.coord, altitude, patrol.speed, patrol.heading, patrol.leg, 0)
local mission=AUFTRAG:NewTANKER(patrol.coord, altitude, patrol.speed, patrol.heading, patrol.leg, 1)
mission.patroldata=patrol
@@ -984,7 +984,7 @@ function AIRWING:CheckTANKER()
local altitude=patrol.altitude+1000*patrol.noccupied
local mission=AUFTRAG:NewTANKER(patrol.coord, altitude, patrol.speed, patrol.heading, patrol.leg, 1)
local mission=AUFTRAG:NewTANKER(patrol.coord, altitude, patrol.speed, patrol.heading, patrol.leg, 0)
mission.patroldata=patrol

View File

@@ -39,6 +39,7 @@
-- * [F-14A/B Tomcat](https://forums.eagle.ru/forumdisplay.php?f=395) (Player & AI)
-- * [A-4E Skyhawk Community Mod](https://forums.eagle.ru/showthread.php?t=224989) (Player & AI)
-- * [AV-8B N/A Harrier](https://forums.eagle.ru/forumdisplay.php?f=555) (Player & AI) [**WIP**]
-- * [T-45C Goshawk (VNAO)(Player & AI)]
-- * F/A-18C Hornet (AI)
-- * F-14A Tomcat (AI)
-- * E-2D Hawkeye (AI)
@@ -1271,6 +1272,7 @@ AIRBOSS.AircraftCarrier={
F14B="F-14B",
F14A_AI="F-14A",
FA18C="F/A-18C",
T45C="T-45",
S3B="S-3B",
S3BTANKER="S-3B Tanker",
E2D="E-2C",
@@ -1705,7 +1707,7 @@ AIRBOSS.MenuF10Root=nil
--- Airboss class version.
-- @field #string version
AIRBOSS.version="1.1.5"
AIRBOSS.version="1.1.6"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -1939,7 +1941,7 @@ function AIRBOSS:New(carriername, alias)
-- Welcome players.
self:SetWelcomePlayers(true)
-- Coordinates
self.landingcoord=COORDINATE:New(0,0,0) --Core.Point#COORDINATE
self.sterncoord=COORDINATE:New(0, 0, 0) --Core.Point#COORDINATE
@@ -1951,11 +1953,11 @@ function AIRBOSS:New(carriername, alias)
elseif self.carriertype==AIRBOSS.CarrierType.ROOSEVELT then
self:_InitNimitz()
elseif self.carriertype==AIRBOSS.CarrierType.LINCOLN then
self:_InitNimitz()
elseif self.carriertype==AIRBOSS.CarrierType.WASHINGTON then
self:_InitNimitz()
elseif self.carriertype==AIRBOSS.CarrierType.TRUMAN then
self:_InitNimitz()
elseif self.carriertype==AIRBOSS.CarrierType.WASHINGTON then
self:_InitNimitz()
elseif self.carriertype==AIRBOSS.CarrierType.TRUMAN then
self:_InitNimitz()
elseif self.carriertype==AIRBOSS.CarrierType.VINSON then
-- TODO: Carl Vinson parameters.
self:_InitStennis()
@@ -1993,7 +1995,7 @@ function AIRBOSS:New(carriername, alias)
self:_GetZoneGroove():SmokeZone(SMOKECOLOR.Red, 5)
self:_GetZoneLineup():SmokeZone(SMOKECOLOR.Green, 5)
self:_GetZoneBullseye(case):SmokeZone(SMOKECOLOR.White, 45)
self:_GetZoneDirtyUp(case):SmokeZone(SMOKECOLOR.Orange, 45)
self:_GetZoneDirtyUp(case):SmokeZone(SMOKECOLOR.Orange, 45)
self:_GetZoneArcIn(case):SmokeZone(SMOKECOLOR.Blue, 45)
self:_GetZoneArcOut(case):SmokeZone(SMOKECOLOR.Blue, 45)
self:_GetZonePlatform(case):SmokeZone(SMOKECOLOR.Blue, 45)
@@ -2033,7 +2035,7 @@ function AIRBOSS:New(carriername, alias)
-- Bow
bow:FlareYellow()
-- Runway half width = 10 m.
local r1=stern:Translate(self.carrierparam.rwywidth*0.5, FB+90)
local r2=stern:Translate(self.carrierparam.rwywidth*0.5, FB-90)
@@ -2646,6 +2648,15 @@ function AIRBOSS:SetRecoveryTurnTime(interval)
return self
end
--- Set multiplayer environment wire correction.
-- @param #AIRBOSS self
-- @param #number Dcorr Correction distance in meters. Default 8.7 m.
-- @return #AIRBOSS self
function AIRBOSS:SetMPWireCorrection(Dcorr)
self.mpWireCorrection=Dcorr or 8.7
return self
end
--- Set time interval for updating queues and other stuff.
-- @param #AIRBOSS self
-- @param #number interval Time interval in seconds. Default 30 sec.
@@ -3284,7 +3295,7 @@ function AIRBOSS:GetNextRecoveryTime(InSeconds)
if InSeconds then
return self.recoverywindow.START, self.recoverywindow.STOP
else
return UTILS.SecondsToClock(self.recoverywindow.START), UTILS.SecondsToClock(self.recoverywindow.STOP)
return UTILS.SecondsToClock(self.recoverywindow.START), UTILS.SecondsToClock(self.recoverywindow.STOP)
end
else
if InSeconds then
@@ -3398,7 +3409,7 @@ function AIRBOSS:onafterStart(From, Event, To)
--self.StatusScheduler=SCHEDULER:New(self)
--self.StatusScheduler:Schedule(self, self._Status, {}, 1, 0.5)
self.StatusTimer=TIMER:New(self._Status, self):Start(2, 0.5)
-- Start status check in 1 second.
@@ -3484,9 +3495,9 @@ function AIRBOSS:onafterStatus(From, Event, To)
-- Disable turn into the wind for this window so that we do not do this all over again.
self.recoverywindow.WIND=false
end
end
end
@@ -3582,9 +3593,9 @@ function AIRBOSS:_CheckAIStatus()
-- Get lineup and distance to carrier.
local lineup=self:_Lineup(unit, true)
local unitcoord=unit:GetCoord()
local dist=unitcoord:Get2DDistance(self:GetCoord())
-- Distance in NM.
@@ -4145,7 +4156,7 @@ end
-- @param #string To To state.
function AIRBOSS:onafterStop(From, Event, To)
self:I(self.lid..string.format("Stopping airboss script."))
-- Unhandle events.
self:UnHandleEvent(EVENTS.Birth)
self:UnHandleEvent(EVENTS.Land)
@@ -4169,7 +4180,7 @@ function AIRBOSS:_InitStennis()
-- Carrier Parameters.
self.carrierparam.sterndist =-153
self.carrierparam.deckheight = 19
self.carrierparam.deckheight = 19.06
-- Total size of the carrier (approx as rectangle).
self.carrierparam.totlength=310 -- Wiki says 332.8 meters overall length.
@@ -4177,7 +4188,7 @@ function AIRBOSS:_InitStennis()
self.carrierparam.totwidthstarboard=30
-- Landing runway.
self.carrierparam.rwyangle = -9
self.carrierparam.rwyangle = -9.1359
self.carrierparam.rwylength = 225
self.carrierparam.rwywidth = 20
@@ -4320,7 +4331,7 @@ function AIRBOSS:_InitNimitz()
-- Carrier Parameters.
self.carrierparam.sterndist =-164
self.carrierparam.deckheight = 20
self.carrierparam.deckheight = 20.1494 --DCS World OpenBeta\CoreMods\tech\USS_Nimitz\Database\USS_CVN_7X.lua
-- Total size of the carrier (approx as rectangle).
self.carrierparam.totlength=332.8 -- Wiki says 332.8 meters overall length.
@@ -4328,7 +4339,7 @@ function AIRBOSS:_InitNimitz()
self.carrierparam.totwidthstarboard=35
-- Landing runway.
self.carrierparam.rwyangle = -9
self.carrierparam.rwyangle = -9.1359 --DCS World OpenBeta\CoreMods\tech\USS_Nimitz\scripts\USS_Nimitz_RunwaysAndRoutes.lua
self.carrierparam.rwylength = 250
self.carrierparam.rwywidth = 25
@@ -5471,6 +5482,7 @@ function AIRBOSS:_GetAircraftAoA(playerData)
-- Get AC type.
local hornet=playerData.actype==AIRBOSS.AircraftCarrier.HORNET
local goshawk=playerData.actype==AIRBOSS.AircraftCarrier.T45C
local skyhawk=playerData.actype==AIRBOSS.AircraftCarrier.A4EC
local harrier=playerData.actype==AIRBOSS.AircraftCarrier.AV8B
local tomcat=playerData.actype==AIRBOSS.AircraftCarrier.F14A or playerData.actype==AIRBOSS.AircraftCarrier.F14B
@@ -5497,6 +5509,15 @@ function AIRBOSS:_GetAircraftAoA(playerData)
aoa.OnSpeedMin = self:_AoAUnit2Deg(playerData, 14.5) --14.17 --14.5 units
aoa.Fast = self:_AoAUnit2Deg(playerData, 14.0) --13.33 --14.0 units
aoa.FAST = self:_AoAUnit2Deg(playerData, 13.0) --11.67 --13.0 units
elseif goshawk then
-- T-45C Goshawk parameters.
aoa.SLOW = 8.00 --19
aoa.Slow = 7.75 --18
aoa.OnSpeedMax = 7.25 --17.5
aoa.OnSpeed = 7.00 --17
aoa.OnSpeedMin = 6.75 --16.5
aoa.Fast = 6.25 --16
aoa.FAST = 6.00 --15
elseif skyhawk then
-- A-4E-C Skyhawk parameters from https://forums.eagle.ru/showpost.php?p=3703467&postcount=390
-- Note that these are arbitrary UNITS and not degrees. We need a conversion formula!
@@ -5681,6 +5702,9 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
elseif skyhawk then
alt=UTILS.FeetToMeters(600)
speed=UTILS.KnotsToMps(250)
elseif goshawk then
alt=UTILS.FeetToMeters(800)
speed=UTILS.KnotsToMps(300)
end
elseif step==AIRBOSS.PatternStep.BREAKENTRY then
@@ -5691,11 +5715,14 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
elseif skyhawk then
alt=UTILS.FeetToMeters(600)
speed=UTILS.KnotsToMps(250)
elseif goshawk then
alt=UTILS.FeetToMeters(800)
speed=UTILS.KnotsToMps(300)
end
elseif step==AIRBOSS.PatternStep.EARLYBREAK then
if hornet or tomcat or harrier then
if hornet or tomcat or harrier or goshawk then
alt=UTILS.FeetToMeters(800)
elseif skyhawk then
alt=UTILS.FeetToMeters(600)
@@ -5703,7 +5730,7 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
elseif step==AIRBOSS.PatternStep.LATEBREAK then
if hornet or tomcat or harrier then
if hornet or tomcat or harrier or goshawk then
alt=UTILS.FeetToMeters(800)
elseif skyhawk then
alt=UTILS.FeetToMeters(600)
@@ -5711,7 +5738,7 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
elseif step==AIRBOSS.PatternStep.ABEAM then
if hornet or tomcat or harrier then
if hornet or tomcat or harrier or goshawk then
alt=UTILS.FeetToMeters(600)
elseif skyhawk then
alt=UTILS.FeetToMeters(500)
@@ -5726,10 +5753,19 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
dist=UTILS.NMToMeters(1.2)
end
if goshawk then
-- 0.9 to 1.1 NM per natops ch.4 page 48
dist=UTILS.NMToMeters(0.9)
else
dist=UTILS.NMToMeters(1.1)
end
elseif step==AIRBOSS.PatternStep.NINETY then
if hornet or tomcat then
alt=UTILS.FeetToMeters(500)
elseif goshawk then
alt=UTILS.FeetToMeters(450)
elseif skyhawk then
alt=UTILS.FeetToMeters(500)
elseif harrier then
@@ -5740,7 +5776,7 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
elseif step==AIRBOSS.PatternStep.WAKE then
if hornet then
if hornet or goshawk then
alt=UTILS.FeetToMeters(370)
elseif tomcat then
alt=UTILS.FeetToMeters(430) -- Tomcat should be a bit higher as it intercepts the GS a bit higher.
@@ -5753,7 +5789,7 @@ function AIRBOSS:_GetAircraftParameters(playerData, step)
elseif step==AIRBOSS.PatternStep.FINAL then
if hornet then
if hornet or goshawk then
alt=UTILS.FeetToMeters(300)
elseif tomcat then
alt=UTILS.FeetToMeters(360)
@@ -6086,7 +6122,7 @@ function AIRBOSS:_ScanCarrierZone()
-- Get flight group.
local flight=_DATABASE:GetFlightGroup(groupname)
if flight and flight:IsInbound() and flight.destbase:GetName()==self.carrier:GetName() then
if flight.ishelo then
else
@@ -6123,7 +6159,7 @@ function AIRBOSS:_ScanCarrierZone()
-- Break the loop to not have all flights at once! Spams the message screen.
break
end -- Closed in or tanker/AWACS
end -- Closed in or tanker/AWACS
end
@@ -6229,7 +6265,7 @@ function AIRBOSS:_MarshalPlayer(playerData, stack)
-- Set stack flag.
flight.flag=stack
-- Trigger Marshal event.
self:Marshal(flight)
end
@@ -6488,7 +6524,7 @@ function AIRBOSS:_MarshalAI(flight, nstack, respawn)
-- Route group.
flight.group:Route(wp, 1)
-- Trigger Marshal event.
self:Marshal(flight)
@@ -7024,7 +7060,7 @@ function AIRBOSS:_GetFreeStack(ai, case, empty)
-- Recovery case.
case=case or self.case
if case==1 then
return self:_GetFreeStack_Old(ai, case, empty)
end
@@ -7040,7 +7076,7 @@ function AIRBOSS:_GetFreeStack(ai, case, empty)
for i=1,nmaxstacks do
stack[i]=self.NmaxStack -- Number of human flights per stack.
end
local nmax=1
-- Loop over all flights in marshal stack.
@@ -7052,7 +7088,7 @@ function AIRBOSS:_GetFreeStack(ai, case, empty)
-- Get stack of flight.
local n=flight.flag
if n>nmax then
nmax=n
end
@@ -7069,7 +7105,7 @@ function AIRBOSS:_GetFreeStack(ai, case, empty)
end
end
local nfree=nil
if stack[nmax]==0 then
-- Max occupied stack is completely full!
@@ -7085,7 +7121,7 @@ function AIRBOSS:_GetFreeStack(ai, case, empty)
-- Case II/III return next stack
nfree=nmax+1
end
elseif stack[nmax]==self.NmaxStack then
-- Max occupied stack is completely empty! This should happen only when there is no other flight in the marshal queue.
self:E(self.lid..string.format("ERROR: Max occupied stack is empty. Should not happen! Nmax=%d, stack[nmax]=%d", nmax, stack[nmax]))
@@ -7097,7 +7133,7 @@ function AIRBOSS:_GetFreeStack(ai, case, empty)
else
nfree=nmax
end
end
self:I(self.lid..string.format("Returning free stack %s", tostring(nfree)))
@@ -10370,7 +10406,7 @@ function AIRBOSS:_GetSternCoord()
self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(7, FB+90, true, true)
else
-- Nimitz SC: translate 8 meters starboard wrt Final bearing.
self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(8.5, FB+90, true, true)
self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(9.5, FB+90, true, true)
end
-- Set altitude.
@@ -10400,6 +10436,11 @@ function AIRBOSS:_GetWire(Lcoord, dc)
-- Corrected landing distance wrt to stern. Landing distance needs to be reduced due to delayed landing event for human players.
local d=Ldist-dc
-- Multiplayer wire correction.
if self.mpWireCorrection then
d=d-self.mpWireCorrection
end
-- Shift wires from stern to their correct position.
local w1=self.carrierparam.wire1
@@ -10491,6 +10532,9 @@ function AIRBOSS:_Trapped(playerData)
elseif playerData.actype==AIRBOSS.AircraftCarrier.A4EC then
-- A-4E gets slowed down much faster the the F/A-18C!
dcorr=56
elseif playerData.actype==AIRBOSS.AircraftCarrier.T45C then
-- T-45 also gets slowed down much faster the the F/A-18C.
dcorr=56
end
-- Get wire.
@@ -10617,7 +10661,7 @@ function AIRBOSS:_GetZoneInitial(case)
-- Polygon zone.
--local zone=ZONE_POLYGON_BASE:New("Zone CASE I/II Initial", vec2)
self.zoneInitial:UpdateFromVec2(vec2)
--return zone
@@ -10646,13 +10690,13 @@ function AIRBOSS:_GetZoneLineup()
-- Vec2 array.
local vec2={c1:GetVec2(), c2:GetVec2(), c3:GetVec2(), c4:GetVec2(), c5:GetVec2()}
self.zoneLineup:UpdateFromVec2(vec2)
-- Polygon zone.
--local zone=ZONE_POLYGON_BASE:New("Zone Lineup", vec2)
--return zone
return self.zoneLineup
end
@@ -10687,13 +10731,13 @@ function AIRBOSS:_GetZoneGroove(l, w, b)
-- Vec2 array.
local vec2={c1:GetVec2(), c2:GetVec2(), c3:GetVec2(), c4:GetVec2(), c5:GetVec2(), c6:GetVec2()}
self.zoneGroove:UpdateFromVec2(vec2)
-- Polygon zone.
--local zone=ZONE_POLYGON_BASE:New("Zone Groove", vec2)
--return zone
return self.zoneGroove
end
@@ -10719,7 +10763,7 @@ function AIRBOSS:_GetZoneBullseye(case)
-- Create zone.
local zone=ZONE_RADIUS:New("Zone Bullseye", vec2, radius)
return zone
--self.zoneBullseye=self.zoneBullseye or ZONE_RADIUS:New("Zone Bullseye", vec2, radius)
end
@@ -10948,9 +10992,9 @@ function AIRBOSS:_GetZoneCarrierBox()
-- Create polygon zone.
--local zone=ZONE_POLYGON_BASE:New("Carrier Box Zone", vec2)
--return zone
self.zoneCarrierbox:UpdateFromVec2(vec2)
return self.zoneCarrierbox
end
@@ -10985,9 +11029,9 @@ function AIRBOSS:_GetZoneRunwayBox()
-- Create polygon zone.
--local zone=ZONE_POLYGON_BASE:New("Landing Runway Zone", vec2)
--return zone
self.zoneRunwaybox:UpdateFromVec2(vec2)
return self.zoneRunwaybox
end
@@ -11118,7 +11162,7 @@ function AIRBOSS:_GetZoneHolding(case, stack)
-- Square zone length=7NM width=6 NM behind the carrier starting at angels+15 NM behind the carrier.
-- So stay 0-5 NM (+1 NM error margin) port of carrier.
self.zoneHolding=self.zoneHolding or ZONE_POLYGON_BASE:New("CASE II/III Holding Zone")
self.zoneHolding:UpdateFromVec2(p)
end
@@ -11164,12 +11208,12 @@ function AIRBOSS:_GetZoneCommence(case, stack)
-- Create holding zone.
self.zoneCommence=self.zoneCommence or ZONE_RADIUS:New("CASE I Commence Zone")
self.zoneCommence:UpdateFromVec2(Three:GetVec2(), R)
else
-- Case II/III
stack=stack or 1
-- Start point at 21 NM for stack=1.
@@ -11197,7 +11241,7 @@ function AIRBOSS:_GetZoneCommence(case, stack)
-- Zone polygon.
self.zoneCommence=self.zoneCommence or ZONE_POLYGON_BASE:New("CASE II/III Commence Zone")
self.zoneCommence:UpdateFromVec2(p)
end
@@ -11445,7 +11489,7 @@ end
-- @param #AIRBOSS self
-- @return Core.Point#COORDINATE Optimal landing coordinate.
function AIRBOSS:_GetOptLandingCoordinate()
-- Start with stern coordiante.
self.landingcoord:UpdateFromCoordinate(self:_GetSternCoord())
@@ -12001,15 +12045,15 @@ function AIRBOSS:_EvalGrooveTime(playerData)
local grade=""
if t<9 then
grade="--"
elseif t<12 then
grade="(OK)"
elseif t<22 then
grade="OK"
grade="_NESA_"
elseif t<15 then
grade="NESA"
elseif t<19 then
grade="OK Groove"
elseif t<=24 then
grade="(OK)"
grade="(LIG)"
else
grade="--"
grade="LIG"
end
-- The unicorn!
@@ -12050,7 +12094,7 @@ function AIRBOSS:_LSOgrade(playerData)
-- Groove time 16-18 sec for a unicorn.
local Tgroove=playerData.Tgroove
local TgrooveUnicorn=Tgroove and (Tgroove>=16.0 and Tgroove<=18.0) or false
local TgrooveUnicorn=Tgroove and (Tgroove>=15.0 and Tgroove<=18.99) or false
local grade
local points
@@ -14080,6 +14124,8 @@ function AIRBOSS:_GetACNickname(actype)
local nickname="unknown"
if actype==AIRBOSS.AircraftCarrier.A4EC then
nickname="Skyhawk"
elseif actype==AIRBOSS.AircraftCarrier.T45C then
nickname="Goshawk"
elseif actype==AIRBOSS.AircraftCarrier.AV8B then
nickname="Harrier"
elseif actype==AIRBOSS.AircraftCarrier.E2D then

View File

@@ -31,6 +31,7 @@
-- @field #boolean clustermarkers If true, create cluster markers on F10 map.
-- @field #number clustercounter Running number of clusters.
-- @field #number dTforget Time interval in seconds before a known contact which is not detected any more is forgotten.
-- @field #number clusterradius Radius im kilometers in which groups/units are considered to belong to a cluster
-- @extends Core.Fsm#FSM
--- Top Secret!
@@ -46,7 +47,7 @@
-- @field #INTEL
INTEL = {
ClassName = "INTEL",
verbose = 2,
verbose = 0,
lid = nil,
alias = nil,
filterCategory = {},
@@ -56,6 +57,7 @@ INTEL = {
ContactsUnknown = {},
Clusters = {},
clustercounter = 1,
clusterradius = 15,
}
--- Detected item info.
@@ -74,6 +76,8 @@ INTEL = {
-- @field #boolean isship
-- @field #boolean ishelo
-- @field #boolean isgrund
-- @field Ops.Auftrag#AUFTRAG mission The current Auftrag attached to this contact
-- @field #string recce The name of the recce unit that detected this contact
--- Cluster info.
-- @type INTEL.Cluster
@@ -85,11 +89,12 @@ INTEL = {
-- @field #number threatlevelAve Average of threat levels.
-- @field Core.Point#COORDINATE coordinate Coordinate of the cluster.
-- @field Wrapper.Marker#MARKER marker F10 marker.
-- @field Ops.Auftrag#AUFTRAG mission The current Auftrag attached to this cluster
--- INTEL class version.
-- @field #string version
INTEL.version="0.1.0"
INTEL.version="0.2.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
@@ -175,6 +180,8 @@ function INTEL:New(DetectionSet, Coalition, Alias)
self:AddTransition("*", "NewContact", "*") -- New contact has been detected.
self:AddTransition("*", "LostContact", "*") -- Contact could not be detected any more.
self:AddTransition("*", "NewCluster", "*") -- New cluster has been detected.
self:AddTransition("*", "LostCluster", "*") -- Cluster could not be detected any more.
-- Defaults
self:SetForgetTime()
@@ -210,10 +217,43 @@ function INTEL:New(DetectionSet, Coalition, Alias)
-- @function [parent=#INTEL] __Status
-- @param #INTEL self
-- @param #number delay Delay in seconds.
--- On After "NewContact" event.
-- @function [parent=#INTEL] OnAfterNewContact
-- @param #INTEL self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #INTEL.Contact Contact Detected contact.
--- On After "LostContact" event.
-- @function [parent=#INTEL] OnAfterLostContact
-- @param #INTEL self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #INTEL.Contact Contact Lost contact.
--- On After "NewCluster" event.
-- @function [parent=#INTEL] OnAfterNewCluster
-- @param #INTEL self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #INTEL.Contact Contact Detected contact.
-- @param #INTEL.Cluster Cluster Detected cluster
--- On After "LostCluster" event.
-- @function [parent=#INTEL] OnAfterLostCluster
-- @param #INTEL self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #INTEL.Cluster Cluster Lost cluster
-- @param Ops.Auftrag#AUFTRAG Mission The Auftrag connected with this cluster or nil
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -307,7 +347,7 @@ function INTEL:SetFilterCategory(Categories)
for _,category in pairs(self.filterCategory) do
text=text..string.format("%d,", category)
end
self:I(self.lid..text)
self:T(self.lid..text)
return self
end
@@ -334,7 +374,7 @@ function INTEL:FilterCategoryGroup(GroupCategories)
for _,category in pairs(self.filterCategoryGroup) do
text=text..string.format("%d,", category)
end
self:I(self.lid..text)
self:T(self.lid..text)
return self
end
@@ -351,6 +391,49 @@ function INTEL:SetClusterAnalysis(Switch, Markers)
return self
end
--- Set verbosity level for debugging.
-- @param #INTEL self
-- @param #number Verbosity The higher, the noisier, e.g. 0=off, 2=debug
-- @return #INTEL self
function INTEL:SetVerbosity(Verbosity)
self.verbose=Verbosity or 2
return self
end
--- Add a Mission (Auftrag) to a contact for tracking.
-- @param #INTEL self
-- @param #INTEL.Contact Contact The contact
-- @param Ops.Auftrag#AUFTRAG Mission The mission connected with this contact
-- @return #INTEL self
function INTEL:AddMissionToContact(Contact, Mission)
if Mission and Contact then
Contact.mission = Mission
end
return self
end
--- Add a Mission (Auftrag) to a cluster for tracking.
-- @param #INTEL self
-- @param #INTEL.Cluster Cluster The cluster
-- @param Ops.Auftrag#AUFTRAG Mission The mission connected with this cluster
-- @return #INTEL self
function INTEL:AddMissionToCluster(Cluster, Mission)
if Mission and Cluster then
Cluster.mission = Mission
end
return self
end
--- Change radius of the Clusters
-- @param #INTEL self
-- @param #number radius The radius of the clusters
-- @return #INTEL self
function INTEL:SetClusterRadius(radius)
local radius = radius or 15
self.clusterradius = radius
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -389,10 +472,11 @@ function INTEL:onafterStatus(From, Event, To)
-- Number of total contacts.
local Ncontacts=#self.Contacts
local Nclusters=#self.Clusters
-- Short info.
if self.verbose>=1 then
local text=string.format("Status %s [Agents=%s]: Contacts=%d, New=%d, Lost=%d", fsmstate, self.detectionset:CountAlive(), Ncontacts, #self.ContactsUnknown, #self.ContactsLost)
local text=string.format("Status %s [Agents=%s]: Contacts=%d, Clusters=%d, New=%d, Lost=%d", fsmstate, self.detectionset:CountAlive(), Ncontacts, Nclusters, #self.ContactsUnknown, #self.ContactsLost)
self:I(self.lid..text)
end
@@ -421,7 +505,8 @@ function INTEL:UpdateIntel()
-- Set of all detected units.
local DetectedUnits={}
-- Set of which units was detected by which recce
local RecceDetecting = {}
-- Loop over all units providing intel.
for _,_group in pairs(self.detectionset.Set or {}) do
local group=_group --Wrapper.Group#GROUP
@@ -432,7 +517,7 @@ function INTEL:UpdateIntel()
local recce=_recce --Wrapper.Unit#UNIT
-- Get detected units.
self:GetDetectedUnits(recce, DetectedUnits)
self:GetDetectedUnits(recce, DetectedUnits, RecceDetecting)
end
@@ -489,7 +574,7 @@ function INTEL:UpdateIntel()
end
end
if not keepit then
self:I(self.lid..string.format("Removing unit %s category=%d", unitname, unit:GetCategory()))
self:T(self.lid..string.format("Removing unit %s category=%d", unitname, unit:GetCategory()))
table.insert(remove, unitname)
end
end
@@ -502,17 +587,20 @@ function INTEL:UpdateIntel()
end
-- Create detected groups.
local DetectedGroups={}
local DetectedGroups={}
local RecceGroups={}
for unitname,_unit in pairs(DetectedUnits) do
local unit=_unit --Wrapper.Unit#UNIT
local group=unit:GetGroup()
if group then
DetectedGroups[group:GetName()]=group
local groupname = group:GetName()
DetectedGroups[groupname]=group
RecceGroups[groupname]=RecceDetecting[unitname]
end
end
-- Create detected contacts.
self:CreateDetectedItems(DetectedGroups)
self:CreateDetectedItems(DetectedGroups, RecceGroups)
-- Paint a picture of the battlefield.
if self.clusteranalysis then
@@ -528,8 +616,9 @@ end
--- Create detected items.
-- @param #INTEL self
-- @param #table DetectedGroups Table of detected Groups
function INTEL:CreateDetectedItems(DetectedGroups)
-- @param #table RecceDetecting Table of detecting recce names
function INTEL:CreateDetectedItems(DetectedGroups, RecceDetecting)
self:F({RecceDetecting=RecceDetecting})
-- Current time.
local Tnow=timer.getAbsTime()
@@ -569,7 +658,8 @@ function INTEL:CreateDetectedItems(DetectedGroups)
item.position=group:GetCoordinate()
item.velocity=group:GetVelocityVec3()
item.speed=group:GetVelocityMPS()
item.recce=RecceDetecting[groupname]
self:T(string.format("%s group detect by %s/%s", groupname, RecceDetecting[groupname] or "unknonw", item.recce or "unknown"))
-- Add contact to table.
self:AddContact(item)
@@ -602,17 +692,20 @@ end
-- 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.
-- @param #table DetectedUnits Table of detected units to be filled
-- @param #table RecceDetecting Table of recce per unit to be filled
-- @param #boolean DetectVisual (Optional) If *false*, do not include visually detected targets.
-- @param #boolean DetectOptical (Optional) If *false*, do not include optically detected targets.
-- @param #boolean DetectRadar (Optional) If *false*, do not include targets detected by radar.
-- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST.
-- @param #boolean DetectRWR (Optional) If *false*, do not include targets detected by RWR.
-- @param #boolean DetectDLINK (Optional) If *false*, do not include targets detected by data link.
function INTEL:GetDetectedUnits(Unit, DetectedUnits, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK)
function INTEL:GetDetectedUnits(Unit, DetectedUnits, RecceDetecting, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK)
-- Get detected DCS units.
local detectedtargets=Unit:GetDetectedTargets(DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK)
local reccename = Unit:GetName()
for DetectionObjectID, Detection in pairs(detectedtargets or {}) do
local DetectedObject=Detection.object -- DCS#Object
@@ -625,7 +718,8 @@ function INTEL:GetDetectedUnits(Unit, DetectedUnits, DetectVisual, DetectOptical
local unitname=unit:GetName()
DetectedUnits[unitname]=unit
RecceDetecting[unitname]=reccename
self:T(string.format("Unit %s detect by %s", unitname, reccename))
end
end
end
@@ -643,7 +737,7 @@ end
-- @param #string To To state.
-- @param #INTEL.Contact Contact Detected contact.
function INTEL:onafterNewContact(From, Event, To, Contact)
self:I(self.lid..string.format("NEW contact %s", Contact.groupname))
self:F(self.lid..string.format("NEW contact %s", Contact.groupname))
table.insert(self.ContactsUnknown, Contact)
end
@@ -654,10 +748,37 @@ end
-- @param #string To To state.
-- @param #INTEL.Contact Contact Detected contact.
function INTEL:onafterLostContact(From, Event, To, Contact)
self:I(self.lid..string.format("LOST contact %s", Contact.groupname))
self:F(self.lid..string.format("LOST contact %s", Contact.groupname))
table.insert(self.ContactsLost, Contact)
end
--- On after "NewCluster" event.
-- @param #INTEL self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #INTEL.Contact Contact Detected contact.
-- @param #INTEL.Cluster Cluster Detected cluster
function INTEL:onafterNewCluster(From, Event, To, Contact, Cluster)
self:F(self.lid..string.format("NEW cluster %d size %d with contact %s", Cluster.index, Cluster.size, Contact.groupname))
end
--- On after "LostCluster" event.
-- @param #INTEL self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #INTEL.Cluster Cluster Lost cluster
-- @param Ops.Auftrag#AUFTRAG Mission The Auftrag connected with this cluster or nil
function INTEL:onafterLostCluster(From, Event, To, Cluster, Mission)
local text = self.lid..string.format("LOST cluster %d", Cluster.index)
if Mission then
local mission=Mission --Ops.Auftrag#AUFTRAG
text=text..string.format(" mission name=%s type=%s target=%s", mission.name, mission.type, mission:GetTargetName() or "unkown")
end
self:T(text)
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Misc Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -752,11 +873,27 @@ function INTEL:PaintPicture()
self:RemoveContactFromCluster(contact, cluster)
end
end
-- clean up cluster table
local ClusterSet = {}
for _i,_cluster in pairs(self.Clusters) do
if (_cluster.size > 0) and (self:ClusterCountUnits(_cluster) > 0) then
table.insert(ClusterSet,_cluster)
else
local mission = _cluster.mission or nil
local marker = _cluster.marker
if marker then
marker:Remove()
end
self:LostCluster(_cluster, mission)
end
end
self.Clusters = ClusterSet
-- update positions
self:_UpdateClusterPositions()
for _,_contact in pairs(self.Contacts) do
local contact=_contact --#INTEL.Contact
self:T(string.format("Paint Picture: checking for %s",contact.groupname))
-- Check if this contact is in any cluster.
local isincluster=self:CheckContactInClusters(contact)
@@ -764,7 +901,7 @@ function INTEL:PaintPicture()
local currentcluster=self:GetClusterOfContact(contact)
if currentcluster then
--self:I(string.format("Paint Picture: %s has current cluster",contact.groupname))
---
-- Contact is currently part of a cluster.
---
@@ -772,8 +909,8 @@ function INTEL:PaintPicture()
-- Check if the contact is still connected to the cluster.
local isconnected=self:IsContactConnectedToCluster(contact, currentcluster)
if not isconnected then
if (not isconnected) and (currentcluster.size > 1) then
--self:I(string.format("Paint Picture: %s has LOST current cluster",contact.groupname))
local cluster=self:IsContactPartOfAnyClusters(contact)
if cluster then
@@ -782,6 +919,7 @@ function INTEL:PaintPicture()
local newcluster=self:CreateCluster(contact.position)
self:AddContactToCluster(contact, newcluster)
self:NewCluster(contact, newcluster)
end
end
@@ -792,7 +930,7 @@ function INTEL:PaintPicture()
---
-- Contact is not in any cluster yet.
---
--self:I(string.format("Paint Picture: %s has NO current cluster",contact.groupname))
local cluster=self:IsContactPartOfAnyClusters(contact)
if cluster then
@@ -801,6 +939,7 @@ function INTEL:PaintPicture()
local newcluster=self:CreateCluster(contact.position)
self:AddContactToCluster(contact, newcluster)
self:NewCluster(contact, newcluster)
end
end
@@ -810,16 +949,17 @@ function INTEL:PaintPicture()
-- Update F10 marker text if cluster has changed.
for _,_cluster in pairs(self.Clusters) do
local cluster=_cluster --#INTEL.Cluster
local coordinate=self:GetClusterCoordinate(cluster)
-- Update F10 marker.
self:UpdateClusterMarker(cluster)
if self.clustermarkers then
for _,_cluster in pairs(self.Clusters) do
local cluster=_cluster --#INTEL.Cluster
local coordinate=self:GetClusterCoordinate(cluster)
-- Update F10 marker.
self:UpdateClusterMarker(cluster)
end
end
end
--- Create a new cluster.
@@ -976,9 +1116,11 @@ function INTEL:IsContactConnectedToCluster(contact, cluster)
if Contact.groupname~=contact.groupname then
local dist=Contact.position:Get2DDistance(contact.position)
--local dist=Contact.position:Get2DDistance(contact.position)
local dist=Contact.position:DistanceFromPointVec2(contact.position)
if dist<10*1000 then
local radius = self.clusterradius or 15
if dist<radius*1000 then
return true
end
@@ -1032,7 +1174,6 @@ end
-- @param #INTEL.Cluster cluster The cluster.
-- @return Core.Point#COORDINATE The coordinate of this cluster.
function INTEL:GetClusterCoordinate(cluster)
-- Init.
local x=0 ; local y=0 ; local z=0 ; local n=0
@@ -1058,12 +1199,14 @@ end
--- Get the coordinate of a cluster.
-- @param #INTEL self
-- @param #INTEL.Cluster cluster The cluster.
-- @param Core.Point#COORDINATE coordinate (Optional) Coordinate of the new cluster. Default is to calculate the current coordinate.
-- @param Core.Point#COORDINATE coordinate (Optional) Coordinate of the new cluster. Default is to calculate the current coordinate.
-- @return #boolean
function INTEL:CheckClusterCoordinateChanged(cluster, coordinate)
coordinate=coordinate or self:GetClusterCoordinate(cluster)
local dist=cluster.coordinate:Get2DDistance(coordinate)
--local dist=cluster.coordinate:Get2DDistance(coordinate)
local dist=cluster.coordinate:DistanceFromPointVec2(coordinate)
if dist>1000 then
return true
@@ -1073,6 +1216,27 @@ function INTEL:CheckClusterCoordinateChanged(cluster, coordinate)
end
--- Update coordinates of the known clusters.
-- @param #INTEL self
function INTEL:_UpdateClusterPositions()
for _,_cluster in pairs (self.Clusters) do
local coord = self:GetClusterCoordinate(_cluster)
_cluster.coordinate = coord
self:T(self.lid..string.format("Cluster size: %s", _cluster.size))
end
end
--- Count number of units in cluster
-- @param #INTEL self
-- @param #INTEL.Cluster Cluster The cluster
-- @return #number unitcount
function INTEL:ClusterCountUnits(Cluster)
local unitcount = 0
for _,_group in pairs (Cluster.Contacts) do -- get Wrapper.GROUP#GROUP _group
unitcount = unitcount + _group.group:CountAliveUnits()
end
return unitcount
end
--- Update cluster F10 marker.
-- @param #INTEL self
@@ -1081,7 +1245,8 @@ end
function INTEL:UpdateClusterMarker(cluster)
-- Create a marker.
local text=string.format("Cluster #%d. Size %d, TLsum=%d", cluster.index, cluster.size, cluster.threatlevelSum)
local unitcount = self:ClusterCountUnits(cluster)
local text=string.format("Cluster #%d. Size %d, Units %d, TLsum=%d", cluster.index, cluster.size, unitcount, cluster.threatlevelSum)
if not cluster.marker then
cluster.marker=MARKER:New(cluster.coordinate, text):ToAll()