mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
commit
7affd05247
@ -979,13 +979,15 @@ function DATABASE:_RegisterClients()
|
||||
|
||||
for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do
|
||||
self:I(string.format("Register Client: %s", tostring(ClientName)))
|
||||
self:AddClient( ClientName )
|
||||
local client=self:AddClient( ClientName )
|
||||
client.SpawnCoord=COORDINATE:New(ClientTemplate.x, ClientTemplate.alt, ClientTemplate.y)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- @param #DATABASE self
|
||||
--- Private method that registeres all static objects.
|
||||
-- @param #DATABASE self
|
||||
function DATABASE:_RegisterStatics()
|
||||
|
||||
local CoalitionsData={GroupsRed=coalition.getStaticObjects(coalition.side.RED), GroupsBlue=coalition.getStaticObjects(coalition.side.BLUE), GroupsNeutral=coalition.getStaticObjects(coalition.side.NEUTRAL)}
|
||||
@ -1036,11 +1038,6 @@ function DATABASE:_RegisterAirbases()
|
||||
text=text.."]"
|
||||
self:I(text)
|
||||
|
||||
-- Check for DCS bug IDs.
|
||||
if airbaseID~=airbase:GetID() then
|
||||
--self:E("WARNING: :getID does NOT match :GetID!")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
|
||||
@ -398,7 +398,7 @@ end
|
||||
-- @param #ZONE_BASE self
|
||||
-- @return #table Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value.
|
||||
function ZONE_BASE:GetColor()
|
||||
return self.Color
|
||||
return self.Color or {1, 0, 0, 0.15}
|
||||
end
|
||||
|
||||
--- Get RGB color of zone.
|
||||
@ -406,9 +406,10 @@ end
|
||||
-- @return #table Table with three entries, e.g. {1, 0, 0}, which is the RGB color code.
|
||||
function ZONE_BASE:GetColorRGB()
|
||||
local rgb={}
|
||||
rgb[1]=self.Color[1]
|
||||
rgb[2]=self.Color[2]
|
||||
rgb[3]=self.Color[3]
|
||||
local Color=self:GetColor()
|
||||
rgb[1]=Color[1]
|
||||
rgb[2]=Color[2]
|
||||
rgb[3]=Color[3]
|
||||
return rgb
|
||||
end
|
||||
|
||||
@ -416,7 +417,8 @@ end
|
||||
-- @param #ZONE_BASE self
|
||||
-- @return #number Alpha value.
|
||||
function ZONE_BASE:GetColorAlpha()
|
||||
local alpha=self.Color[4]
|
||||
local Color=self:GetColor()
|
||||
local alpha=Color[4]
|
||||
return alpha
|
||||
end
|
||||
|
||||
@ -443,7 +445,7 @@ end
|
||||
-- @param #ZONE_BASE self
|
||||
-- @return #table Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value.
|
||||
function ZONE_BASE:GetFillColor()
|
||||
return self.FillColor
|
||||
return self.FillColor or {1, 0, 0, 0.15}
|
||||
end
|
||||
|
||||
--- Get RGB fill color of zone.
|
||||
@ -451,9 +453,10 @@ end
|
||||
-- @return #table Table with three entries, e.g. {1, 0, 0}, which is the RGB color code.
|
||||
function ZONE_BASE:GetFillColorRGB()
|
||||
local rgb={}
|
||||
rgb[1]=self.FillColor[1]
|
||||
rgb[2]=self.FillColor[2]
|
||||
rgb[3]=self.FillColor[3]
|
||||
local FillColor=self:GetFillColor()
|
||||
rgb[1]=FillColor[1]
|
||||
rgb[2]=FillColor[2]
|
||||
rgb[3]=FillColor[3]
|
||||
return rgb
|
||||
end
|
||||
|
||||
@ -461,7 +464,8 @@ end
|
||||
-- @param #ZONE_BASE self
|
||||
-- @return #number Alpha value.
|
||||
function ZONE_BASE:GetFillColorAlpha()
|
||||
local alpha=self.FillColor[4]
|
||||
local FillColor=self:GetFillColor()
|
||||
local alpha=FillColor[4]
|
||||
return alpha
|
||||
end
|
||||
|
||||
@ -1683,7 +1687,7 @@ end
|
||||
|
||||
|
||||
--- @type ZONE_POLYGON_BASE
|
||||
-- --@field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{DCS#Vec2}.
|
||||
-- @field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{DCS#Vec2}.
|
||||
-- @extends #ZONE_BASE
|
||||
|
||||
|
||||
@ -2387,8 +2391,8 @@ do -- ZONE_ELASTIC
|
||||
--- Update the convex hull of the polygon.
|
||||
-- This uses the [Graham scan](https://en.wikipedia.org/wiki/Graham_scan).
|
||||
-- @param #ZONE_ELASTIC self
|
||||
-- @field #number Delay Delay in seconds before the zone is updated. Default 0.
|
||||
-- @field #boolean Draw Draw the zone. Default `nil`.
|
||||
-- @param #number Delay Delay in seconds before the zone is updated. Default 0.
|
||||
-- @param #boolean Draw Draw the zone. Default `nil`.
|
||||
-- @return #ZONE_ELASTIC self
|
||||
function ZONE_ELASTIC:Update(Delay, Draw)
|
||||
|
||||
@ -2420,6 +2424,7 @@ do -- ZONE_ELASTIC
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Start the updating scheduler.
|
||||
@ -2427,7 +2432,7 @@ do -- ZONE_ELASTIC
|
||||
-- @param #number Tstart Time in seconds before the updating starts.
|
||||
-- @param #number dT Time interval in seconds between updates. Default 60 sec.
|
||||
-- @param #number Tstop Time in seconds after which the updating stops. Default `nil`.
|
||||
-- @field #boolean Draw Draw the zone. Default `nil`.
|
||||
-- @param #boolean Draw Draw the zone. Default `nil`.
|
||||
-- @return #ZONE_ELASTIC self
|
||||
function ZONE_ELASTIC:StartUpdate(Tstart, dT, Tstop, Draw)
|
||||
|
||||
|
||||
@ -792,7 +792,7 @@ function FOX:onafterMissileLaunch(From, Event, To, missile)
|
||||
local text=string.format("Missile launch detected! Distance %.1f NM, bearing %03d°.", UTILS.MetersToNM(distance), bearing)
|
||||
|
||||
-- Say notching headings.
|
||||
BASE:ScheduleOnce(5, FOX._SayNotchingHeadings, self, player, missile.weapon)
|
||||
self:ScheduleOnce(5, FOX._SayNotchingHeadings, self, player, missile.weapon)
|
||||
|
||||
--TODO: ALERT or INFO depending on whether this is a direct target.
|
||||
--TODO: lauchalertall option.
|
||||
@ -1114,6 +1114,13 @@ end
|
||||
-- Event Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- FOX event handler for event birth.
|
||||
-- @param #FOX self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function FOX:OnEventPlayerEnterAircraft(EventData)
|
||||
|
||||
end
|
||||
|
||||
--- FOX event handler for event birth.
|
||||
-- @param #FOX self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
@ -1155,7 +1162,7 @@ function FOX:OnEventBirth(EventData)
|
||||
|
||||
-- Add F10 radio menu for player.
|
||||
if not self.menudisabled then
|
||||
SCHEDULER:New(nil, self._AddF10Commands, {self,_unitName}, 0.1)
|
||||
self:ScheduleOnce(0.1, FOX._AddF10Commands, self, _unitname)
|
||||
end
|
||||
|
||||
-- Player data.
|
||||
|
||||
@ -1978,7 +1978,8 @@ function AIRBOSS:New( carriername, alias )
|
||||
|
||||
-- Init carrier parameters.
|
||||
if self.carriertype == AIRBOSS.CarrierType.STENNIS then
|
||||
self:_InitStennis()
|
||||
--self:_InitStennis()
|
||||
self:_InitNimitz()
|
||||
elseif self.carriertype == AIRBOSS.CarrierType.ROOSEVELT then
|
||||
self:_InitNimitz()
|
||||
elseif self.carriertype == AIRBOSS.CarrierType.LINCOLN then
|
||||
|
||||
@ -51,6 +51,7 @@
|
||||
-- @field Core.Spawn#SPAWN parkingGuard Parking guard spawner.
|
||||
-- @field #table holdingpatterns Holding points.
|
||||
-- @field #number hpcounter Counter for holding zones.
|
||||
-- @field Sound.SRS#MSRSQUEUE msrsqueue Queue for TTS transmissions using MSRS class.
|
||||
-- @field Sound.SRS#MSRS msrsTower Moose SRS wrapper.
|
||||
-- @field Sound.SRS#MSRS msrsPilot Moose SRS wrapper.
|
||||
-- @field #number Tlastmessage Time stamp (abs.) of last radio transmission.
|
||||
@ -326,7 +327,7 @@ FLIGHTCONTROL.FlightStatus={
|
||||
|
||||
--- FlightControl class version.
|
||||
-- @field #string version
|
||||
FLIGHTCONTROL.version="0.7.0"
|
||||
FLIGHTCONTROL.version="0.7.1"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -405,6 +406,9 @@ function FLIGHTCONTROL:New(AirbaseName, Frequency, Modulation, PathToSRS)
|
||||
self:SetMarkHoldingPattern(true)
|
||||
self:SetRunwayRepairtime()
|
||||
|
||||
-- Init msrs queue.
|
||||
self.msrsqueue=MSRSQUEUE:New(self.alias)
|
||||
|
||||
-- SRS for Tower.
|
||||
self.msrsTower=MSRS:New(PathToSRS, Frequency, Modulation)
|
||||
self:SetSRSTower()
|
||||
@ -977,6 +981,7 @@ end
|
||||
-- @param #FLIGHTCONTROL self
|
||||
function FLIGHTCONTROL:onbeforeStatusUpdate()
|
||||
|
||||
--[[
|
||||
if self.Tlastmessage then
|
||||
local Tnow=timer.getAbsTime()
|
||||
|
||||
@ -1001,6 +1006,21 @@ function FLIGHTCONTROL:onbeforeStatusUpdate()
|
||||
self:T2(self.lid..string.format("Last radio sent %d>%d sec ago. Status update allowed", dT, self.dTmessage))
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
local Tqueue=self.msrsqueue:CalcTransmisstionDuration()
|
||||
|
||||
if Tqueue>0 then
|
||||
-- Debug info.
|
||||
local text=string.format("Still got %d messages in the radio queue. Will call status again in %.1f sec", #self.msrsqueue, Tqueue)
|
||||
self:I(self.lid..text)
|
||||
|
||||
-- Call status again in dt seconds.
|
||||
self:__StatusUpdate(-Tqueue)
|
||||
|
||||
-- Deny transition.
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
@ -3274,7 +3294,9 @@ function FLIGHTCONTROL:_PlayerAbortLanding(groupname)
|
||||
|
||||
if flight then
|
||||
|
||||
if flight:IsLanding() and self:IsControlling(flight) then
|
||||
local flightstatus=self:GetFlightStatus(flight)
|
||||
|
||||
if (flight:IsLanding() or flightstatus==FLIGHTCONTROL.FlightStatus.LANDING) and self:IsControlling(flight) then
|
||||
|
||||
-- Call sign.
|
||||
local callsign=self:_GetCallsignName(flight)
|
||||
@ -3358,8 +3380,11 @@ function FLIGHTCONTROL:_PlayerRequestDirectLanding(groupname)
|
||||
|
||||
else
|
||||
|
||||
-- Runway.
|
||||
local runway=self:GetActiveRunwayText()
|
||||
|
||||
-- Message text.
|
||||
local text=string.format("%s, affirmative! Confirm approach", callsign)
|
||||
local text=string.format("%s, affirmative, runway %s. Confirm approach!", callsign, runway)
|
||||
|
||||
-- Send message.
|
||||
self:TransmissionTower(text, flight, 10)
|
||||
@ -4025,12 +4050,15 @@ function FLIGHTCONTROL:_CheckFlights()
|
||||
local onRunway=self:IsCoordinateRunway(coord)
|
||||
|
||||
-- Debug output.
|
||||
self:I(self.lid..string.format("Player %s speed %.1f knots (max=%.1f) onRunway=%s", playerElement.playerName, UTILS.MpsToKnots(speed), UTILS.MpsToKnots(self.speedLimitTaxi), tostring(onRunway)))
|
||||
self:T(self.lid..string.format("Player %s speed %.1f knots (max=%.1f) onRunway=%s", playerElement.playerName, UTILS.MpsToKnots(speed), UTILS.MpsToKnots(self.speedLimitTaxi), tostring(onRunway)))
|
||||
|
||||
if speed and speed>self.speedLimitTaxi and not onRunway then
|
||||
|
||||
-- Callsign.
|
||||
local callsign=self:_GetCallsignName(flight)
|
||||
|
||||
-- Radio text.
|
||||
local text="Slow down, you are taxiing too fast!"
|
||||
local text=string.format("%s, slow down, you are taxiing too fast!", callsign)
|
||||
|
||||
-- Radio message to player.
|
||||
self:TransmissionTower(text, flight)
|
||||
@ -4228,17 +4256,19 @@ function FLIGHTCONTROL:TransmissionTower(Text, Flight, Delay)
|
||||
-- Spoken text.
|
||||
local text=self:_GetTextForSpeech(Text)
|
||||
|
||||
-- Tower radio call.
|
||||
self.msrsTower:PlayText(text, Delay)
|
||||
|
||||
-- "Subtitle".
|
||||
local subgroups=nil
|
||||
if Flight and not Flight.isAI then
|
||||
local playerData=Flight:_GetPlayerData()
|
||||
if playerData.subtitles then
|
||||
self:TextMessageToFlight(Text, Flight, 5, false, Delay)
|
||||
subgroups=subgroups or {}
|
||||
table.insert(subgroups, Flight.group)
|
||||
end
|
||||
end
|
||||
|
||||
-- New transmission.
|
||||
local transmission=self.msrsqueue:NewTransmission(text, nil, self.msrsTower, nil, 1, subgroups, Text)
|
||||
|
||||
-- Set time stamp. Can be in the future.
|
||||
self.Tlastmessage=timer.getAbsTime() + (Delay or 0)
|
||||
|
||||
@ -4263,22 +4293,28 @@ function FLIGHTCONTROL:TransmissionPilot(Text, Flight, Delay)
|
||||
-- Spoken text.
|
||||
local text=self:_GetTextForSpeech(Text)
|
||||
|
||||
-- MSRS instance to use.
|
||||
local msrs=self.msrsPilot
|
||||
|
||||
if Flight.useSRS and Flight.msrs then
|
||||
|
||||
-- Pilot radio call using settings of the FLIGHTGROUP. We just overwrite the frequency.
|
||||
Flight.msrs:PlayTextExt(text, Delay, self.frequency, self.modulation, Gender, Culture, Voice, Volume, Label)
|
||||
|
||||
else
|
||||
|
||||
-- Pilot radio call using the default settings.
|
||||
self.msrsPilot:PlayText(text, Delay)
|
||||
msrs=Flight.msrs
|
||||
|
||||
end
|
||||
|
||||
-- "Subtitle".
|
||||
local subgroups=nil
|
||||
if Flight and not Flight.isAI then
|
||||
self:TextMessageToFlight(Text, Flight, 5, false, Delay)
|
||||
local playerData=Flight:_GetPlayerData()
|
||||
if playerData.subtitles then
|
||||
subgroups=subgroups or {}
|
||||
table.insert(subgroups, Flight.group)
|
||||
end
|
||||
end
|
||||
|
||||
-- Add transmission to msrsqueue.
|
||||
self.msrsqueue:NewTransmission(text, nil, msrs, nil, 1, subgroups, Text, nil, self.frequency, self.modulation)
|
||||
|
||||
end
|
||||
|
||||
@ -4439,7 +4475,7 @@ end
|
||||
--- Get text for text-to-speech.
|
||||
-- Numbers are spaced out, e.g. "Heading 180" becomes "Heading 1 8 0 ".
|
||||
-- @param #FLIGHTCONTROL self
|
||||
-- @param #string text
|
||||
-- @param #string text Original text.
|
||||
-- @return #string Spoken text.
|
||||
function FLIGHTCONTROL:_GetTextForSpeech(text)
|
||||
|
||||
|
||||
@ -576,10 +576,11 @@ end
|
||||
-- @param Ops.OpsGroup#OPSGROUP.Element Element (Optional) Only check status for given element.
|
||||
-- @return #boolean If true, flight is parking after spawned.
|
||||
function FLIGHTGROUP:IsParking(Element)
|
||||
local is=self:Is("Parking")
|
||||
if Element then
|
||||
return Element.status==OPSGROUP.ElementStatus.PARKING
|
||||
is=Element.status==OPSGROUP.ElementStatus.PARKING
|
||||
end
|
||||
return self:Is("Parking")
|
||||
return is
|
||||
end
|
||||
|
||||
--- Check if is taxiing to the runway.
|
||||
@ -587,10 +588,11 @@ end
|
||||
-- @param Ops.OpsGroup#OPSGROUP.Element Element (Optional) Only check status for given element.
|
||||
-- @return #boolean If true, flight is taxiing after engine start up.
|
||||
function FLIGHTGROUP:IsTaxiing(Element)
|
||||
local is=self:Is("Taxiing")
|
||||
if Element then
|
||||
return Element.status==OPSGROUP.ElementStatus.TAXIING
|
||||
is=Element.status==OPSGROUP.ElementStatus.TAXIING
|
||||
end
|
||||
return self:Is("Taxiing")
|
||||
return is
|
||||
end
|
||||
|
||||
--- Check if flight is airborne or cruising.
|
||||
@ -598,17 +600,19 @@ end
|
||||
-- @param Ops.OpsGroup#OPSGROUP.Element Element (Optional) Only check status for given element.
|
||||
-- @return #boolean If true, flight is airborne.
|
||||
function FLIGHTGROUP:IsAirborne(Element)
|
||||
local is=self:Is("Airborne") or self:Is("Cruising")
|
||||
if Element then
|
||||
return Element.status==OPSGROUP.ElementStatus.AIRBORNE
|
||||
is=Element.status==OPSGROUP.ElementStatus.AIRBORNE
|
||||
end
|
||||
return self:Is("Airborne") or self:Is("Cruising")
|
||||
return is
|
||||
end
|
||||
|
||||
--- Check if flight is airborne or cruising.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #boolean If true, flight is airborne.
|
||||
function FLIGHTGROUP:IsCruising()
|
||||
return self:Is("Cruising")
|
||||
local is=self:Is("Cruising")
|
||||
return is
|
||||
end
|
||||
|
||||
--- Check if flight is landing.
|
||||
@ -616,10 +620,11 @@ end
|
||||
-- @param Ops.OpsGroup#OPSGROUP.Element Element (Optional) Only check status for given element.
|
||||
-- @return #boolean If true, flight is landing, i.e. on final approach.
|
||||
function FLIGHTGROUP:IsLanding(Element)
|
||||
local is=self:Is("Landing")
|
||||
if Element then
|
||||
return Element.status==OPSGROUP.ElementStatus.LANDING
|
||||
is=Element.status==OPSGROUP.ElementStatus.LANDING
|
||||
end
|
||||
return self:Is("Landing")
|
||||
return is
|
||||
end
|
||||
|
||||
--- Check if flight has landed and is now taxiing to its parking spot.
|
||||
@ -627,10 +632,11 @@ end
|
||||
-- @param Ops.OpsGroup#OPSGROUP.Element Element (Optional) Only check status for given element.
|
||||
-- @return #boolean If true, flight has landed
|
||||
function FLIGHTGROUP:IsLanded(Element)
|
||||
local is=self:Is("Landed")
|
||||
if Element then
|
||||
return Element.status==OPSGROUP.ElementStatus.LANDED
|
||||
is=Element.status==OPSGROUP.ElementStatus.LANDED
|
||||
end
|
||||
return self:Is("Landed")
|
||||
return is
|
||||
end
|
||||
|
||||
--- Check if flight has arrived at its destination parking spot.
|
||||
@ -638,45 +644,51 @@ end
|
||||
-- @param Ops.OpsGroup#OPSGROUP.Element Element (Optional) Only check status for given element.
|
||||
-- @return #boolean If true, flight has arrived at its destination and is parking.
|
||||
function FLIGHTGROUP:IsArrived(Element)
|
||||
local is=self:Is("Arrived")
|
||||
if Element then
|
||||
return Element.status==OPSGROUP.ElementStatus.ARRIVED
|
||||
is=Element.status==OPSGROUP.ElementStatus.ARRIVED
|
||||
end
|
||||
return self:Is("Arrived")
|
||||
return is
|
||||
end
|
||||
|
||||
--- Check if flight is inbound and traveling to holding pattern.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #boolean If true, flight is holding.
|
||||
function FLIGHTGROUP:IsInbound()
|
||||
return self:Is("Inbound")
|
||||
local is=self:Is("Inbound")
|
||||
return is
|
||||
end
|
||||
|
||||
--- Check if flight is holding and waiting for landing clearance.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #boolean If true, flight is holding.
|
||||
function FLIGHTGROUP:IsHolding()
|
||||
return self:Is("Holding")
|
||||
local is=self:Is("Holding")
|
||||
return is
|
||||
end
|
||||
|
||||
--- Check if flight is going for fuel.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #boolean If true, flight is refueling.
|
||||
function FLIGHTGROUP:IsGoing4Fuel()
|
||||
return self:Is("Going4Fuel")
|
||||
local is=self:Is("Going4Fuel")
|
||||
return is
|
||||
end
|
||||
|
||||
--- Check if helo(!) flight is ordered to land at a specific point.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #boolean If true, group has task to land somewhere.
|
||||
function FLIGHTGROUP:IsLandingAt()
|
||||
return self:Is("LandingAt")
|
||||
local is=self:Is("LandingAt")
|
||||
return is
|
||||
end
|
||||
|
||||
--- Check if helo(!) flight has landed at a specific point.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #boolean If true, has landed somewhere.
|
||||
function FLIGHTGROUP:IsLandedAt()
|
||||
return self:Is("LandedAt")
|
||||
is=self:Is("LandedAt")
|
||||
return is
|
||||
end
|
||||
|
||||
--- Check if flight is low on fuel.
|
||||
|
||||
@ -52,8 +52,6 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # The MSRS Concept
|
||||
--
|
||||
-- This class allows to broadcast sound files or text via Simple Radio Standalone (SRS).
|
||||
@ -143,7 +141,7 @@ MSRS = {
|
||||
|
||||
--- MSRS class version.
|
||||
-- @field #string version
|
||||
MSRS.version="0.0.6"
|
||||
MSRS.version="0.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -181,7 +179,7 @@ function MSRS:New(PathToSRS, Frequency, Modulation, Volume)
|
||||
self:SetCoalition()
|
||||
self:SetLabel()
|
||||
self:SetVolume()
|
||||
self.lid = string.format("%s-%s | ",self.name,self.version)
|
||||
self.lid = string.format("%s-%s | ", self.name, self.version)
|
||||
|
||||
if not io or not os then
|
||||
self:E(self.lid.."***** ERROR - io or os NOT desanitized! MSRS will not work!")
|
||||
@ -455,20 +453,9 @@ function MSRS:PlaySoundFile(Soundfile, Delay)
|
||||
-- Append file.
|
||||
command=command..' --file="'..tostring(soundfile)..'"'
|
||||
|
||||
-- Execute command.
|
||||
self:_ExecCommand(command)
|
||||
|
||||
--[[
|
||||
|
||||
command=command.." > bla.txt"
|
||||
|
||||
-- Debug output.
|
||||
self:I(string.format("MSRS PlaySoundfile command=%s", command))
|
||||
|
||||
-- Execute SRS command.
|
||||
local x=os.execute(command)
|
||||
|
||||
]]
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
@ -494,16 +481,6 @@ function MSRS:PlaySoundText(SoundText, Delay)
|
||||
-- Execute command.
|
||||
self:_ExecCommand(command)
|
||||
|
||||
--[[
|
||||
command=command.." > bla.txt"
|
||||
|
||||
-- Debug putput.
|
||||
self:I(string.format("MSRS PlaySoundfile command=%s", command))
|
||||
|
||||
-- Execute SRS command.
|
||||
local x=os.execute(command)
|
||||
]]
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
@ -538,6 +515,13 @@ end
|
||||
-- @param #MSRS self
|
||||
-- @param #string Text Text message.
|
||||
-- @param #number Delay Delay in seconds, before the message is played.
|
||||
-- @param #table Frequencies Radio frequencies.
|
||||
-- @param #table Modulations Radio modulations.
|
||||
-- @param #string Gender Gender.
|
||||
-- @param #string Culture Culture.
|
||||
-- @param #string Voice Voice.
|
||||
-- @param #number Volume Volume.
|
||||
-- @param #string Label Label.
|
||||
-- @return #MSRS self
|
||||
function MSRS:PlayTextExt(Text, Delay, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label)
|
||||
|
||||
@ -765,5 +749,354 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Manages radio transmissions.
|
||||
--
|
||||
-- The purpose of the MSRSQUEUE class is to manage SRS text-to-speech (TTS) messages using the MSRS class.
|
||||
-- This can be used to submit multiple TTS messages and the class takes care that they are transmitted one after the other (and not overlapping).
|
||||
--
|
||||
-- @type MSRSQUEUE
|
||||
-- @field #string ClassName Name of the class "MSRSQUEUE".
|
||||
-- @field #string lid ID for dcs.log.
|
||||
-- @field #table queue The queue of transmissions.
|
||||
-- @field #string alias Name of the radio queue.
|
||||
-- @field #number dt Time interval in seconds for checking the radio queue.
|
||||
-- @field #number Tlast Time (abs) when the last transmission finished.
|
||||
-- @field #boolean checking If `true`, the queue update function is scheduled to be called again.
|
||||
-- @extends Core.Base#BASE
|
||||
MSRSQUEUE = {
|
||||
ClassName = "MSRSQUEUE",
|
||||
Debugmode = nil,
|
||||
lid = nil,
|
||||
queue = {},
|
||||
alias = nil,
|
||||
dt = nil,
|
||||
Tlast = nil,
|
||||
checking = nil,
|
||||
}
|
||||
|
||||
--- Radio queue transmission data.
|
||||
-- @type MSRSQUEUE.Transmission
|
||||
-- @field #string text Text to be transmitted.
|
||||
-- @field Sound.SRS#MSRS msrs MOOSE SRS object.
|
||||
-- @field #number duration Duration in seconds.
|
||||
-- @field #table subgroups Groups to send subtitle to.
|
||||
-- @field #string subtitle Subtitle of the transmission.
|
||||
-- @field #number subduration Duration of the subtitle being displayed.
|
||||
-- @field #number frequency Frequency.
|
||||
-- @field #number modulation Modulation.
|
||||
-- @field #number Tstarted Mission time (abs) in seconds when the transmission started.
|
||||
-- @field #boolean isplaying If true, transmission is currently playing.
|
||||
-- @field #number Tplay Mission time (abs) in seconds when the transmission should be played.
|
||||
-- @field #number interval Interval in seconds before next transmission.
|
||||
|
||||
--- Create a new MSRSQUEUE object for a given radio frequency/modulation.
|
||||
-- @param #MSRSQUEUE self
|
||||
-- @param #string alias (Optional) Name of the radio queue.
|
||||
-- @return #MSRSQUEUE self The MSRSQUEUE object.
|
||||
function MSRSQUEUE:New(alias)
|
||||
|
||||
-- Inherit base
|
||||
local self=BASE:Inherit(self, BASE:New()) --#MSRSQUEUE
|
||||
|
||||
self.alias=alias or "My Radio"
|
||||
|
||||
self.dt=1.0
|
||||
|
||||
self.lid=string.format("MSRSQUEUE %s | ", self.alias)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Clear the radio queue.
|
||||
-- @param #MSRSQUEUE self
|
||||
-- @return #MSRSQUEUE self The MSRSQUEUE object.
|
||||
function MSRSQUEUE:Clear()
|
||||
self:I(self.lid.."Clearning MSRSQUEUE")
|
||||
self.queue={}
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Add a transmission to the radio queue.
|
||||
-- @param #MSRSQUEUE self
|
||||
-- @param #MSRSQUEUE.Transmission transmission The transmission data table.
|
||||
-- @return #MSRSQUEUE self
|
||||
function MSRSQUEUE:AddTransmission(transmission)
|
||||
|
||||
-- Init.
|
||||
transmission.isplaying=false
|
||||
transmission.Tstarted=nil
|
||||
|
||||
-- Add to queue.
|
||||
table.insert(self.queue, transmission)
|
||||
|
||||
-- Start checking.
|
||||
if not self.checking then
|
||||
self:_CheckRadioQueue()
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new transmission and add it to the radio queue.
|
||||
-- @param #MSRSQUEUE self
|
||||
-- @param #string text Text to play.
|
||||
-- @param #number duration Duration in seconds the file lasts. Default is determined by number of characters of the text message.
|
||||
-- @param Sound.SRS#MSRS msrs MOOSE SRS object.
|
||||
-- @param #number tstart Start time (abs) seconds. Default now.
|
||||
-- @param #number interval Interval in seconds after the last transmission finished.
|
||||
-- @param #table subgroups Groups that should receive the subtiltle.
|
||||
-- @param #string subtitle Subtitle displayed when the message is played.
|
||||
-- @param #number subduration Duration [sec] of the subtitle being displayed. Default 5 sec.
|
||||
-- @param #number frequency Radio frequency if other than MSRS default.
|
||||
-- @param #number modulation Radio modulation if other then MSRS default.
|
||||
-- @return #MSRSQUEUE.Transmission Radio transmission table.
|
||||
function MSRSQUEUE:NewTransmission(text, duration, msrs, tstart, interval, subgroups, subtitle, subduration, frequency, modulation)
|
||||
|
||||
-- Sanity checks.
|
||||
if not text then
|
||||
self:E(self.lid.."ERROR: No text specified.")
|
||||
return nil
|
||||
end
|
||||
if type(text)~="string" then
|
||||
self:E(self.lid.."ERROR: Text specified is NOT a string.")
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
-- Create a new transmission object.
|
||||
local transmission={} --#MSRSQUEUE.Transmission
|
||||
transmission.text=text
|
||||
transmission.duration=duration or STTS.getSpeechTime(text)
|
||||
transmission.msrs=msrs
|
||||
transmission.Tplay=tstart or timer.getAbsTime()
|
||||
transmission.subtitle=subtitle
|
||||
transmission.interval=interval or 0
|
||||
transmission.frequency=frequency
|
||||
transmission.modulation=modulation
|
||||
transmission.subgroups=subgroups
|
||||
if transmission.subtitle then
|
||||
transmission.subduration=subduration or transmission.duration
|
||||
else
|
||||
transmission.subduration=0 --nil
|
||||
end
|
||||
|
||||
-- Add transmission to queue.
|
||||
self:AddTransmission(transmission)
|
||||
|
||||
return transmission
|
||||
end
|
||||
|
||||
--- Broadcast radio message.
|
||||
-- @param #MSRSQUEUE self
|
||||
-- @param #MSRSQUEUE.Transmission transmission The transmission.
|
||||
function MSRSQUEUE:Broadcast(transmission)
|
||||
|
||||
if transmission.frequency then
|
||||
transmission.msrs:PlayTextExt(transmission.text, nil, transmission.frequency, transmission.modulation, Gender, Culture, Voice, Volume, Label)
|
||||
else
|
||||
transmission.msrs:PlayText(transmission.text)
|
||||
end
|
||||
|
||||
local function texttogroup(gid)
|
||||
-- Text to group.
|
||||
trigger.action.outTextForGroup(gid, transmission.subtitle, transmission.subduration, true)
|
||||
end
|
||||
|
||||
if transmission.subgroups and #transmission.subgroups>0 then
|
||||
|
||||
for _,_group in pairs(transmission.subgroups) do
|
||||
local group=_group --Wrapper.Group#GROUP
|
||||
|
||||
if group and group:IsAlive() then
|
||||
local gid=group:GetID()
|
||||
|
||||
self:ScheduleOnce(4, texttogroup, gid)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Calculate total transmission duration of all transmission in the queue.
|
||||
-- @param #MSRSQUEUE self
|
||||
-- @return #number Total transmission duration.
|
||||
function MSRSQUEUE:CalcTransmisstionDuration()
|
||||
|
||||
local Tnow=timer.getAbsTime()
|
||||
|
||||
local T=0
|
||||
for _,_transmission in pairs(self.queue) do
|
||||
local transmission=_transmission --#MSRSQUEUE.Transmission
|
||||
|
||||
if transmission.isplaying then
|
||||
|
||||
-- Playing for dt seconds.
|
||||
local dt=Tnow-transmission.Tstarted
|
||||
|
||||
T=T+transmission.duration-dt
|
||||
|
||||
else
|
||||
T=T+transmission.duration
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return T
|
||||
end
|
||||
|
||||
--- Check radio queue for transmissions to be broadcasted.
|
||||
-- @param #MSRSQUEUE self
|
||||
-- @param #number delay Delay in seconds before checking.
|
||||
function MSRSQUEUE:_CheckRadioQueue(delay)
|
||||
|
||||
-- Transmissions in queue.
|
||||
local N=#self.queue
|
||||
|
||||
-- Debug info.
|
||||
self:T2(self.lid..string.format("Check radio queue %s: delay=%.3f sec, N=%d, checking=%s", self.alias, delay or 0, N, tostring(self.checking)))
|
||||
|
||||
if delay and delay>0 then
|
||||
|
||||
-- Delayed call.
|
||||
self:ScheduleOnce(delay, MSRSQUEUE._CheckRadioQueue, self)
|
||||
|
||||
-- Checking on.
|
||||
self.checking=true
|
||||
|
||||
else
|
||||
|
||||
-- Check if queue is empty.
|
||||
if N==0 then
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Check radio queue %s empty ==> disable checking", self.alias))
|
||||
|
||||
-- Queue is now empty. Nothing to else to do. We start checking again, if a transmission is added.
|
||||
self.checking=false
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- Get current abs time.
|
||||
local time=timer.getAbsTime()
|
||||
|
||||
-- Checking on.
|
||||
self.checking=true
|
||||
|
||||
-- Set dt.
|
||||
local dt=self.dt
|
||||
|
||||
|
||||
local playing=false
|
||||
local next=nil --#MSRSQUEUE.Transmission
|
||||
local remove=nil
|
||||
for i,_transmission in ipairs(self.queue) do
|
||||
local transmission=_transmission --#MSRSQUEUE.Transmission
|
||||
|
||||
-- Check if transmission time has passed.
|
||||
if time>=transmission.Tplay then
|
||||
|
||||
-- Check if transmission is currently playing.
|
||||
if transmission.isplaying then
|
||||
|
||||
-- Check if transmission is finished.
|
||||
if time>=transmission.Tstarted+transmission.duration then
|
||||
|
||||
-- Transmission over.
|
||||
transmission.isplaying=false
|
||||
|
||||
-- Remove ith element in queue.
|
||||
remove=i
|
||||
|
||||
-- Store time last transmission finished.
|
||||
self.Tlast=time
|
||||
|
||||
else -- still playing
|
||||
|
||||
-- Transmission is still playing.
|
||||
playing=true
|
||||
|
||||
dt=transmission.duration-(time-transmission.Tstarted)
|
||||
|
||||
end
|
||||
|
||||
else -- not playing yet
|
||||
|
||||
local Tlast=self.Tlast
|
||||
|
||||
if transmission.interval==nil then
|
||||
|
||||
-- Not playing ==> this will be next.
|
||||
if next==nil then
|
||||
next=transmission
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
if Tlast==nil or time-Tlast>=transmission.interval then
|
||||
next=transmission
|
||||
else
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- We got a transmission or one with an interval that is not due yet. No need for anything else.
|
||||
if next or Tlast then
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
-- Transmission not due yet.
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- Found a new transmission.
|
||||
if next~=nil and not playing then
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Broadcasting text=\"%s\" at T=%.3f", next.text, time))
|
||||
|
||||
-- Call SRS.
|
||||
self:Broadcast(next)
|
||||
|
||||
next.isplaying=true
|
||||
next.Tstarted=time
|
||||
dt=next.duration
|
||||
end
|
||||
|
||||
-- Remove completed call from queue.
|
||||
if remove then
|
||||
-- Remove from queue.
|
||||
table.remove(self.queue, remove)
|
||||
N=N-1
|
||||
|
||||
-- Check if queue is empty.
|
||||
if #self.queue==0 then
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Check radio queue %s empty ==> disable checking", self.alias))
|
||||
|
||||
self.checking=false
|
||||
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Check queue.
|
||||
self:_CheckRadioQueue(dt)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
@ -20,11 +20,11 @@ do
|
||||
-- @type FIFO
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @field #string version Version of FiFo
|
||||
-- @field #number counter
|
||||
-- @field #number pointer
|
||||
-- @field #table stackbypointer
|
||||
-- @field #table stackbyid
|
||||
-- @field #string version Version of FiFo.
|
||||
-- @field #number counter Counter.
|
||||
-- @field #number pointer Pointer.
|
||||
-- @field #table stackbypointer Stack by pointer.
|
||||
-- @field #table stackbyid Stack by ID.
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
---
|
||||
@ -45,12 +45,12 @@ FIFO = {
|
||||
stackbyid = {}
|
||||
}
|
||||
|
||||
--- Instantiate a new FIFO Stack
|
||||
--- Instantiate a new FIFO Stack.
|
||||
-- @param #FIFO self
|
||||
-- @return #FIFO self
|
||||
function FIFO:New()
|
||||
-- Inherit everything from BASE class.
|
||||
local self=BASE:Inherit(self, BASE:New())
|
||||
local self=BASE:Inherit(self, BASE:New()) --#FIFO
|
||||
self.pointer = 0
|
||||
self.counter = 0
|
||||
self.stackbypointer = {}
|
||||
@ -62,7 +62,7 @@ function FIFO:New()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Empty FIFO Stack
|
||||
--- Empty FIFO Stack.
|
||||
-- @param #FIFO self
|
||||
-- @return #FIFO self
|
||||
function FIFO:Clear()
|
||||
@ -77,7 +77,7 @@ function FIFO:Clear()
|
||||
return self
|
||||
end
|
||||
|
||||
--- FIFO Push Object to Stack
|
||||
--- FIFO Push Object to Stack.
|
||||
-- @param #FIFO self
|
||||
-- @param #table Object
|
||||
-- @param #string UniqueID (optional) - will default to current pointer + 1. Note - if you intend to use `FIFO:GetIDStackSorted()` keep the UniqueID numerical!
|
||||
@ -97,7 +97,7 @@ function FIFO:Push(Object,UniqueID)
|
||||
return self
|
||||
end
|
||||
|
||||
--- FIFO Pull Object from Stack
|
||||
--- FIFO Pull Object from Stack.
|
||||
-- @param #FIFO self
|
||||
-- @return #table Object or nil if stack is empty
|
||||
function FIFO:Pull()
|
||||
|
||||
@ -154,7 +154,7 @@ function STTS.getSpeechTime(length,speed,isGoogle)
|
||||
length = string.len(length)
|
||||
end
|
||||
|
||||
return math.ceil(length/cps)
|
||||
return length/cps --math.ceil(length/cps)
|
||||
end
|
||||
|
||||
--- Text to speech function.
|
||||
|
||||
@ -1081,12 +1081,10 @@ function AIRBASE:_InitParkingSpots()
|
||||
-- Get client coordinates.
|
||||
local function isClient(coord)
|
||||
local clients=_DATABASE.CLIENTS
|
||||
for clientname, client in pairs(clients) do
|
||||
local template=_DATABASE:GetGroupTemplateFromUnitName(clientname)
|
||||
local units=template.units
|
||||
for i,unit in pairs(units) do
|
||||
local Coord=COORDINATE:New(unit.x, unit.alt, unit.y)
|
||||
local dist=Coord:Get2DDistance(coord)
|
||||
for clientname, _client in pairs(clients) do
|
||||
local client=_client --Wrapper.Client#CLIENT
|
||||
if client and client.SpawnCoord then
|
||||
local dist=client.SpawnCoord:Get2DDistance(coord)
|
||||
if dist<2 then
|
||||
return true, clientname
|
||||
end
|
||||
@ -1743,16 +1741,6 @@ function AIRBASE:_InitRunways(IncludeInverse)
|
||||
return ((b.z - a.z)*(c.x - a.x) - (b.x - a.x)*(c.z - a.z)) > 0
|
||||
end
|
||||
|
||||
--[[
|
||||
local a={x=1, y=0, z=0}
|
||||
local A={x=0, y=0, z=0}
|
||||
local b={x=0, y=0, z=1}
|
||||
local c={x=0, y=0, z=-1}
|
||||
local bl=isLeft(A, a, b)
|
||||
local cl=isLeft(A, a, c)
|
||||
env.info(string.format("b left=%s, c left=%s", tostring(bl), tostring(cl)))
|
||||
]]
|
||||
|
||||
for i,j in pairs(rpairs) do
|
||||
local ri=Runways[i] --#AIRBASE.Runway
|
||||
local rj=Runways[j] --#AIRBASE.Runway
|
||||
@ -1769,13 +1757,6 @@ function AIRBASE:_InitRunways(IncludeInverse)
|
||||
local b=UTILS.VecSubstract(rj.center, ri.center)
|
||||
b=UTILS.VecAdd(ri.center, b)
|
||||
|
||||
--[[
|
||||
local ca=COORDINATE:NewFromVec3(a)
|
||||
local cb=COORDINATE:NewFromVec3(b)
|
||||
c0:ArrowToAll(ca, nil , {0,1,0})
|
||||
c0:ArrowToAll(cb, nil , {0,0,1})
|
||||
]]
|
||||
|
||||
-- Check if rj is left of ri.
|
||||
local left=isLeft(c0, a, b)
|
||||
|
||||
@ -1992,7 +1973,7 @@ function AIRBASE:SetActiveRunwayLanding(Name, PreferLeft)
|
||||
end
|
||||
|
||||
if runway then
|
||||
self:I("Setting active runway for landing as "..self:GetRunwayName(runway))
|
||||
self:I(string.format("%s: Setting active runway for landing as %s", self.AirbaseName, self:GetRunwayName(runway)))
|
||||
else
|
||||
self:E("ERROR: Could not set the runway for landing!")
|
||||
end
|
||||
@ -2040,7 +2021,7 @@ function AIRBASE:SetActiveRunwayTakeoff(Name, PreferLeft)
|
||||
end
|
||||
|
||||
if runway then
|
||||
self:I("Setting active runway for takeoff as "..self:GetRunwayName(runway))
|
||||
self:I(string.format("%s: Setting active runway for takeoff as %s", self.AirbaseName, self:GetRunwayName(runway)))
|
||||
else
|
||||
self:E("ERROR: Could not set the runway for takeoff!")
|
||||
end
|
||||
|
||||
@ -13,6 +13,17 @@
|
||||
|
||||
--- The CLIENT class
|
||||
-- @type CLIENT
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #string ClientName Name of the client.
|
||||
-- @field #string ClientBriefing Briefing.
|
||||
-- @field #function ClientCallBack Callback function.
|
||||
-- @field #table ClientParameters Parameters of the callback function.
|
||||
-- @field #number ClientGroupID Group ID of the client.
|
||||
-- @field #string ClientGroupName Group name.
|
||||
-- @field #boolean ClientAlive Client alive.
|
||||
-- @field #boolean ClientAlive2 Client alive 2.
|
||||
-- @field #table Players Player table.
|
||||
-- @field Core.Point#COORDINATE SpawnCoord Spawn coordinate from the template.
|
||||
-- @extends Wrapper.Unit#UNIT
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user