mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
OPS (#1723)
**INTEL** - Added nil check for cluster position update **OPSGROUP** - Improved fire at point task to take only max avail shots and relative shot amount - Fixed tasks not executed after teleport
This commit is contained in:
parent
68dce2f247
commit
d2d431ce2e
@ -4220,7 +4220,7 @@ function WAREHOUSE:_AssetItemInfo(asset)
|
|||||||
text=text..string.format("Cargo bay max = %5.2f kg\n", asset.cargobaymax)
|
text=text..string.format("Cargo bay max = %5.2f kg\n", asset.cargobaymax)
|
||||||
text=text..string.format("Load radius = %s m\n", tostring(asset.loadradius))
|
text=text..string.format("Load radius = %s m\n", tostring(asset.loadradius))
|
||||||
text=text..string.format("Skill = %s\n", tostring(asset.skill))
|
text=text..string.format("Skill = %s\n", tostring(asset.skill))
|
||||||
text=text..string.format("Livery = %s", tostring(asset.livery))
|
text=text..string.format("Livery = %s", tostring(asset.livery))
|
||||||
self:I(self.lid..text)
|
self:I(self.lid..text)
|
||||||
self:T({DCSdesc=asset.DCSdesc})
|
self:T({DCSdesc=asset.DCSdesc})
|
||||||
self:T3({Template=asset.template})
|
self:T3({Template=asset.template})
|
||||||
|
|||||||
@ -896,10 +896,13 @@ function ARMYGROUP:onafterSpawned(From, Event, To)
|
|||||||
-- Will be set in update route.
|
-- Will be set in update route.
|
||||||
--self.option.Formation=self.optionDefault.Formation
|
--self.option.Formation=self.optionDefault.Formation
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Number of waypoints.
|
||||||
|
local Nwp=#self.waypoints
|
||||||
|
|
||||||
-- Update route.
|
-- Update route.
|
||||||
if #self.waypoints>1 then
|
if Nwp>1 and self.isMobile then
|
||||||
self:T(self.lid.."Got waypoints on spawn ==> Cruise in -0.1 sec!")
|
self:T(self.lid..string.format("Got %d waypoints on spawn ==> Cruise in -1.0 sec!", Nwp))
|
||||||
self:__Cruise(-1, nil, self.option.Formation)
|
self:__Cruise(-1, nil, self.option.Formation)
|
||||||
else
|
else
|
||||||
self:T(self.lid.."No waypoints on spawn ==> Full Stop!")
|
self:T(self.lid.."No waypoints on spawn ==> Full Stop!")
|
||||||
@ -920,8 +923,13 @@ end
|
|||||||
-- @param #number Speed Speed in knots. Default cruise speed.
|
-- @param #number Speed Speed in knots. Default cruise speed.
|
||||||
-- @param #number Formation Formation of the group.
|
-- @param #number Formation Formation of the group.
|
||||||
function ARMYGROUP:onbeforeUpdateRoute(From, Event, To, n, N, Speed, Formation)
|
function ARMYGROUP:onbeforeUpdateRoute(From, Event, To, n, N, Speed, Formation)
|
||||||
|
|
||||||
|
-- Is transition allowed? We assume yes until proven otherwise.
|
||||||
|
local allowed=true
|
||||||
|
local trepeat=nil
|
||||||
|
|
||||||
if self:IsWaiting() then
|
if self:IsWaiting() then
|
||||||
self:T(self.lid.."Update route denied. Group is WAIRING!")
|
self:T(self.lid.."Update route denied. Group is WAITING!")
|
||||||
return false
|
return false
|
||||||
elseif self:IsInUtero() then
|
elseif self:IsInUtero() then
|
||||||
self:T(self.lid.."Update route denied. Group is INUTERO!")
|
self:T(self.lid.."Update route denied. Group is INUTERO!")
|
||||||
@ -936,7 +944,54 @@ function ARMYGROUP:onbeforeUpdateRoute(From, Event, To, n, N, Speed, Formation)
|
|||||||
self:T(self.lid.."Update route denied. Group is holding position!")
|
self:T(self.lid.."Update route denied. Group is holding position!")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return true
|
|
||||||
|
-- Check for a current task.
|
||||||
|
if self.taskcurrent>0 then
|
||||||
|
|
||||||
|
-- Get the current task. Must not be executing already.
|
||||||
|
local task=self:GetTaskByID(self.taskcurrent)
|
||||||
|
|
||||||
|
if task then
|
||||||
|
if task.dcstask.id=="PatrolZone" then
|
||||||
|
-- For patrol zone, we need to allow the update as we insert new waypoints.
|
||||||
|
self:T2(self.lid.."Allowing update route for Task: PatrolZone")
|
||||||
|
elseif task.dcstask.id=="ReconMission" then
|
||||||
|
-- For recon missions, we need to allow the update as we insert new waypoints.
|
||||||
|
self:T2(self.lid.."Allowing update route for Task: ReconMission")
|
||||||
|
elseif task.dcstask.id==AUFTRAG.SpecialTask.RELOCATECOHORT then
|
||||||
|
-- For relocate
|
||||||
|
self:T2(self.lid.."Allowing update route for Task: Relocate Cohort")
|
||||||
|
else
|
||||||
|
local taskname=task and task.description or "No description"
|
||||||
|
self:T(self.lid..string.format("WARNING: Update route denied because taskcurrent=%d>0! Task description = %s", self.taskcurrent, tostring(taskname)))
|
||||||
|
allowed=false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Now this can happen, if we directly use TaskExecute as the task is not in the task queue and cannot be removed. Therefore, also directly executed tasks should be added to the queue!
|
||||||
|
self:T(self.lid..string.format("WARNING: before update route taskcurrent=%d (>0!) but no task?!", self.taskcurrent))
|
||||||
|
-- Anyhow, a task is running so we do not allow to update the route!
|
||||||
|
allowed=false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Not good, because mission will never start. Better only check if there is a current task!
|
||||||
|
--if self.currentmission then
|
||||||
|
--end
|
||||||
|
|
||||||
|
-- Only AI flights.
|
||||||
|
if not self.isAI then
|
||||||
|
allowed=false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T2(self.lid..string.format("Onbefore Updateroute in state %s: allowed=%s (repeat in %s)", self:GetState(), tostring(allowed), tostring(trepeat)))
|
||||||
|
|
||||||
|
-- Try again?
|
||||||
|
if trepeat then
|
||||||
|
self:__UpdateRoute(trepeat, n)
|
||||||
|
end
|
||||||
|
|
||||||
|
return allowed
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "UpdateRoute" event.
|
--- On after "UpdateRoute" event.
|
||||||
@ -1239,6 +1294,33 @@ function ARMYGROUP:onafterRearmed(From, Event, To)
|
|||||||
self:_CheckGroupDone(1)
|
self:_CheckGroupDone(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- On before "RTZ" event.
|
||||||
|
-- @param #ARMYGROUP self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Zone#ZONE Zone The zone to return to.
|
||||||
|
-- @param #number Formation Formation of the group.
|
||||||
|
function ARMYGROUP:onbeforeRTZ(From, Event, To, Zone, Formation)
|
||||||
|
|
||||||
|
-- Zone.
|
||||||
|
local zone=Zone or self.homezone
|
||||||
|
|
||||||
|
if zone then
|
||||||
|
|
||||||
|
if (not self.isMobile) and (not self:IsInZone(zone)) then
|
||||||
|
self:Teleport(zone:GetCoordinate(), 0, true)
|
||||||
|
self:__RTZ(-1, Zone, Formation)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
--- On after "RTZ" event.
|
--- On after "RTZ" event.
|
||||||
-- @param #ARMYGROUP self
|
-- @param #ARMYGROUP self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
@ -1618,8 +1700,12 @@ function ARMYGROUP:onafterCruise(From, Event, To, Speed, Formation)
|
|||||||
-- Not waiting anymore.
|
-- Not waiting anymore.
|
||||||
self.Twaiting=nil
|
self.Twaiting=nil
|
||||||
self.dTwait=nil
|
self.dTwait=nil
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid.."Cruise ==> Update route in 0.01 sec")
|
||||||
|
|
||||||
self:__UpdateRoute(-0.1, nil, nil, Speed, Formation)
|
-- Update route.
|
||||||
|
self:__UpdateRoute(-0.01, nil, nil, Speed, Formation)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1712,6 +1798,13 @@ function ARMYGROUP:_InitGroup(Template)
|
|||||||
-- Max speed in km/h.
|
-- Max speed in km/h.
|
||||||
self.speedMax=self.group:GetSpeedMax()
|
self.speedMax=self.group:GetSpeedMax()
|
||||||
|
|
||||||
|
-- Is group mobile?
|
||||||
|
if self.speedMax>3.6 then
|
||||||
|
self.isMobile=true
|
||||||
|
else
|
||||||
|
self.isMobile=false
|
||||||
|
end
|
||||||
|
|
||||||
-- Cruise speed in km/h
|
-- Cruise speed in km/h
|
||||||
self.speedCruise=self.speedMax*0.7
|
self.speedCruise=self.speedMax*0.7
|
||||||
|
|
||||||
|
|||||||
@ -3097,6 +3097,13 @@ function FLIGHTGROUP:_InitGroup(Template)
|
|||||||
|
|
||||||
-- Max speed in km/h.
|
-- Max speed in km/h.
|
||||||
self.speedMax=group:GetSpeedMax()
|
self.speedMax=group:GetSpeedMax()
|
||||||
|
|
||||||
|
-- Is group mobile?
|
||||||
|
if self.speedMax>3.6 then
|
||||||
|
self.isMobile=true
|
||||||
|
else
|
||||||
|
self.isMobile=false
|
||||||
|
end
|
||||||
|
|
||||||
-- Cruise speed limit 350 kts for fixed and 80 knots for rotary wings.
|
-- Cruise speed limit 350 kts for fixed and 80 knots for rotary wings.
|
||||||
local speedCruiseLimit=self.isHelo and UTILS.KnotsToKmph(80) or UTILS.KnotsToKmph(350)
|
local speedCruiseLimit=self.isHelo and UTILS.KnotsToKmph(80) or UTILS.KnotsToKmph(350)
|
||||||
|
|||||||
@ -145,7 +145,7 @@ INTEL = {
|
|||||||
|
|
||||||
--- Contact or cluster type.
|
--- Contact or cluster type.
|
||||||
-- @type INTEL.Ctype
|
-- @type INTEL.Ctype
|
||||||
-- @field #string GROUND Ground.
|
-- @field #string GROUND Ground.
|
||||||
-- @field #string NAVAL Ship.
|
-- @field #string NAVAL Ship.
|
||||||
-- @field #string AIRCRAFT Airpane or helicopter.
|
-- @field #string AIRCRAFT Airpane or helicopter.
|
||||||
-- @field #string STRUCTURE Static structure.
|
-- @field #string STRUCTURE Static structure.
|
||||||
@ -349,7 +349,7 @@ function INTEL:New(DetectionSet, Coalition, Alias)
|
|||||||
-- @param #INTEL self
|
-- @param #INTEL self
|
||||||
-- @param #number delay Delay in seconds.
|
-- @param #number delay Delay in seconds.
|
||||||
-- @param #INTEL.Cluster Cluster Detected cluster.
|
-- @param #INTEL.Cluster Cluster Detected cluster.
|
||||||
|
|
||||||
--- On After "NewCluster" event.
|
--- On After "NewCluster" event.
|
||||||
-- @function [parent=#INTEL] OnAfterNewCluster
|
-- @function [parent=#INTEL] OnAfterNewCluster
|
||||||
-- @param #INTEL self
|
-- @param #INTEL self
|
||||||
@ -753,10 +753,10 @@ function INTEL:UpdateIntel()
|
|||||||
|
|
||||||
-- Set of all detected units.
|
-- Set of all detected units.
|
||||||
local DetectedUnits={}
|
local DetectedUnits={}
|
||||||
|
|
||||||
-- Set of which units was detected by which recce
|
-- Set of which units was detected by which recce
|
||||||
local RecceDetecting = {}
|
local RecceDetecting = {}
|
||||||
|
|
||||||
-- Loop over all units providing intel.
|
-- Loop over all units providing intel.
|
||||||
for _,_group in pairs(self.detectionset.Set or {}) do
|
for _,_group in pairs(self.detectionset.Set or {}) do
|
||||||
local group=_group --Wrapper.Group#GROUP
|
local group=_group --Wrapper.Group#GROUP
|
||||||
@ -863,8 +863,8 @@ function INTEL:UpdateIntel()
|
|||||||
if self.clusteranalysis then
|
if self.clusteranalysis then
|
||||||
self:PaintPicture()
|
self:PaintPicture()
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Update an #INTEL.Contact item.
|
--- Update an #INTEL.Contact item.
|
||||||
@ -874,11 +874,11 @@ end
|
|||||||
function INTEL:_UpdateContact(Contact)
|
function INTEL:_UpdateContact(Contact)
|
||||||
|
|
||||||
if Contact.isStatic then
|
if Contact.isStatic then
|
||||||
|
|
||||||
-- Statics don't need to be updated.
|
-- Statics don't need to be updated.
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
if Contact.group and Contact.group:IsAlive() then
|
if Contact.group and Contact.group:IsAlive() then
|
||||||
|
|
||||||
Contact.Tdetected=timer.getAbsTime()
|
Contact.Tdetected=timer.getAbsTime()
|
||||||
@ -899,7 +899,7 @@ function INTEL:_UpdateContact(Contact)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@ -915,11 +915,11 @@ function INTEL:_CreateContact(Positionable, RecceName)
|
|||||||
|
|
||||||
-- Create new contact.
|
-- Create new contact.
|
||||||
local item={} --#INTEL.Contact
|
local item={} --#INTEL.Contact
|
||||||
|
|
||||||
if Positionable:IsInstanceOf("GROUP") then
|
if Positionable:IsInstanceOf("GROUP") then
|
||||||
|
|
||||||
local group=Positionable --Wrapper.Group#GROUP
|
local group=Positionable --Wrapper.Group#GROUP
|
||||||
|
|
||||||
item.groupname=group:GetName()
|
item.groupname=group:GetName()
|
||||||
item.group=group
|
item.group=group
|
||||||
item.Tdetected=timer.getAbsTime()
|
item.Tdetected=timer.getAbsTime()
|
||||||
@ -952,13 +952,13 @@ function INTEL:_CreateContact(Positionable, RecceName)
|
|||||||
elseif item.category==Group.Category.SHIP then
|
elseif item.category==Group.Category.SHIP then
|
||||||
item.ctype=INTEL.Ctype.NAVAL
|
item.ctype=INTEL.Ctype.NAVAL
|
||||||
end
|
end
|
||||||
|
|
||||||
return item
|
return item
|
||||||
|
|
||||||
elseif Positionable:IsInstanceOf("STATIC") then
|
elseif Positionable:IsInstanceOf("STATIC") then
|
||||||
|
|
||||||
local static=Positionable --Wrapper.Static#STATIC
|
local static=Positionable --Wrapper.Static#STATIC
|
||||||
|
|
||||||
item.groupname=static:GetName()
|
item.groupname=static:GetName()
|
||||||
item.group=static
|
item.group=static
|
||||||
item.Tdetected=timer.getAbsTime()
|
item.Tdetected=timer.getAbsTime()
|
||||||
@ -973,14 +973,14 @@ function INTEL:_CreateContact(Positionable, RecceName)
|
|||||||
item.recce=RecceName
|
item.recce=RecceName
|
||||||
item.isground = true
|
item.isground = true
|
||||||
item.isship = false
|
item.isship = false
|
||||||
item.isStatic=true
|
item.isStatic=true
|
||||||
item.ctype=INTEL.Ctype.STRUCTURE
|
item.ctype=INTEL.Ctype.STRUCTURE
|
||||||
|
|
||||||
return item
|
return item
|
||||||
else
|
else
|
||||||
self:E(self.lid..string.format("ERROR: object needs to be a GROUP or STATIC!"))
|
self:E(self.lid..string.format("ERROR: object needs to be a GROUP or STATIC!"))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -1005,7 +1005,7 @@ function INTEL:CreateDetectedItems(DetectedGroups, DetectedStatics, RecceDetecti
|
|||||||
self:KnowObject(group, RecceDetecting[groupname])
|
self:KnowObject(group, RecceDetecting[groupname])
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Loop over statics.
|
-- Loop over statics.
|
||||||
for staticname,_static in pairs(DetectedStatics) do
|
for staticname,_static in pairs(DetectedStatics) do
|
||||||
local static=_static --Wrapper.Static#STATIC
|
local static=_static --Wrapper.Static#STATIC
|
||||||
@ -1105,7 +1105,7 @@ function INTEL:onafterNewContact(From, Event, To, Contact)
|
|||||||
|
|
||||||
-- Debug text.
|
-- Debug text.
|
||||||
self:F(self.lid..string.format("NEW contact %s", Contact.groupname))
|
self:F(self.lid..string.format("NEW contact %s", Contact.groupname))
|
||||||
|
|
||||||
-- Add to table of unknown contacts.
|
-- Add to table of unknown contacts.
|
||||||
table.insert(self.ContactsUnknown, Contact)
|
table.insert(self.ContactsUnknown, Contact)
|
||||||
return self
|
return self
|
||||||
@ -1121,7 +1121,7 @@ function INTEL:onafterLostContact(From, Event, To, Contact)
|
|||||||
|
|
||||||
-- Debug text.
|
-- Debug text.
|
||||||
self:F(self.lid..string.format("LOST contact %s", Contact.groupname))
|
self:F(self.lid..string.format("LOST contact %s", Contact.groupname))
|
||||||
|
|
||||||
-- Add to table of lost contacts.
|
-- Add to table of lost contacts.
|
||||||
table.insert(self.ContactsLost, Contact)
|
table.insert(self.ContactsLost, Contact)
|
||||||
return self
|
return self
|
||||||
@ -1134,10 +1134,10 @@ end
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #INTEL.Cluster Cluster Detected cluster.
|
-- @param #INTEL.Cluster Cluster Detected cluster.
|
||||||
function INTEL:onafterNewCluster(From, Event, To, Cluster)
|
function INTEL:onafterNewCluster(From, Event, To, Cluster)
|
||||||
|
|
||||||
-- Debug text.
|
-- Debug text.
|
||||||
self:F(self.lid..string.format("NEW cluster #%d [%s] of size %d", Cluster.index, Cluster.ctype, Cluster.size))
|
self:F(self.lid..string.format("NEW cluster #%d [%s] of size %d", Cluster.index, Cluster.ctype, Cluster.size))
|
||||||
|
|
||||||
-- Add cluster to table.
|
-- Add cluster to table.
|
||||||
self:_AddCluster(Cluster)
|
self:_AddCluster(Cluster)
|
||||||
return self
|
return self
|
||||||
@ -1154,12 +1154,12 @@ function INTEL:onafterLostCluster(From, Event, To, Cluster, Mission)
|
|||||||
|
|
||||||
-- Debug text.
|
-- Debug text.
|
||||||
local text = self.lid..string.format("LOST cluster #%d [%s]", Cluster.index, Cluster.ctype)
|
local text = self.lid..string.format("LOST cluster #%d [%s]", Cluster.index, Cluster.ctype)
|
||||||
|
|
||||||
if Mission then
|
if Mission then
|
||||||
local mission=Mission --Ops.Auftrag#AUFTRAG
|
local mission=Mission --Ops.Auftrag#AUFTRAG
|
||||||
text=text..string.format(" mission name=%s type=%s target=%s", mission.name, mission.type, mission:GetTargetName() or "unknown")
|
text=text..string.format(" mission name=%s type=%s target=%s", mission.name, mission.type, mission:GetTargetName() or "unknown")
|
||||||
end
|
end
|
||||||
|
|
||||||
self:T(text)
|
self:T(text)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@ -1178,47 +1178,47 @@ function INTEL:KnowObject(Positionable, RecceName, Tdetected)
|
|||||||
|
|
||||||
local Tnow=timer.getAbsTime()
|
local Tnow=timer.getAbsTime()
|
||||||
Tdetected=Tdetected or Tnow
|
Tdetected=Tdetected or Tnow
|
||||||
|
|
||||||
if Positionable and Positionable:IsAlive() then
|
if Positionable and Positionable:IsAlive() then
|
||||||
|
|
||||||
if Tdetected>Tnow then
|
if Tdetected>Tnow then
|
||||||
-- Delay call.
|
-- Delay call.
|
||||||
self:ScheduleOnce(Tdetected-Tnow, self.KnowObject, self, Positionable, RecceName)
|
self:ScheduleOnce(Tdetected-Tnow, self.KnowObject, self, Positionable, RecceName)
|
||||||
else
|
else
|
||||||
|
|
||||||
-- Name of the object.
|
-- Name of the object.
|
||||||
local name=Positionable:GetName()
|
local name=Positionable:GetName()
|
||||||
|
|
||||||
-- Try to get the contact by name.
|
-- Try to get the contact by name.
|
||||||
local contact=self:GetContactByName(name)
|
local contact=self:GetContactByName(name)
|
||||||
|
|
||||||
if contact then
|
if contact then
|
||||||
|
|
||||||
-- Update contact info.
|
-- Update contact info.
|
||||||
self:_UpdateContact(contact)
|
self:_UpdateContact(contact)
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- Create new contact.
|
-- Create new contact.
|
||||||
contact=self:_CreateContact(Positionable, RecceName)
|
contact=self:_CreateContact(Positionable, RecceName)
|
||||||
|
|
||||||
if contact then
|
if contact then
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(string.format("%s contact detected by %s", contact.groupname, RecceName or "unknown"))
|
self:T(string.format("%s contact detected by %s", contact.groupname, RecceName or "unknown"))
|
||||||
|
|
||||||
-- Add contact to table.
|
-- Add contact to table.
|
||||||
self:AddContact(contact)
|
self:AddContact(contact)
|
||||||
|
|
||||||
-- Trigger new contact event.
|
-- Trigger new contact event.
|
||||||
self:NewContact(contact)
|
self:NewContact(contact)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1268,7 +1268,7 @@ function INTEL:AddContact(Contact)
|
|||||||
self:T(self.lid..string.format("Adding new Contact %s to table", tostring(Contact.groupname)))
|
self:T(self.lid..string.format("Adding new Contact %s to table", tostring(Contact.groupname)))
|
||||||
table.insert(self.Contacts, Contact)
|
table.insert(self.Contacts, Contact)
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1298,7 +1298,7 @@ function INTEL:_CheckContactLost(Contact)
|
|||||||
if Contact.group==nil or not Contact.group:IsAlive() then
|
if Contact.group==nil or not Contact.group:IsAlive() then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- We never forget statics as they don't move.
|
-- We never forget statics as they don't move.
|
||||||
if Contact.isStatic then
|
if Contact.isStatic then
|
||||||
return false
|
return false
|
||||||
@ -1308,7 +1308,7 @@ function INTEL:_CheckContactLost(Contact)
|
|||||||
local dT=timer.getAbsTime()-Contact.Tdetected
|
local dT=timer.getAbsTime()-Contact.Tdetected
|
||||||
|
|
||||||
local dTforget=nil
|
local dTforget=nil
|
||||||
|
|
||||||
if Contact.category==Group.Category.GROUND then
|
if Contact.category==Group.Category.GROUND then
|
||||||
dTforget=60*60*2 -- 2 hours
|
dTforget=60*60*2 -- 2 hours
|
||||||
elseif Contact.category==Group.Category.AIRPLANE then
|
elseif Contact.category==Group.Category.AIRPLANE then
|
||||||
@ -1341,80 +1341,80 @@ function INTEL:PaintPicture()
|
|||||||
-- First remove all lost contacts from clusters.
|
-- First remove all lost contacts from clusters.
|
||||||
for _,_contact in pairs(self.ContactsLost) do
|
for _,_contact in pairs(self.ContactsLost) do
|
||||||
local contact=_contact --#INTEL.Contact
|
local contact=_contact --#INTEL.Contact
|
||||||
|
|
||||||
-- Get cluster this contact belongs to (if any).
|
-- Get cluster this contact belongs to (if any).
|
||||||
local cluster=self:GetClusterOfContact(contact)
|
local cluster=self:GetClusterOfContact(contact)
|
||||||
|
|
||||||
if cluster then
|
if cluster then
|
||||||
self:RemoveContactFromCluster(contact, cluster)
|
self:RemoveContactFromCluster(contact, cluster)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Clean up cluster table.
|
-- Clean up cluster table.
|
||||||
local ClusterSet = {}
|
local ClusterSet = {}
|
||||||
|
|
||||||
-- Now check if whole clusters were lost.
|
-- Now check if whole clusters were lost.
|
||||||
for _i,_cluster in pairs(self.Clusters) do
|
for _i,_cluster in pairs(self.Clusters) do
|
||||||
local cluster=_cluster --#INTEL.Cluster
|
local cluster=_cluster --#INTEL.Cluster
|
||||||
|
|
||||||
if cluster.size>0 and self:ClusterCountUnits(cluster)>0 then
|
if cluster.size>0 and self:ClusterCountUnits(cluster)>0 then
|
||||||
-- This one has size>0 and units>0
|
-- This one has size>0 and units>0
|
||||||
table.insert(ClusterSet,_cluster)
|
table.insert(ClusterSet,_cluster)
|
||||||
else
|
else
|
||||||
|
|
||||||
-- This cluster is gone.
|
-- This cluster is gone.
|
||||||
|
|
||||||
-- Remove marker.
|
-- Remove marker.
|
||||||
if cluster.marker then
|
if cluster.marker then
|
||||||
cluster.marker:Remove()
|
cluster.marker:Remove()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Marker of the arrow.
|
-- Marker of the arrow.
|
||||||
if cluster.markerID then
|
if cluster.markerID then
|
||||||
COORDINATE:RemoveMark(cluster.markerID)
|
COORDINATE:RemoveMark(cluster.markerID)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Lost cluster.
|
-- Lost cluster.
|
||||||
self:LostCluster(cluster, cluster.mission)
|
self:LostCluster(cluster, cluster.mission)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set Clusters.
|
-- Set Clusters.
|
||||||
self.Clusters = ClusterSet
|
self.Clusters = ClusterSet
|
||||||
|
|
||||||
-- Update positions.
|
-- Update positions.
|
||||||
self:_UpdateClusterPositions()
|
self:_UpdateClusterPositions()
|
||||||
|
|
||||||
|
|
||||||
for _,_contact in pairs(self.Contacts) do
|
for _,_contact in pairs(self.Contacts) do
|
||||||
local contact=_contact --#INTEL.Contact
|
local contact=_contact --#INTEL.Contact
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(string.format("Paint Picture: checking for %s",contact.groupname))
|
self:T(string.format("Paint Picture: checking for %s",contact.groupname))
|
||||||
|
|
||||||
-- Get the current cluster (if any) this contact belongs to.
|
-- Get the current cluster (if any) this contact belongs to.
|
||||||
local currentcluster=self:GetClusterOfContact(contact)
|
local currentcluster=self:GetClusterOfContact(contact)
|
||||||
|
|
||||||
if currentcluster then
|
if currentcluster then
|
||||||
---
|
---
|
||||||
-- Contact is currently part of a cluster.
|
-- Contact is currently part of a cluster.
|
||||||
---
|
---
|
||||||
|
|
||||||
-- Check if the contact is still connected to the cluster.
|
-- Check if the contact is still connected to the cluster.
|
||||||
local isconnected=self:IsContactConnectedToCluster(contact, currentcluster)
|
local isconnected=self:IsContactConnectedToCluster(contact, currentcluster)
|
||||||
|
|
||||||
if isconnected then
|
if isconnected then
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
--- Not connected to current cluster any more.
|
--- Not connected to current cluster any more.
|
||||||
|
|
||||||
-- Remove from current cluster.
|
-- Remove from current cluster.
|
||||||
self:RemoveContactFromCluster(contact, currentcluster)
|
self:RemoveContactFromCluster(contact, currentcluster)
|
||||||
|
|
||||||
-- Find new cluster.
|
-- Find new cluster.
|
||||||
local cluster=self:_GetClosestClusterOfContact(contact)
|
local cluster=self:_GetClosestClusterOfContact(contact)
|
||||||
|
|
||||||
if cluster then
|
if cluster then
|
||||||
-- Add contact to cluster.
|
-- Add contact to cluster.
|
||||||
self:AddContactToCluster(contact, cluster)
|
self:AddContactToCluster(contact, cluster)
|
||||||
@ -1422,11 +1422,11 @@ function INTEL:PaintPicture()
|
|||||||
|
|
||||||
-- Create a new cluster.
|
-- Create a new cluster.
|
||||||
local newcluster=self:_CreateClusterFromContact(contact)
|
local newcluster=self:_CreateClusterFromContact(contact)
|
||||||
|
|
||||||
-- Trigger new cluster event.
|
-- Trigger new cluster event.
|
||||||
self:NewCluster(newcluster)
|
self:NewCluster(newcluster)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -1434,26 +1434,26 @@ function INTEL:PaintPicture()
|
|||||||
---
|
---
|
||||||
-- Contact is not in any cluster yet.
|
-- Contact is not in any cluster yet.
|
||||||
---
|
---
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("Paint Picture: contact %s has NO current cluster", contact.groupname))
|
self:T(self.lid..string.format("Paint Picture: contact %s has NO current cluster", contact.groupname))
|
||||||
|
|
||||||
-- Get the closest existing cluster of this contact.
|
-- Get the closest existing cluster of this contact.
|
||||||
local cluster=self:_GetClosestClusterOfContact(contact)
|
local cluster=self:_GetClosestClusterOfContact(contact)
|
||||||
|
|
||||||
if cluster then
|
if cluster then
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("Paint Picture: contact %s has closest cluster #%d",contact.groupname, cluster.index))
|
self:T(self.lid..string.format("Paint Picture: contact %s has closest cluster #%d",contact.groupname, cluster.index))
|
||||||
|
|
||||||
-- Add contact to this cluster.
|
-- Add contact to this cluster.
|
||||||
self:AddContactToCluster(contact, cluster)
|
self:AddContactToCluster(contact, cluster)
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- Create a brand new cluster.
|
-- Create a brand new cluster.
|
||||||
local newcluster=self:_CreateClusterFromContact(contact)
|
local newcluster=self:_CreateClusterFromContact(contact)
|
||||||
|
|
||||||
-- Trigger event for a new cluster.
|
-- Trigger event for a new cluster.
|
||||||
self:NewCluster(newcluster)
|
self:NewCluster(newcluster)
|
||||||
end
|
end
|
||||||
@ -1470,19 +1470,19 @@ function INTEL:PaintPicture()
|
|||||||
for _,_cluster in pairs(self.Clusters) do
|
for _,_cluster in pairs(self.Clusters) do
|
||||||
local cluster=_cluster --#INTEL.Cluster
|
local cluster=_cluster --#INTEL.Cluster
|
||||||
--local coordinate=self:GetClusterCoordinate(cluster)
|
--local coordinate=self:GetClusterCoordinate(cluster)
|
||||||
|
|
||||||
-- Update F10 marker.
|
-- Update F10 marker.
|
||||||
MESSAGE:New("Updating cluster marker and future position", 10):ToAll()
|
MESSAGE:New("Updating cluster marker and future position", 10):ToAll()
|
||||||
|
|
||||||
-- Update cluster markers.
|
-- Update cluster markers.
|
||||||
self:UpdateClusterMarker(cluster)
|
self:UpdateClusterMarker(cluster)
|
||||||
|
|
||||||
-- Extrapolate future position of the cluster.
|
-- Extrapolate future position of the cluster.
|
||||||
self:CalcClusterFuturePosition(cluster, 300)
|
self:CalcClusterFuturePosition(cluster, 300)
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1515,15 +1515,15 @@ end
|
|||||||
function INTEL:_CreateClusterFromContact(Contact)
|
function INTEL:_CreateClusterFromContact(Contact)
|
||||||
|
|
||||||
local cluster=self:_CreateCluster()
|
local cluster=self:_CreateCluster()
|
||||||
|
|
||||||
self:T(self.lid..string.format("Created NEW cluster #%d with first contact %s", cluster.index, Contact.groupname))
|
self:T(self.lid..string.format("Created NEW cluster #%d with first contact %s", cluster.index, Contact.groupname))
|
||||||
|
|
||||||
cluster.coordinate:UpdateFromCoordinate(Contact.position)
|
cluster.coordinate:UpdateFromCoordinate(Contact.position)
|
||||||
|
|
||||||
cluster.ctype=Contact.ctype
|
cluster.ctype=Contact.ctype
|
||||||
|
|
||||||
self:AddContactToCluster(Contact, cluster)
|
self:AddContactToCluster(Contact, cluster)
|
||||||
|
|
||||||
return cluster
|
return cluster
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1536,7 +1536,7 @@ function INTEL:_AddCluster(Cluster)
|
|||||||
|
|
||||||
-- Add cluster.
|
-- Add cluster.
|
||||||
table.insert(self.Clusters, Cluster)
|
table.insert(self.Clusters, Cluster)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1547,7 +1547,7 @@ end
|
|||||||
function INTEL:AddContactToCluster(contact, cluster)
|
function INTEL:AddContactToCluster(contact, cluster)
|
||||||
|
|
||||||
if contact and cluster then
|
if contact and cluster then
|
||||||
|
|
||||||
-- Add neighbour to cluster contacts.
|
-- Add neighbour to cluster contacts.
|
||||||
table.insert(cluster.Contacts, contact)
|
table.insert(cluster.Contacts, contact)
|
||||||
|
|
||||||
@ -1556,14 +1556,14 @@ function INTEL:AddContactToCluster(contact, cluster)
|
|||||||
|
|
||||||
-- Increase size.
|
-- Increase size.
|
||||||
cluster.size=cluster.size+1
|
cluster.size=cluster.size+1
|
||||||
|
|
||||||
-- alt
|
-- alt
|
||||||
self:GetClusterAltitude(cluster,true)
|
self:GetClusterAltitude(cluster,true)
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("Adding contact %s to cluster #%d [%s] ==> New size=%d", contact.groupname, cluster.index, cluster.ctype, cluster.size))
|
self:T(self.lid..string.format("Adding contact %s to cluster #%d [%s] ==> New size=%d", contact.groupname, cluster.index, cluster.ctype, cluster.size))
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1582,7 +1582,7 @@ function INTEL:RemoveContactFromCluster(contact, cluster)
|
|||||||
|
|
||||||
-- Remove threat level sum.
|
-- Remove threat level sum.
|
||||||
cluster.threatlevelSum=cluster.threatlevelSum-contact.threatlevel
|
cluster.threatlevelSum=cluster.threatlevelSum-contact.threatlevel
|
||||||
|
|
||||||
-- Decrease cluster size.
|
-- Decrease cluster size.
|
||||||
cluster.size=cluster.size-1
|
cluster.size=cluster.size-1
|
||||||
|
|
||||||
@ -1662,13 +1662,13 @@ function INTEL:CalcClusterDirection(cluster)
|
|||||||
local n=0
|
local n=0
|
||||||
for _,_contact in pairs(cluster.Contacts) do
|
for _,_contact in pairs(cluster.Contacts) do
|
||||||
local contact=_contact --#INTEL.Contact
|
local contact=_contact --#INTEL.Contact
|
||||||
|
|
||||||
if (not contact.isStatic) and contact.group:IsAlive() then
|
if (not contact.isStatic) and contact.group:IsAlive() then
|
||||||
direction = direction + contact.group:GetHeading()
|
direction = direction + contact.group:GetHeading()
|
||||||
n=n+1
|
n=n+1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--TODO: This calculation is WRONG!
|
--TODO: This calculation is WRONG!
|
||||||
-- Simple example for two groups:
|
-- Simple example for two groups:
|
||||||
-- First group is going West, i.e. heading 090
|
-- First group is going West, i.e. heading 090
|
||||||
@ -1677,7 +1677,7 @@ function INTEL:CalcClusterDirection(cluster)
|
|||||||
-- It should not go anywhere as the two movements cancel each other.
|
-- It should not go anywhere as the two movements cancel each other.
|
||||||
-- Correct, edge case for N=2^x, but when 2 pairs of groups drive in exact opposite directions, the cluster will split at some point?
|
-- Correct, edge case for N=2^x, but when 2 pairs of groups drive in exact opposite directions, the cluster will split at some point?
|
||||||
-- maybe add the speed as weight to get a factor
|
-- maybe add the speed as weight to get a factor
|
||||||
|
|
||||||
if n==0 then
|
if n==0 then
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
@ -1694,17 +1694,17 @@ function INTEL:CalcClusterSpeed(cluster)
|
|||||||
local velocity = 0 ; local n=0
|
local velocity = 0 ; local n=0
|
||||||
for _,_contact in pairs(cluster.Contacts) do
|
for _,_contact in pairs(cluster.Contacts) do
|
||||||
local contact=_contact --#INTEL.Contact
|
local contact=_contact --#INTEL.Contact
|
||||||
|
|
||||||
if (not contact.isStatic) and contact.group:IsAlive() then
|
if (not contact.isStatic) and contact.group:IsAlive() then
|
||||||
velocity = velocity + contact.group:GetVelocityMPS()
|
velocity = velocity + contact.group:GetVelocityMPS()
|
||||||
n=n+1
|
n=n+1
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if n==0 then
|
if n==0 then
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
return math.floor(velocity / n)
|
return math.floor(velocity / n)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1716,10 +1716,10 @@ end
|
|||||||
function INTEL:CalcClusterVelocityVec3(cluster)
|
function INTEL:CalcClusterVelocityVec3(cluster)
|
||||||
|
|
||||||
local v={x=0, y=0, z=0} --DCS#Vec3
|
local v={x=0, y=0, z=0} --DCS#Vec3
|
||||||
|
|
||||||
for _,_contact in pairs(cluster.Contacts) do
|
for _,_contact in pairs(cluster.Contacts) do
|
||||||
local contact=_contact --#INTEL.Contact
|
local contact=_contact --#INTEL.Contact
|
||||||
|
|
||||||
if (not contact.isStatic) and contact.group:IsAlive() then
|
if (not contact.isStatic) and contact.group:IsAlive() then
|
||||||
local vec=contact.group:GetVelocityVec3()
|
local vec=contact.group:GetVelocityVec3()
|
||||||
v.x=v.x+vec.x
|
v.x=v.x+vec.x
|
||||||
@ -1727,7 +1727,7 @@ function INTEL:CalcClusterVelocityVec3(cluster)
|
|||||||
v.z=v.y+vec.z
|
v.z=v.y+vec.z
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return v
|
return v
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1737,22 +1737,22 @@ end
|
|||||||
-- @param #number seconds Time interval in seconds. Default is `self.prediction`.
|
-- @param #number seconds Time interval in seconds. Default is `self.prediction`.
|
||||||
-- @return Core.Point#COORDINATE Calculated future position of the cluster.
|
-- @return Core.Point#COORDINATE Calculated future position of the cluster.
|
||||||
function INTEL:CalcClusterFuturePosition(cluster, seconds)
|
function INTEL:CalcClusterFuturePosition(cluster, seconds)
|
||||||
|
|
||||||
-- Get current position of the cluster.
|
-- Get current position of the cluster.
|
||||||
local p=self:GetClusterCoordinate(cluster)
|
local p=self:GetClusterCoordinate(cluster)
|
||||||
|
|
||||||
-- Velocity vector in m/s.
|
-- Velocity vector in m/s.
|
||||||
local v=self:CalcClusterVelocityVec3(cluster)
|
local v=self:CalcClusterVelocityVec3(cluster)
|
||||||
|
|
||||||
-- Time in seconds.
|
-- Time in seconds.
|
||||||
local t=seconds or self.prediction
|
local t=seconds or self.prediction
|
||||||
|
|
||||||
-- Extrapolated vec3.
|
-- Extrapolated vec3.
|
||||||
local Vec3={x=p.x+v.x*t, y=p.y+v.y*t, z=p.z+v.z*t}
|
local Vec3={x=p.x+v.x*t, y=p.y+v.y*t, z=p.z+v.z*t}
|
||||||
|
|
||||||
-- Future position.
|
-- Future position.
|
||||||
local futureposition=COORDINATE:NewFromVec3(Vec3)
|
local futureposition=COORDINATE:NewFromVec3(Vec3)
|
||||||
|
|
||||||
-- Create an arrow pointing in the direction of the movement.
|
-- Create an arrow pointing in the direction of the movement.
|
||||||
if self.clustermarkers and self.verbose>1 then
|
if self.clustermarkers and self.verbose>1 then
|
||||||
if cluster.markerID then
|
if cluster.markerID then
|
||||||
@ -1760,7 +1760,7 @@ function INTEL:CalcClusterFuturePosition(cluster, seconds)
|
|||||||
end
|
end
|
||||||
cluster.markerID = p:ArrowToAll(futureposition, self.coalition, {1,0,0}, 1, {1,1,0}, 0.5, 2, true, "Position Calc")
|
cluster.markerID = p:ArrowToAll(futureposition, self.coalition, {1,0,0}, 1, {1,1,0}, 0.5, 2, true, "Position Calc")
|
||||||
end
|
end
|
||||||
|
|
||||||
return futureposition
|
return futureposition
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1798,7 +1798,7 @@ function INTEL:IsContactConnectedToCluster(contact, cluster)
|
|||||||
if contact.ctype~=cluster.ctype then
|
if contact.ctype~=cluster.ctype then
|
||||||
return false, math.huge
|
return false, math.huge
|
||||||
end
|
end
|
||||||
|
|
||||||
for _,_contact in pairs(cluster.Contacts) do
|
for _,_contact in pairs(cluster.Contacts) do
|
||||||
local Contact=_contact --#INTEL.Contact
|
local Contact=_contact --#INTEL.Contact
|
||||||
|
|
||||||
@ -1807,7 +1807,7 @@ function INTEL:IsContactConnectedToCluster(contact, cluster)
|
|||||||
|
|
||||||
--local dist=Contact.position:Get2DDistance(contact.position)
|
--local dist=Contact.position:Get2DDistance(contact.position)
|
||||||
local dist=Contact.position:DistanceFromPointVec2(contact.position)
|
local dist=Contact.position:DistanceFromPointVec2(contact.position)
|
||||||
|
|
||||||
-- AIR - check for spatial proximity
|
-- AIR - check for spatial proximity
|
||||||
local airprox = false
|
local airprox = false
|
||||||
if contact.ctype == INTEL.Ctype.AIRCRAFT then
|
if contact.ctype == INTEL.Ctype.AIRCRAFT then
|
||||||
@ -1817,7 +1817,7 @@ function INTEL:IsContactConnectedToCluster(contact, cluster)
|
|||||||
airprox = true
|
airprox = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if dist<self.clusterradius and airprox then
|
if dist<self.clusterradius and airprox then
|
||||||
return true, dist
|
return true, dist
|
||||||
end
|
end
|
||||||
@ -1854,19 +1854,19 @@ end
|
|||||||
function INTEL:_GetDistContactToCluster(Contact, Cluster)
|
function INTEL:_GetDistContactToCluster(Contact, Cluster)
|
||||||
|
|
||||||
local distmin=math.huge
|
local distmin=math.huge
|
||||||
|
|
||||||
for _,_contact in pairs(Cluster.Contacts) do
|
for _,_contact in pairs(Cluster.Contacts) do
|
||||||
local contact=_contact --#INTEL.Contact
|
local contact=_contact --#INTEL.Contact
|
||||||
|
|
||||||
if contact.group and contact.group:IsAlive() and Contact.groupname~=contact.groupname then
|
if contact.group and contact.group:IsAlive() and Contact.groupname~=contact.groupname then
|
||||||
|
|
||||||
local dist=Contact.position:Get2DDistance(contact.position)
|
local dist=Contact.position:Get2DDistance(contact.position)
|
||||||
|
|
||||||
if dist<distmin then
|
if dist<distmin then
|
||||||
distmin=dist
|
distmin=dist
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return distmin
|
return distmin
|
||||||
@ -1880,20 +1880,20 @@ end
|
|||||||
function INTEL:_GetClosestClusterOfContact(Contact)
|
function INTEL:_GetClosestClusterOfContact(Contact)
|
||||||
|
|
||||||
local Cluster=nil --#INTEL.Cluster
|
local Cluster=nil --#INTEL.Cluster
|
||||||
|
|
||||||
local distmin=self.clusterradius
|
local distmin=self.clusterradius
|
||||||
|
|
||||||
if not Contact.altitude then
|
if not Contact.altitude then
|
||||||
Contact.altitude = Contact.group:GetAltitude()
|
Contact.altitude = Contact.group:GetAltitude()
|
||||||
end
|
end
|
||||||
|
|
||||||
for _,_cluster in pairs(self.Clusters) do
|
for _,_cluster in pairs(self.Clusters) do
|
||||||
local cluster=_cluster --#INTEL.Cluster
|
local cluster=_cluster --#INTEL.Cluster
|
||||||
|
|
||||||
if cluster.ctype==Contact.ctype then
|
if cluster.ctype==Contact.ctype then
|
||||||
|
|
||||||
local dist=self:_GetDistContactToCluster(Contact, cluster)
|
local dist=self:_GetDistContactToCluster(Contact, cluster)
|
||||||
|
|
||||||
-- AIR - check for spatial proximity
|
-- AIR - check for spatial proximity
|
||||||
local airprox = false
|
local airprox = false
|
||||||
if Contact.ctype == INTEL.Ctype.AIRCRAFT then
|
if Contact.ctype == INTEL.Ctype.AIRCRAFT then
|
||||||
@ -1906,12 +1906,12 @@ function INTEL:_GetClosestClusterOfContact(Contact)
|
|||||||
airprox = true
|
airprox = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if dist<distmin and airprox then
|
if dist<distmin and airprox then
|
||||||
Cluster=cluster
|
Cluster=cluster
|
||||||
distmin=dist
|
distmin=dist
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1949,7 +1949,7 @@ function INTEL:GetClusterAltitude(Cluster, Update)
|
|||||||
-- Init.
|
-- Init.
|
||||||
local newalt = 0
|
local newalt = 0
|
||||||
local n=0
|
local n=0
|
||||||
|
|
||||||
-- Loop over all contacts.
|
-- Loop over all contacts.
|
||||||
for _,_contact in pairs(Cluster.Contacts) do
|
for _,_contact in pairs(Cluster.Contacts) do
|
||||||
local contact=_contact --#INTEL.Contact
|
local contact=_contact --#INTEL.Contact
|
||||||
@ -1964,12 +1964,12 @@ function INTEL:GetClusterAltitude(Cluster, Update)
|
|||||||
if n>0 then
|
if n>0 then
|
||||||
avgalt = newalt/n
|
avgalt = newalt/n
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Update cluster coordinate.
|
-- Update cluster coordinate.
|
||||||
Cluster.altitude = avgalt
|
Cluster.altitude = avgalt
|
||||||
|
|
||||||
self:T(string.format("Updating Cluster Altitude: %d",Cluster.altitude))
|
self:T(string.format("Updating Cluster Altitude: %d",Cluster.altitude))
|
||||||
|
|
||||||
return Cluster.altitude
|
return Cluster.altitude
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1982,35 +1982,44 @@ function INTEL:GetClusterCoordinate(Cluster, Update)
|
|||||||
|
|
||||||
-- Init.
|
-- Init.
|
||||||
local x=0 ; local y=0 ; local z=0 ; local n=0
|
local x=0 ; local y=0 ; local z=0 ; local n=0
|
||||||
|
|
||||||
-- Loop over all contacts.
|
-- Loop over all contacts.
|
||||||
for _,_contact in pairs(Cluster.Contacts) do
|
for _,_contact in pairs(Cluster.Contacts) do
|
||||||
local contact=_contact --#INTEL.Contact
|
local contact=_contact --#INTEL.Contact
|
||||||
|
|
||||||
local vec3=nil --DCS#Vec3
|
local vec3=nil --DCS#Vec3
|
||||||
|
|
||||||
if Update and contact.group:IsAlive() then
|
if Update and contact.group and contact.group:IsAlive() then
|
||||||
vec3 = contact.group:GetVec3()
|
vec3 = contact.group:GetVec3()
|
||||||
else
|
|
||||||
vec3 = contact.position
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Sum up posits.
|
if not vec3 then
|
||||||
|
vec3=contact.position
|
||||||
|
end
|
||||||
|
|
||||||
if vec3 then
|
if vec3 then
|
||||||
|
|
||||||
|
-- Sum up posits.
|
||||||
x=x+vec3.x
|
x=x+vec3.x
|
||||||
y=y+vec3.y
|
y=y+vec3.y
|
||||||
z=z+vec3.z
|
z=z+vec3.z
|
||||||
|
|
||||||
-- Increase counter.
|
-- Increase counter.
|
||||||
n=n+1
|
n=n+1
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Average.
|
if n>0 then
|
||||||
local Vec3={x=x/n, y=y/n, z=z/n} --DCS#Vec3
|
|
||||||
|
-- Average.
|
||||||
-- Update cluster coordinate.
|
local Vec3={x=x/n, y=y/n, z=z/n} --DCS#Vec3
|
||||||
Cluster.coordinate:UpdateFromVec3(Vec3)
|
|
||||||
|
-- Update cluster coordinate.
|
||||||
|
Cluster.coordinate:UpdateFromVec3(Vec3)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
return Cluster.coordinate
|
return Cluster.coordinate
|
||||||
end
|
end
|
||||||
@ -2024,7 +2033,7 @@ end
|
|||||||
function INTEL:_CheckClusterCoordinateChanged(Cluster, Coordinate, Threshold)
|
function INTEL:_CheckClusterCoordinateChanged(Cluster, Coordinate, Threshold)
|
||||||
|
|
||||||
Threshold=Threshold or 100
|
Threshold=Threshold or 100
|
||||||
|
|
||||||
Coordinate=Coordinate or Cluster.coordinate
|
Coordinate=Coordinate or Cluster.coordinate
|
||||||
|
|
||||||
-- Positions of cluster.
|
-- Positions of cluster.
|
||||||
@ -2046,11 +2055,11 @@ end
|
|||||||
function INTEL:_UpdateClusterPositions()
|
function INTEL:_UpdateClusterPositions()
|
||||||
for _,_cluster in pairs (self.Clusters) do
|
for _,_cluster in pairs (self.Clusters) do
|
||||||
local cluster=_cluster --#INTEL.Cluster
|
local cluster=_cluster --#INTEL.Cluster
|
||||||
|
|
||||||
-- Update cluster coordinate.
|
-- Update cluster coordinate.
|
||||||
local coord = self:GetClusterCoordinate(cluster, true)
|
local coord = self:GetClusterCoordinate(cluster, true)
|
||||||
local alt = self:GetClusterAltitude(cluster,true)
|
local alt = self:GetClusterAltitude(cluster,true)
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("Updating Cluster position size: %s", cluster.size))
|
self:T(self.lid..string.format("Updating Cluster position size: %s", cluster.size))
|
||||||
end
|
end
|
||||||
@ -2070,7 +2079,7 @@ function INTEL:ContactCountUnits(Contact)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
if Contact.group then
|
if Contact.group then
|
||||||
local n=Contact.group:CountAliveUnits()
|
local n=Contact.group:CountAliveUnits()
|
||||||
return n
|
return n
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
@ -2084,7 +2093,7 @@ end
|
|||||||
-- @return #number unitcount
|
-- @return #number unitcount
|
||||||
function INTEL:ClusterCountUnits(Cluster)
|
function INTEL:ClusterCountUnits(Cluster)
|
||||||
local unitcount = 0
|
local unitcount = 0
|
||||||
for _,_contact in pairs (Cluster.Contacts) do
|
for _,_contact in pairs (Cluster.Contacts) do
|
||||||
local contact=_contact --#INTEL.Contact
|
local contact=_contact --#INTEL.Contact
|
||||||
unitcount = unitcount + self:ContactCountUnits(contact)
|
unitcount = unitcount + self:ContactCountUnits(contact)
|
||||||
end
|
end
|
||||||
@ -2102,10 +2111,10 @@ function INTEL:UpdateClusterMarker(cluster)
|
|||||||
local text=string.format("Cluster #%d: %s\nSize %d\nUnits %d\nTLsum=%d", cluster.index, cluster.ctype, cluster.size, unitcount, cluster.threatlevelSum)
|
local text=string.format("Cluster #%d: %s\nSize %d\nUnits %d\nTLsum=%d", cluster.index, cluster.ctype, cluster.size, unitcount, cluster.threatlevelSum)
|
||||||
|
|
||||||
if not cluster.marker then
|
if not cluster.marker then
|
||||||
|
|
||||||
-- First time ==> need to create a new marker object.
|
-- First time ==> need to create a new marker object.
|
||||||
cluster.marker=MARKER:New(cluster.coordinate, text):ToCoalition(self.coalition)
|
cluster.marker=MARKER:New(cluster.coordinate, text):ToCoalition(self.coalition)
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- Need to refresh?
|
-- Need to refresh?
|
||||||
@ -2118,7 +2127,7 @@ function INTEL:UpdateClusterMarker(cluster)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Check if coordinate changed.
|
-- Check if coordinate changed.
|
||||||
local coordchange=self:_CheckClusterCoordinateChanged(cluster, cluster.marker.coordinate)
|
local coordchange=self:_CheckClusterCoordinateChanged(cluster, cluster.marker.coordinate)
|
||||||
if coordchange then
|
if coordchange then
|
||||||
cluster.marker.coordinate:UpdateFromCoordinate(cluster.coordinate)
|
cluster.marker.coordinate:UpdateFromCoordinate(cluster.coordinate)
|
||||||
refresh=true
|
refresh=true
|
||||||
@ -2197,22 +2206,22 @@ INTEL_DLINK.version = "0.0.1"
|
|||||||
-- Contact duplicates are removed. Clusters might contain duplicates (Might fix that later, WIP).
|
-- Contact duplicates are removed. Clusters might contain duplicates (Might fix that later, WIP).
|
||||||
--
|
--
|
||||||
-- Basic setup:
|
-- Basic setup:
|
||||||
--
|
--
|
||||||
-- local datalink = INTEL_DLINK:New({myintel1,myintel2}), "FSB", 20, 300)
|
-- local datalink = INTEL_DLINK:New({myintel1,myintel2}), "FSB", 20, 300)
|
||||||
-- datalink:__Start(2)
|
-- datalink:__Start(2)
|
||||||
--
|
--
|
||||||
-- Add an Intel while running:
|
-- Add an Intel while running:
|
||||||
--
|
--
|
||||||
-- datalink:AddIntel(myintel3)
|
-- datalink:AddIntel(myintel3)
|
||||||
--
|
--
|
||||||
-- Gather the data:
|
-- Gather the data:
|
||||||
--
|
--
|
||||||
-- datalink:GetContactTable() -- #table of #INTEL.Contact contacts.
|
-- datalink:GetContactTable() -- #table of #INTEL.Contact contacts.
|
||||||
-- datalink:GetClusterTable() -- #table of #INTEL.Cluster clusters.
|
-- datalink:GetClusterTable() -- #table of #INTEL.Cluster clusters.
|
||||||
-- datalink:GetDetectedItemCoordinates() -- #table of contact coordinates, to be compatible with @{Functional.Detection#DETECTION}.
|
-- datalink:GetDetectedItemCoordinates() -- #table of contact coordinates, to be compatible with @{Functional.Detection#DETECTION}.
|
||||||
--
|
--
|
||||||
-- Gather data with the event function:
|
-- Gather data with the event function:
|
||||||
--
|
--
|
||||||
-- function datalink:OnAfterCollected(From, Event, To, Contacts, Clusters)
|
-- function datalink:OnAfterCollected(From, Event, To, Contacts, Clusters)
|
||||||
-- ... <your code here> ...
|
-- ... <your code here> ...
|
||||||
-- end
|
-- end
|
||||||
|
|||||||
@ -83,7 +83,6 @@ function LEGION:New(WarehouseName, LegionName)
|
|||||||
self.lid=string.format("LEGION %s | ", self.alias)
|
self.lid=string.format("LEGION %s | ", self.alias)
|
||||||
|
|
||||||
-- Defaults:
|
-- Defaults:
|
||||||
-- TODO: What?
|
|
||||||
self:SetMarker(false)
|
self:SetMarker(false)
|
||||||
|
|
||||||
-- Dead and crash events are handled via opsgroups.
|
-- Dead and crash events are handled via opsgroups.
|
||||||
|
|||||||
@ -1021,23 +1021,75 @@ end
|
|||||||
-- @param #number Speed Speed in knots to the next waypoint.
|
-- @param #number Speed Speed in knots to the next waypoint.
|
||||||
-- @param #number Depth Depth in meters to the next waypoint.
|
-- @param #number Depth Depth in meters to the next waypoint.
|
||||||
function NAVYGROUP:onbeforeUpdateRoute(From, Event, To, n, Speed, Depth)
|
function NAVYGROUP:onbeforeUpdateRoute(From, Event, To, n, Speed, Depth)
|
||||||
|
-- Is transition allowed? We assume yes until proven otherwise.
|
||||||
|
local allowed=true
|
||||||
|
local trepeat=nil
|
||||||
|
|
||||||
if self:IsWaiting() then
|
if self:IsWaiting() then
|
||||||
self:E(self.lid.."Update route denied. Group is WAITING!")
|
self:T(self.lid.."Update route denied. Group is WAITING!")
|
||||||
return false
|
return false
|
||||||
elseif self:IsInUtero() then
|
elseif self:IsInUtero() then
|
||||||
self:E(self.lid.."Update route denied. Group is INUTERO!")
|
self:T(self.lid.."Update route denied. Group is INUTERO!")
|
||||||
return false
|
return false
|
||||||
elseif self:IsDead() then
|
elseif self:IsDead() then
|
||||||
self:E(self.lid.."Update route denied. Group is DEAD!")
|
self:T(self.lid.."Update route denied. Group is DEAD!")
|
||||||
return false
|
return false
|
||||||
elseif self:IsStopped() then
|
elseif self:IsStopped() then
|
||||||
self:E(self.lid.."Update route denied. Group is STOPPED!")
|
self:T(self.lid.."Update route denied. Group is STOPPED!")
|
||||||
return false
|
return false
|
||||||
elseif self:IsHolding() then
|
elseif self:IsHolding() then
|
||||||
self:T(self.lid.."Update route denied. Group is holding position!")
|
self:T(self.lid.."Update route denied. Group is holding position!")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return true
|
|
||||||
|
-- Check for a current task.
|
||||||
|
if self.taskcurrent>0 then
|
||||||
|
|
||||||
|
-- Get the current task. Must not be executing already.
|
||||||
|
local task=self:GetTaskByID(self.taskcurrent)
|
||||||
|
|
||||||
|
if task then
|
||||||
|
if task.dcstask.id=="PatrolZone" then
|
||||||
|
-- For patrol zone, we need to allow the update as we insert new waypoints.
|
||||||
|
self:T2(self.lid.."Allowing update route for Task: PatrolZone")
|
||||||
|
elseif task.dcstask.id=="ReconMission" then
|
||||||
|
-- For recon missions, we need to allow the update as we insert new waypoints.
|
||||||
|
self:T2(self.lid.."Allowing update route for Task: ReconMission")
|
||||||
|
elseif task.dcstask.id==AUFTRAG.SpecialTask.RELOCATECOHORT then
|
||||||
|
-- For relocate
|
||||||
|
self:T2(self.lid.."Allowing update route for Task: Relocate Cohort")
|
||||||
|
else
|
||||||
|
local taskname=task and task.description or "No description"
|
||||||
|
self:T(self.lid..string.format("WARNING: Update route denied because taskcurrent=%d>0! Task description = %s", self.taskcurrent, tostring(taskname)))
|
||||||
|
allowed=false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Now this can happen, if we directly use TaskExecute as the task is not in the task queue and cannot be removed. Therefore, also directly executed tasks should be added to the queue!
|
||||||
|
self:T(self.lid..string.format("WARNING: before update route taskcurrent=%d (>0!) but no task?!", self.taskcurrent))
|
||||||
|
-- Anyhow, a task is running so we do not allow to update the route!
|
||||||
|
allowed=false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Not good, because mission will never start. Better only check if there is a current task!
|
||||||
|
--if self.currentmission then
|
||||||
|
--end
|
||||||
|
|
||||||
|
-- Only AI flights.
|
||||||
|
if not self.isAI then
|
||||||
|
allowed=false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T2(self.lid..string.format("Onbefore Updateroute in state %s: allowed=%s (repeat in %s)", self:GetState(), tostring(allowed), tostring(trepeat)))
|
||||||
|
|
||||||
|
-- Try again?
|
||||||
|
if trepeat then
|
||||||
|
self:__UpdateRoute(trepeat, n)
|
||||||
|
end
|
||||||
|
|
||||||
|
return allowed
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "UpdateRoute" event.
|
--- On after "UpdateRoute" event.
|
||||||
@ -1712,6 +1764,13 @@ function NAVYGROUP:_InitGroup(Template)
|
|||||||
-- Max speed in km/h.
|
-- Max speed in km/h.
|
||||||
self.speedMax=self.group:GetSpeedMax()
|
self.speedMax=self.group:GetSpeedMax()
|
||||||
|
|
||||||
|
-- Is group mobile?
|
||||||
|
if self.speedMax>3.6 then
|
||||||
|
self.isMobile=true
|
||||||
|
else
|
||||||
|
self.isMobile=false
|
||||||
|
end
|
||||||
|
|
||||||
-- Cruise speed: 70% of max speed.
|
-- Cruise speed: 70% of max speed.
|
||||||
self.speedCruise=self.speedMax*0.7
|
self.speedCruise=self.speedMax*0.7
|
||||||
|
|
||||||
|
|||||||
@ -4144,8 +4144,18 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
|
|||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("Fire at point with nshots=%d of %d", nShots, nAmmo))
|
self:T(self.lid..string.format("Fire at point with nshots=%d of %d", nShots, nAmmo))
|
||||||
|
|
||||||
-- Only fire number of avail shots.
|
if nShots==-1 then
|
||||||
nShots=math.min(nShots, nAmmo)
|
-- The -1 is for using all available ammo.
|
||||||
|
nShots=nAmmo
|
||||||
|
self:T(self.lid..string.format("Fire at point taking max amount of ammo = %d", nShots))
|
||||||
|
elseif nShots<1 then
|
||||||
|
local p=nShots
|
||||||
|
nShots=UTILS.Round(p*nAmmo, 0)
|
||||||
|
self:T(self.lid..string.format("Fire at point taking %.1f percent amount of ammo = %d", p, nShots))
|
||||||
|
else
|
||||||
|
-- Fire nShots but at most nAmmo.
|
||||||
|
nShots=math.min(nShots, nAmmo)
|
||||||
|
end
|
||||||
|
|
||||||
-- Set quantity of task.
|
-- Set quantity of task.
|
||||||
DCSTask.params.expendQty=nShots
|
DCSTask.params.expendQty=nShots
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user