mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Merge branch 'develop' into FF/Ops
This commit is contained in:
commit
3a6b58ea8c
@ -10,6 +10,7 @@
|
|||||||
-- * Send message to all players.
|
-- * Send message to all players.
|
||||||
-- * Send messages to a coalition.
|
-- * Send messages to a coalition.
|
||||||
-- * Send messages to a specific group.
|
-- * Send messages to a specific group.
|
||||||
|
-- * Send messages to a specific unit or client.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@ -35,6 +36,7 @@
|
|||||||
--
|
--
|
||||||
-- * To a @{Client} using @{#MESSAGE.ToClient}().
|
-- * To a @{Client} using @{#MESSAGE.ToClient}().
|
||||||
-- * To a @{Wrapper.Group} using @{#MESSAGE.ToGroup}()
|
-- * To a @{Wrapper.Group} using @{#MESSAGE.ToGroup}()
|
||||||
|
-- * To a @{Wrapper.Unit} using @{#MESSAGE.ToUnit}()
|
||||||
-- * To a coalition using @{#MESSAGE.ToCoalition}().
|
-- * To a coalition using @{#MESSAGE.ToCoalition}().
|
||||||
-- * To the red coalition using @{#MESSAGE.ToRed}().
|
-- * To the red coalition using @{#MESSAGE.ToRed}().
|
||||||
-- * To the blue coalition using @{#MESSAGE.ToBlue}().
|
-- * To the blue coalition using @{#MESSAGE.ToBlue}().
|
||||||
@ -199,11 +201,14 @@ function MESSAGE:ToClient( Client, Settings )
|
|||||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local Unit = Client:GetClient()
|
||||||
|
|
||||||
if self.MessageDuration ~= 0 then
|
if self.MessageDuration ~= 0 then
|
||||||
local ClientGroupID = Client:GetClientGroupID()
|
local ClientGroupID = Client:GetClientGroupID()
|
||||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||||
trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
--trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
||||||
|
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -233,6 +238,31 @@ function MESSAGE:ToGroup( Group, Settings )
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Sends a MESSAGE to a Unit.
|
||||||
|
-- @param #MESSAGE self
|
||||||
|
-- @param Wrapper.Unit#UNIT Unit to which the message is displayed.
|
||||||
|
-- @return #MESSAGE Message object.
|
||||||
|
function MESSAGE:ToUnit( Unit, Settings )
|
||||||
|
self:F( Unit.IdentifiableName )
|
||||||
|
|
||||||
|
if Unit then
|
||||||
|
|
||||||
|
if self.MessageType then
|
||||||
|
local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
|
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||||
|
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.MessageDuration ~= 0 then
|
||||||
|
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||||
|
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Sends a MESSAGE to the Blue coalition.
|
--- Sends a MESSAGE to the Blue coalition.
|
||||||
-- @param #MESSAGE self
|
-- @param #MESSAGE self
|
||||||
-- @return #MESSAGE
|
-- @return #MESSAGE
|
||||||
|
|||||||
@ -2768,9 +2768,10 @@ do -- COORDINATE
|
|||||||
--- Create a BRAA NATO call string to this COORDINATE from the FromCOORDINATE. Note - BRA delivered if no aspect can be obtained and "Merged" if range < 3nm
|
--- Create a BRAA NATO call string to this COORDINATE from the FromCOORDINATE. Note - BRA delivered if no aspect can be obtained and "Merged" if range < 3nm
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
|
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
|
||||||
|
-- @param #boolean Bogey Add "Bogey" at the end if true (not yet declared hostile or friendly)
|
||||||
-- @param #boolean Spades Add "Spades" at the end if true (no IFF/VID ID yet known)
|
-- @param #boolean Spades Add "Spades" at the end if true (no IFF/VID ID yet known)
|
||||||
-- @return #string The BRAA text.
|
-- @return #string The BRAA text.
|
||||||
function COORDINATE:ToStringBRAANATO(FromCoordinate,Spades)
|
function COORDINATE:ToStringBRAANATO(FromCoordinate,Bogey,Spades)
|
||||||
|
|
||||||
-- Thanks to @Pikey
|
-- Thanks to @Pikey
|
||||||
local BRAANATO = "Merged."
|
local BRAANATO = "Merged."
|
||||||
@ -2796,8 +2797,12 @@ do -- COORDINATE
|
|||||||
else
|
else
|
||||||
BRAANATO = string.format("BRAA, %03d, %d miles, Angels %d, %s, Track %s",bearing, rangeNM, alt, aspect, track)
|
BRAANATO = string.format("BRAA, %03d, %d miles, Angels %d, %s, Track %s",bearing, rangeNM, alt, aspect, track)
|
||||||
end
|
end
|
||||||
if Spades then
|
if Bogey and Spades then
|
||||||
BRAANATO = BRAANATO..", Spades."
|
BRAANATO = BRAANATO..", Bogey, Spades."
|
||||||
|
elseif Bogey then
|
||||||
|
BRAANATO = BRAANATO..", Bogey."
|
||||||
|
elseif Spades then
|
||||||
|
BRAANATO = BRAANATO..", Spades."
|
||||||
else
|
else
|
||||||
BRAANATO = BRAANATO.."."
|
BRAANATO = BRAANATO.."."
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1085,16 +1085,22 @@ do -- SET_GROUP
|
|||||||
-- Note that for each unit in the group that is set, a default cargo bay limit is initialized.
|
-- Note that for each unit in the group that is set, a default cargo bay limit is initialized.
|
||||||
-- @param Core.Set#SET_GROUP self
|
-- @param Core.Set#SET_GROUP self
|
||||||
-- @param Wrapper.Group#GROUP group The group which should be added to the set.
|
-- @param Wrapper.Group#GROUP group The group which should be added to the set.
|
||||||
|
-- @param #boolean DontSetCargoBayLimit If true, do not attempt to auto-add the cargo bay limit per unit in this group.
|
||||||
-- @return Core.Set#SET_GROUP self
|
-- @return Core.Set#SET_GROUP self
|
||||||
function SET_GROUP:AddGroup( group )
|
function SET_GROUP:AddGroup( group, DontSetCargoBayLimit )
|
||||||
|
|
||||||
self:Add( group:GetName(), group )
|
self:Add( group:GetName(), group )
|
||||||
|
|
||||||
-- I set the default cargo bay weight limit each time a new group is added to the set.
|
if not DontSetCargoBayLimit then
|
||||||
for UnitID, UnitData in pairs( group:GetUnits() ) do
|
-- I set the default cargo bay weight limit each time a new group is added to the set.
|
||||||
UnitData:SetCargoBayWeightLimit()
|
-- TODO Why is this here in the first place?
|
||||||
|
for UnitID, UnitData in pairs( group:GetUnits() ) do
|
||||||
|
if UnitData and UnitData:IsAlive() then
|
||||||
|
UnitData:SetCargoBayWeightLimit()
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -3010,7 +3010,7 @@ function RANGE:_CheckInZone(_unitName)
|
|||||||
Straferesult.rangename=self.rangename
|
Straferesult.rangename=self.rangename
|
||||||
|
|
||||||
-- Save trap sheet.
|
-- Save trap sheet.
|
||||||
if playerData.targeton and self.targetsheet then
|
if playerData and playerData.targeton and self.targetsheet then
|
||||||
self:_SaveTargetSheet(_playername, result)
|
self:_SaveTargetSheet(_playername, result)
|
||||||
end
|
end
|
||||||
--RangeBoss edit for strafe data saved to file
|
--RangeBoss edit for strafe data saved to file
|
||||||
|
|||||||
@ -100,6 +100,7 @@ __Moose.Include( 'Scripts/Moose/Ops/OpsZone.lua' )
|
|||||||
__Moose.Include( 'Scripts/Moose/Ops/Chief.lua' )
|
__Moose.Include( 'Scripts/Moose/Ops/Chief.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Ops/Flotilla.lua' )
|
__Moose.Include( 'Scripts/Moose/Ops/Flotilla.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Ops/Fleet.lua' )
|
__Moose.Include( 'Scripts/Moose/Ops/Fleet.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Ops/Awacs.lua' )
|
||||||
|
|
||||||
__Moose.Include( 'Scripts/Moose/AI/AI_Balancer.lua' )
|
__Moose.Include( 'Scripts/Moose/AI/AI_Balancer.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/AI/AI_Air.lua' )
|
__Moose.Include( 'Scripts/Moose/AI/AI_Air.lua' )
|
||||||
|
|||||||
@ -5713,7 +5713,7 @@ function AIRBOSS:_ScanCarrierZone()
|
|||||||
local putintomarshal = false
|
local putintomarshal = false
|
||||||
|
|
||||||
-- Get flight group.
|
-- Get flight group.
|
||||||
local flight = _DATABASE:GetFlightGroup( groupname )
|
local flight = _DATABASE:GetOpsGroup( groupname )
|
||||||
|
|
||||||
if flight and flight:IsInbound() and flight.destbase:GetName() == self.carrier:GetName() then
|
if flight and flight:IsInbound() and flight.destbase:GetName() == self.carrier:GetName() then
|
||||||
if flight.ishelo then
|
if flight.ishelo then
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -122,8 +122,11 @@ INTEL = {
|
|||||||
-- @field Ops.Auftrag#AUFTRAG mission The current Auftrag attached to this contact.
|
-- @field Ops.Auftrag#AUFTRAG mission The current Auftrag attached to this contact.
|
||||||
-- @field Ops.Target#TARGET target The Target attached to this contact.
|
-- @field Ops.Target#TARGET target The Target attached to this contact.
|
||||||
-- @field #string recce The name of the recce unit that detected this contact.
|
-- @field #string recce The name of the recce unit that detected this contact.
|
||||||
-- @field #string ctype Contact type.
|
-- @field #string ctype Contact type of #INTEL.Ctype.
|
||||||
-- @field #string platform [AIR] Contact platform name, e.g. Foxbat, Flanker_E, defaults to Bogey if unknown
|
-- @field #string platform [AIR] Contact platform name, e.g. Foxbat, Flanker_E, defaults to Bogey if unknown
|
||||||
|
-- @field #number heading [AIR] Heading of the contact, if available.
|
||||||
|
-- @field #boolean maneuvering [AIR] Contact has changed direction by >10 deg.
|
||||||
|
-- @field #number altitude [AIR] Flight altitude of the contact in meters.
|
||||||
|
|
||||||
--- Cluster info.
|
--- Cluster info.
|
||||||
-- @type INTEL.Cluster
|
-- @type INTEL.Cluster
|
||||||
@ -137,11 +140,12 @@ INTEL = {
|
|||||||
-- @field Wrapper.Marker#MARKER marker F10 marker.
|
-- @field Wrapper.Marker#MARKER marker F10 marker.
|
||||||
-- @field #number markerID Marker ID.
|
-- @field #number markerID Marker ID.
|
||||||
-- @field Ops.Auftrag#AUFTRAG mission The current Auftrag attached to this cluster.
|
-- @field Ops.Auftrag#AUFTRAG mission The current Auftrag attached to this cluster.
|
||||||
-- @field #string ctype Cluster type.
|
-- @field #string ctype Cluster type of #INTEL.Ctype.
|
||||||
|
-- @field #number altitude [AIR] Average flight altitude of the cluster in meters.
|
||||||
|
|
||||||
--- 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.
|
||||||
@ -345,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
|
||||||
@ -541,6 +545,7 @@ function INTEL:SetDetectStatics(Switch)
|
|||||||
else
|
else
|
||||||
self.detectStatics=false
|
self.detectStatics=false
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set verbosity level for debugging.
|
--- Set verbosity level for debugging.
|
||||||
@ -692,6 +697,7 @@ function INTEL:onafterStart(From, Event, To)
|
|||||||
|
|
||||||
-- Start the status monitoring.
|
-- Start the status monitoring.
|
||||||
self:__Status(-math.random(10))
|
self:__Status(-math.random(10))
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "Status" event.
|
--- On after "Status" event.
|
||||||
@ -737,6 +743,7 @@ function INTEL:onafterStatus(From, Event, To)
|
|||||||
end
|
end
|
||||||
|
|
||||||
self:__Status(self.statusupdate)
|
self:__Status(self.statusupdate)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -746,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
|
||||||
@ -857,6 +864,7 @@ function INTEL:UpdateIntel()
|
|||||||
self:PaintPicture()
|
self:PaintPicture()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Update an #INTEL.Contact item.
|
--- Update an #INTEL.Contact item.
|
||||||
@ -866,22 +874,34 @@ 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()
|
||||||
Contact.position=Contact.group:GetCoordinate()
|
Contact.position=Contact.group:GetCoordinate()
|
||||||
Contact.velocity=Contact.group:GetVelocityVec3()
|
Contact.velocity=Contact.group:GetVelocityVec3()
|
||||||
Contact.speed=Contact.group:GetVelocityMPS()
|
Contact.speed=Contact.group:GetVelocityMPS()
|
||||||
|
if Contact.group:IsAir() then
|
||||||
|
Contact.altitude=Contact.group:GetAltitude()
|
||||||
|
local oldheading = Contact.heading or 1
|
||||||
|
local newheading = Contact.group:GetHeading()
|
||||||
|
if newheading == 0 then newheading = 1 end
|
||||||
|
local changeh = math.abs(((oldheading - newheading) + 360) % 360)
|
||||||
|
Contact.heading = newheading
|
||||||
|
if changeh > 10 then
|
||||||
|
Contact.maneuvering = true
|
||||||
|
else
|
||||||
|
Contact.maneuvering = false
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create an #INTEL.Contact item from a given GROUP or STATIC object.
|
--- Create an #INTEL.Contact item from a given GROUP or STATIC object.
|
||||||
@ -895,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()
|
||||||
@ -917,9 +937,13 @@ function INTEL:_CreateContact(Positionable, RecceName)
|
|||||||
item.isStatic=false
|
item.isStatic=false
|
||||||
if group:IsAir() then
|
if group:IsAir() then
|
||||||
item.platform=group:GetNatoReportingName()
|
item.platform=group:GetNatoReportingName()
|
||||||
|
item.heading = group:GetHeading()
|
||||||
|
item.maneuvering = false
|
||||||
|
item.altitude = group:GetAltitude()
|
||||||
else
|
else
|
||||||
-- TODO optionally add ground types?
|
-- TODO optionally add ground types?
|
||||||
item.platform="Unknown"
|
item.platform="Unknown"
|
||||||
|
item.altitude = group:GetAltitude(true)
|
||||||
end
|
end
|
||||||
if item.category==Group.Category.AIRPLANE or item.category==Group.Category.HELICOPTER then
|
if item.category==Group.Category.AIRPLANE or item.category==Group.Category.HELICOPTER then
|
||||||
item.ctype=INTEL.Ctype.AIRCRAFT
|
item.ctype=INTEL.Ctype.AIRCRAFT
|
||||||
@ -928,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()
|
||||||
@ -949,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
|
||||||
@ -981,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
|
||||||
@ -1006,7 +1030,7 @@ function INTEL:CreateDetectedItems(DetectedGroups, DetectedStatics, RecceDetecti
|
|||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) Return the detected target groups of the controllable as a @{SET_GROUP}.
|
--- (Internal) Return the detected target groups of the controllable as a @{SET_GROUP}.
|
||||||
@ -1081,10 +1105,10 @@ 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
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "LostContact" event.
|
--- On after "LostContact" event.
|
||||||
@ -1097,10 +1121,10 @@ 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
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "NewCluster" event.
|
--- On after "NewCluster" event.
|
||||||
@ -1110,13 +1134,13 @@ 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
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "LostCluster" event.
|
--- On after "LostCluster" event.
|
||||||
@ -1130,14 +1154,14 @@ 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
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@ -1154,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
|
||||||
|
|
||||||
@ -1244,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
|
||||||
|
|
||||||
@ -1261,7 +1285,7 @@ function INTEL:RemoveContact(Contact)
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if a contact was lost.
|
--- Check if a contact was lost.
|
||||||
@ -1274,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
|
||||||
@ -1284,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
|
||||||
@ -1317,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)
|
||||||
@ -1398,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
|
||||||
@ -1410,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
|
||||||
@ -1446,18 +1470,20 @@ 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
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create a new cluster.
|
--- Create a new cluster.
|
||||||
@ -1474,6 +1500,7 @@ function INTEL:_CreateCluster()
|
|||||||
cluster.threatlevelMax=0
|
cluster.threatlevelMax=0
|
||||||
cluster.size=0
|
cluster.size=0
|
||||||
cluster.Contacts={}
|
cluster.Contacts={}
|
||||||
|
cluster.altitude=0
|
||||||
|
|
||||||
-- Increase counter.
|
-- Increase counter.
|
||||||
self.clustercounter=self.clustercounter+1
|
self.clustercounter=self.clustercounter+1
|
||||||
@ -1488,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
|
||||||
|
|
||||||
@ -1510,6 +1537,7 @@ function INTEL:_AddCluster(Cluster)
|
|||||||
-- Add cluster.
|
-- Add cluster.
|
||||||
table.insert(self.Clusters, Cluster)
|
table.insert(self.Clusters, Cluster)
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add a contact to the cluster.
|
--- Add a contact to the cluster.
|
||||||
@ -1519,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)
|
||||||
|
|
||||||
@ -1528,11 +1556,15 @@ function INTEL:AddContactToCluster(contact, cluster)
|
|||||||
|
|
||||||
-- Increase size.
|
-- Increase size.
|
||||||
cluster.size=cluster.size+1
|
cluster.size=cluster.size+1
|
||||||
|
|
||||||
|
-- alt
|
||||||
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Remove a contact from a cluster.
|
--- Remove a contact from a cluster.
|
||||||
@ -1550,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
|
||||||
|
|
||||||
@ -1560,13 +1592,13 @@ function INTEL:RemoveContactFromCluster(contact, cluster)
|
|||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("Removing contact %s from cluster #%d ==> New cluster size=%d", contact.groupname, cluster.index, cluster.size))
|
self:T(self.lid..string.format("Removing contact %s from cluster #%d ==> New cluster size=%d", contact.groupname, cluster.index, cluster.size))
|
||||||
|
|
||||||
return
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Calculate cluster threat level sum.
|
--- Calculate cluster threat level sum.
|
||||||
@ -1630,20 +1662,22 @@ 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
|
||||||
-- Second group is going East, i.e. heading 270
|
-- Second group is going East, i.e. heading 270
|
||||||
-- Total is 360/2=180, i.e. South!
|
-- Total is 360/2=180, i.e. South!
|
||||||
-- 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?
|
||||||
|
-- maybe add the speed as weight to get a factor
|
||||||
|
|
||||||
if n==0 then
|
if n==0 then
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
@ -1660,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
|
||||||
@ -1682,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
|
||||||
@ -1693,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
|
||||||
|
|
||||||
@ -1703,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
|
||||||
@ -1726,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
|
||||||
|
|
||||||
@ -1764,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
|
||||||
|
|
||||||
@ -1774,7 +1808,17 @@ 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)
|
||||||
|
|
||||||
if dist<self.clusterradius then
|
-- AIR - check for spatial proximity
|
||||||
|
local airprox = false
|
||||||
|
if contact.ctype == INTEL.Ctype.AIRCRAFT then
|
||||||
|
self:T(string.format("Cluster Alt=%d | Contact Alt=%d",cluster.altitude,contact.altitude))
|
||||||
|
local adist = math.abs(cluster.altitude - contact.altitude)
|
||||||
|
if adist < UTILS.FeetToMeters(10000) then -- limit to 10kft
|
||||||
|
airprox = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if dist<self.clusterradius and airprox then
|
||||||
return true, dist
|
return true, dist
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1810,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
|
||||||
@ -1836,21 +1880,38 @@ 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
|
||||||
|
Contact.altitude = Contact.group:GetAltitude()
|
||||||
|
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)
|
||||||
|
|
||||||
if dist<distmin then
|
-- AIR - check for spatial proximity
|
||||||
|
local airprox = false
|
||||||
|
if Contact.ctype == INTEL.Ctype.AIRCRAFT then
|
||||||
|
if not cluster.altitude then
|
||||||
|
cluster.altitude = self:GetClusterAltitude(cluster,true)
|
||||||
|
end
|
||||||
|
local adist = math.abs(cluster.altitude - Contact.altitude)
|
||||||
|
self:T(string.format("Cluster Alt=%d | Contact Alt=%d",cluster.altitude,Contact.altitude))
|
||||||
|
if adist < UTILS.FeetToMeters(10000) then
|
||||||
|
airprox = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if dist<distmin and airprox then
|
||||||
Cluster=cluster
|
Cluster=cluster
|
||||||
distmin=dist
|
distmin=dist
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1878,6 +1939,40 @@ function INTEL:GetClusterOfContact(contact)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get the altitude of a cluster.
|
||||||
|
-- @param #INTEL self
|
||||||
|
-- @param #INTEL.Cluster Cluster The cluster.
|
||||||
|
-- @param #boolean Update If `true`, update the altitude. Default is to just return the last stored altitude.
|
||||||
|
-- @return #number The average altitude (ASL) of this cluster in meters.
|
||||||
|
function INTEL:GetClusterAltitude(Cluster, Update)
|
||||||
|
|
||||||
|
-- Init.
|
||||||
|
local newalt = 0
|
||||||
|
local n=0
|
||||||
|
|
||||||
|
-- Loop over all contacts.
|
||||||
|
for _,_contact in pairs(Cluster.Contacts) do
|
||||||
|
local contact=_contact --#INTEL.Contact
|
||||||
|
if contact.altitude then
|
||||||
|
newalt = newalt + contact.altitude
|
||||||
|
n=n+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Average.
|
||||||
|
local avgalt = 0
|
||||||
|
if n>0 then
|
||||||
|
avgalt = newalt/n
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update cluster coordinate.
|
||||||
|
Cluster.altitude = avgalt
|
||||||
|
|
||||||
|
self:T(string.format("Updating Cluster Altitude: %d",Cluster.altitude))
|
||||||
|
|
||||||
|
return Cluster.altitude
|
||||||
|
end
|
||||||
|
|
||||||
--- Get the coordinate of a cluster.
|
--- Get the coordinate of a cluster.
|
||||||
-- @param #INTEL self
|
-- @param #INTEL self
|
||||||
-- @param #INTEL.Cluster Cluster The cluster.
|
-- @param #INTEL.Cluster Cluster The cluster.
|
||||||
@ -1887,43 +1982,43 @@ 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 and contact.group:IsAlive() then
|
if Update and contact.group and contact.group:IsAlive() then
|
||||||
vec3 = contact.group:GetVec3()
|
vec3 = contact.group:GetVec3()
|
||||||
end
|
end
|
||||||
|
|
||||||
if not vec3 then
|
if not vec3 then
|
||||||
vec3=contact.position
|
vec3=contact.position
|
||||||
end
|
end
|
||||||
|
|
||||||
if vec3 then
|
if vec3 then
|
||||||
|
|
||||||
-- Sum up posits.
|
-- 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
|
||||||
|
|
||||||
if n>0 then
|
if n>0 then
|
||||||
|
|
||||||
-- Average.
|
-- Average.
|
||||||
local Vec3={x=x/n, y=y/n, z=z/n} --DCS#Vec3
|
local Vec3={x=x/n, y=y/n, z=z/n} --DCS#Vec3
|
||||||
|
|
||||||
-- Update cluster coordinate.
|
-- Update cluster coordinate.
|
||||||
Cluster.coordinate:UpdateFromVec3(Vec3)
|
Cluster.coordinate:UpdateFromVec3(Vec3)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return Cluster.coordinate
|
return Cluster.coordinate
|
||||||
@ -1938,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.
|
||||||
@ -1960,13 +2055,15 @@ 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)
|
||||||
|
|
||||||
-- 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
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Count number of alive units in contact.
|
--- Count number of alive units in contact.
|
||||||
@ -1982,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
|
||||||
@ -1996,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
|
||||||
@ -2014,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?
|
||||||
@ -2030,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
|
||||||
@ -2109,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
|
||||||
|
|||||||
@ -2085,7 +2085,7 @@ function OPSGROUP:RadioTransmission(Text, Delay, SayCallsign, Frequency)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:I(self.lid..string.format("Radio transmission on %.3f MHz %s: %s", freq, UTILS.GetModulationName(modu), Text))
|
self:T(self.lid..string.format("Radio transmission on %.3f MHz %s: %s", freq, UTILS.GetModulationName(modu), Text))
|
||||||
|
|
||||||
self.msrs:PlayText(Text)
|
self.msrs:PlayText(Text)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -40,7 +40,7 @@ do -- UserSound
|
|||||||
-- @param #USERSOUND self
|
-- @param #USERSOUND self
|
||||||
-- @param #string UserSoundFileName The filename of the usersound.
|
-- @param #string UserSoundFileName The filename of the usersound.
|
||||||
-- @return #USERSOUND
|
-- @return #USERSOUND
|
||||||
function USERSOUND:New( UserSoundFileName ) --R2.3
|
function USERSOUND:New( UserSoundFileName )
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #USERSOUND
|
local self = BASE:Inherit( self, BASE:New() ) -- #USERSOUND
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ do -- UserSound
|
|||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- BlueVictory:SetFileName( "BlueVictoryLoud.ogg" ) -- Set the BlueVictory to change the file name to play a louder sound.
|
-- BlueVictory:SetFileName( "BlueVictoryLoud.ogg" ) -- Set the BlueVictory to change the file name to play a louder sound.
|
||||||
--
|
--
|
||||||
function USERSOUND:SetFileName( UserSoundFileName ) --R2.3
|
function USERSOUND:SetFileName( UserSoundFileName )
|
||||||
|
|
||||||
self.UserSoundFileName = UserSoundFileName
|
self.UserSoundFileName = UserSoundFileName
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ do -- UserSound
|
|||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- BlueVictory:ToAll() -- Play the sound that Blue has won.
|
-- BlueVictory:ToAll() -- Play the sound that Blue has won.
|
||||||
--
|
--
|
||||||
function USERSOUND:ToAll() --R2.3
|
function USERSOUND:ToAll()
|
||||||
|
|
||||||
trigger.action.outSound( self.UserSoundFileName )
|
trigger.action.outSound( self.UserSoundFileName )
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ do -- UserSound
|
|||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- BlueVictory:ToCoalition( coalition.side.BLUE ) -- Play the sound that Blue has won to the blue coalition.
|
-- BlueVictory:ToCoalition( coalition.side.BLUE ) -- Play the sound that Blue has won to the blue coalition.
|
||||||
--
|
--
|
||||||
function USERSOUND:ToCoalition( Coalition ) --R2.3
|
function USERSOUND:ToCoalition( Coalition )
|
||||||
|
|
||||||
trigger.action.outSoundForCoalition(Coalition, self.UserSoundFileName )
|
trigger.action.outSoundForCoalition(Coalition, self.UserSoundFileName )
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ do -- UserSound
|
|||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- BlueVictory:ToCountry( country.id.USA ) -- Play the sound that Blue has won to the USA country.
|
-- BlueVictory:ToCountry( country.id.USA ) -- Play the sound that Blue has won to the USA country.
|
||||||
--
|
--
|
||||||
function USERSOUND:ToCountry( Country ) --R2.3
|
function USERSOUND:ToCountry( Country )
|
||||||
|
|
||||||
trigger.action.outSoundForCountry( Country, self.UserSoundFileName )
|
trigger.action.outSoundForCountry( Country, self.UserSoundFileName )
|
||||||
|
|
||||||
@ -123,9 +123,9 @@ do -- UserSound
|
|||||||
-- @usage
|
-- @usage
|
||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- local PlayerGroup = GROUP:FindByName( "PlayerGroup" ) -- Search for the active group named "PlayerGroup", that contains a human player.
|
-- local PlayerGroup = GROUP:FindByName( "PlayerGroup" ) -- Search for the active group named "PlayerGroup", that contains a human player.
|
||||||
-- BlueVictory:ToGroup( PlayerGroup ) -- Play the sound that Blue has won to the player group.
|
-- BlueVictory:ToGroup( PlayerGroup ) -- Play the victory sound to the player group.
|
||||||
--
|
--
|
||||||
function USERSOUND:ToGroup( Group, Delay ) --R2.3
|
function USERSOUND:ToGroup( Group, Delay )
|
||||||
|
|
||||||
Delay=Delay or 0
|
Delay=Delay or 0
|
||||||
if Delay>0 then
|
if Delay>0 then
|
||||||
@ -136,5 +136,27 @@ do -- UserSound
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Play the usersound to the given @{Wrapper.Unit}.
|
||||||
|
-- @param #USERSOUND self
|
||||||
|
-- @param Wrapper.Unit#UNIT Unit The @{Wrapper.Unit} to play the usersound to.
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds, before the sound is played. Default 0.
|
||||||
|
-- @return #USERSOUND The usersound instance.
|
||||||
|
-- @usage
|
||||||
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
|
-- local PlayerUnit = UNIT:FindByName( "PlayerUnit" ) -- Search for the active unit named "PlayerUnit", a human player.
|
||||||
|
-- BlueVictory:ToUnit( PlayerUnit ) -- Play the victory sound to the player unit.
|
||||||
|
--
|
||||||
|
function USERSOUND:ToUnit( Unit, Delay )
|
||||||
|
|
||||||
|
Delay=Delay or 0
|
||||||
|
if Delay>0 then
|
||||||
|
SCHEDULER:New(nil, USERSOUND.ToUnit,{self, Unit}, Delay)
|
||||||
|
else
|
||||||
|
trigger.action.outSoundForUnit( Unit:GetID(), self.UserSoundFileName )
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -509,11 +509,12 @@ ENUMS.ReportingName =
|
|||||||
Atlas = "A400",
|
Atlas = "A400",
|
||||||
Lancer = "B1-B",
|
Lancer = "B1-B",
|
||||||
Stratofortress = "B-52H",
|
Stratofortress = "B-52H",
|
||||||
Hercules = "C-130", -- modded version has type name "Hercules", unfortunately
|
Hercules = "C-130",
|
||||||
|
Super_Hercules = "Hercules",
|
||||||
Globemaster = "C-17",
|
Globemaster = "C-17",
|
||||||
Greyhound = "C-2A",
|
Greyhound = "C-2A",
|
||||||
Galaxy = "C-5",
|
Galaxy = "C-5",
|
||||||
Hawkexe = "E-2D",
|
Hawkeye = "E-2D",
|
||||||
Sentry = "E-3A",
|
Sentry = "E-3A",
|
||||||
Stratotanker = "KC-135",
|
Stratotanker = "KC-135",
|
||||||
Extender = "KC-10",
|
Extender = "KC-10",
|
||||||
|
|||||||
@ -249,7 +249,11 @@ end
|
|||||||
-- @return #boolean exists
|
-- @return #boolean exists
|
||||||
function FIFO:HasUniqueID(UniqueID)
|
function FIFO:HasUniqueID(UniqueID)
|
||||||
self:T(self.lid.."HasUniqueID")
|
self:T(self.lid.."HasUniqueID")
|
||||||
return self.stackbyid[UniqueID] and true or false
|
if self.stackbyid[UniqueID] ~= nil then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- FIFO Get the data stack by UniqueID
|
--- FIFO Get the data stack by UniqueID
|
||||||
|
|||||||
@ -631,7 +631,7 @@ function GROUP:GetUnits()
|
|||||||
local DCSGroup = self:GetDCSObject()
|
local DCSGroup = self:GetDCSObject()
|
||||||
|
|
||||||
if DCSGroup then
|
if DCSGroup then
|
||||||
local DCSUnits = DCSGroup:getUnits()
|
local DCSUnits = DCSGroup:getUnits() or {}
|
||||||
local Units = {}
|
local Units = {}
|
||||||
for Index, UnitData in pairs( DCSUnits ) do
|
for Index, UnitData in pairs( DCSUnits ) do
|
||||||
Units[#Units+1] = UNIT:Find( UnitData )
|
Units[#Units+1] = UNIT:Find( UnitData )
|
||||||
@ -667,6 +667,29 @@ function GROUP:GetPlayerUnits()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if an (air) group is a client or player slot. Information is retrieved from the group template.
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @return #boolean If true, group is associated with a client or player slot.
|
||||||
|
function GROUP:IsPlayer()
|
||||||
|
|
||||||
|
-- Get group.
|
||||||
|
-- local group=self:GetGroup()
|
||||||
|
|
||||||
|
-- Units of template group.
|
||||||
|
local units=self:GetTemplate().units
|
||||||
|
|
||||||
|
-- Get numbers.
|
||||||
|
for _,unit in pairs(units) do
|
||||||
|
|
||||||
|
-- Check if unit name matach and skill is Client or Player.
|
||||||
|
if unit.name==self:GetName() and (unit.skill=="Client" or unit.skill=="Player") then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns the UNIT wrapper class with number UnitNumber.
|
--- Returns the UNIT wrapper class with number UnitNumber.
|
||||||
-- If the underlying DCS Unit does not exist, the method will return nil. .
|
-- If the underlying DCS Unit does not exist, the method will return nil. .
|
||||||
@ -1027,16 +1050,25 @@ end
|
|||||||
-- @param Wrapper.Group#GROUP self
|
-- @param Wrapper.Group#GROUP self
|
||||||
-- @return Core.Point#COORDINATE The COORDINATE of the GROUP.
|
-- @return Core.Point#COORDINATE The COORDINATE of the GROUP.
|
||||||
function GROUP:GetCoordinate()
|
function GROUP:GetCoordinate()
|
||||||
|
|
||||||
local FirstUnit = self:GetUnit(1)
|
|
||||||
|
local Units = self:GetUnits() or {}
|
||||||
|
|
||||||
if FirstUnit then
|
for _,_unit in pairs(Units) do
|
||||||
local FirstUnitCoordinate = FirstUnit:GetCoordinate()
|
local FirstUnit = _unit -- Wrapper.Unit#UNIT
|
||||||
local Heading = self:GetHeading()
|
|
||||||
FirstUnitCoordinate.Heading = Heading
|
if FirstUnit then
|
||||||
return FirstUnitCoordinate
|
|
||||||
|
local FirstUnitCoordinate = FirstUnit:GetCoordinate()
|
||||||
|
|
||||||
|
if FirstUnitCoordinate then
|
||||||
|
local Heading = self:GetHeading()
|
||||||
|
FirstUnitCoordinate.Heading = Heading
|
||||||
|
return FirstUnitCoordinate
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
BASE:E( { "Cannot GetCoordinate", Group = self, Alive = self:IsAlive() } )
|
BASE:E( { "Cannot GetCoordinate", Group = self, Alive = self:IsAlive() } )
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -1187,6 +1187,33 @@ function POSITIONABLE:MessageToGroup( Message, Duration, MessageGroup, Name )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Send a message to a @{Wrapper.Unit}.
|
||||||
|
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||||
|
-- @param #POSITIONABLE self
|
||||||
|
-- @param #string Message The message text
|
||||||
|
-- @param DCS#Duration Duration The duration of the message.
|
||||||
|
-- @param Wrapper.Unit#UNIT MessageUnit The UNIT object receiving the message.
|
||||||
|
-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable.
|
||||||
|
function POSITIONABLE:MessageToUnit( Message, Duration, MessageUnit, Name )
|
||||||
|
self:F2( { Message, Duration } )
|
||||||
|
|
||||||
|
local DCSObject = self:GetDCSObject()
|
||||||
|
if DCSObject then
|
||||||
|
if DCSObject:isExist() then
|
||||||
|
if MessageUnit:IsAlive() then
|
||||||
|
self:GetMessage( Message, Duration, Name ):ToUnit( MessageUnit )
|
||||||
|
else
|
||||||
|
BASE:E( { "Message not sent to Unit; Unit is not alive...", Message = Message, MessageUnit = MessageUnit } )
|
||||||
|
end
|
||||||
|
else
|
||||||
|
BASE:E( { "Message not sent to Unit; Positionable is not alive ...", Message = Message, Positionable = self, MessageUnit = MessageUnit } )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--- Send a message of a message type to a @{Wrapper.Group}.
|
--- Send a message of a message type to a @{Wrapper.Group}.
|
||||||
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||||
-- @param #POSITIONABLE self
|
-- @param #POSITIONABLE self
|
||||||
@ -1231,6 +1258,30 @@ function POSITIONABLE:MessageToSetGroup( Message, Duration, MessageSetGroup, Nam
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Send a message to a @{Core.Set#SET_UNIT}.
|
||||||
|
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||||
|
-- @param #POSITIONABLE self
|
||||||
|
-- @param #string Message The message text
|
||||||
|
-- @param DCS#Duration Duration The duration of the message.
|
||||||
|
-- @param Core.Set#SET_UNIT MessageSetUnit The SET_UNIT collection receiving the message.
|
||||||
|
-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable.
|
||||||
|
function POSITIONABLE:MessageToSetUnit( Message, Duration, MessageSetUnit, Name )
|
||||||
|
self:F2( { Message, Duration } )
|
||||||
|
|
||||||
|
local DCSObject = self:GetDCSObject()
|
||||||
|
if DCSObject then
|
||||||
|
if DCSObject:isExist() then
|
||||||
|
MessageSetUnit:ForEachUnit(
|
||||||
|
function( MessageGroup )
|
||||||
|
self:GetMessage( Message, Duration, Name ):ToUnit( MessageGroup )
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--- Send a message to the players in the @{Wrapper.Group}.
|
--- Send a message to the players in the @{Wrapper.Group}.
|
||||||
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||||
-- @param #POSITIONABLE self
|
-- @param #POSITIONABLE self
|
||||||
|
|||||||
@ -95,6 +95,7 @@ Ops/Commander.lua
|
|||||||
Ops/Chief.lua
|
Ops/Chief.lua
|
||||||
Ops/CSAR.lua
|
Ops/CSAR.lua
|
||||||
Ops/CTLD.lua
|
Ops/CTLD.lua
|
||||||
|
Ops/Awacs.lua
|
||||||
|
|
||||||
AI/AI_Balancer.lua
|
AI/AI_Balancer.lua
|
||||||
AI/AI_Air.lua
|
AI/AI_Air.lua
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user