Merge branch 'develop' into FF/Ops

This commit is contained in:
Frank 2022-05-03 09:25:15 +02:00
commit 3a6b58ea8c
15 changed files with 840 additions and 436 deletions

View File

@ -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}().
@ -200,10 +202,13 @@ function MESSAGE:ToClient( Client, Settings )
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

View File

@ -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,7 +2797,11 @@ 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..", Bogey, Spades."
elseif Bogey then
BRAANATO = BRAANATO..", Bogey."
elseif Spades then
BRAANATO = BRAANATO..", Spades." BRAANATO = BRAANATO..", Spades."
else else
BRAANATO = BRAANATO.."." BRAANATO = BRAANATO.."."

View File

@ -1085,15 +1085,21 @@ 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 )
if not DontSetCargoBayLimit then
-- I set the default cargo bay weight limit each time a new group is added to the set. -- I set the default cargo bay weight limit each time a new group is added to the set.
-- TODO Why is this here in the first place?
for UnitID, UnitData in pairs( group:GetUnits() ) do for UnitID, UnitData in pairs( group:GetUnits() ) do
if UnitData and UnitData:IsAlive() then
UnitData:SetCargoBayWeightLimit() UnitData:SetCargoBayWeightLimit()
end end
end
end
return self return self
end end

View File

@ -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

View 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' )

View File

@ -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

View File

@ -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,7 +140,8 @@ 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
@ -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
@ -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.
@ -877,11 +885,23 @@ function INTEL:_UpdateContact(Contact)
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.
@ -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
@ -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}.
@ -1084,7 +1108,7 @@ function INTEL:onafterNewContact(From, Event, To, Contact)
-- 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.
@ -1100,7 +1124,7 @@ function INTEL:onafterLostContact(From, Event, To, Contact)
-- 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.
@ -1116,7 +1140,7 @@ function INTEL:onafterNewCluster(From, Event, To, Cluster)
-- 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.
@ -1137,7 +1161,7 @@ function INTEL:onafterLostCluster(From, Event, To, Cluster, Mission)
end end
self:T(text) self:T(text)
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.
@ -1458,6 +1482,8 @@ function INTEL:PaintPicture()
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
@ -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.
@ -1529,10 +1557,14 @@ 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.
@ -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.
@ -1643,6 +1675,8 @@ function INTEL:CalcClusterDirection(cluster)
-- 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
@ -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
@ -1839,6 +1883,10 @@ function INTEL:_GetClosestClusterOfContact(Contact)
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
@ -1846,7 +1894,20 @@ function INTEL:_GetClosestClusterOfContact(Contact)
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
@ -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.
@ -1963,10 +2058,12 @@ function INTEL:_UpdateClusterPositions()
-- 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.

View File

@ -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

View File

@ -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
@ -137,4 +137,26 @@ 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

View File

@ -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",

View File

@ -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

View File

@ -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. .
@ -1028,15 +1051,24 @@ end
-- @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 {}
for _,_unit in pairs(Units) do
local FirstUnit = _unit -- Wrapper.Unit#UNIT
if FirstUnit then if FirstUnit then
local FirstUnitCoordinate = FirstUnit:GetCoordinate() local FirstUnitCoordinate = FirstUnit:GetCoordinate()
if FirstUnitCoordinate then
local Heading = self:GetHeading() local Heading = self:GetHeading()
FirstUnitCoordinate.Heading = Heading FirstUnitCoordinate.Heading = Heading
return FirstUnitCoordinate 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

View File

@ -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

View File

@ -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