#SRS - fix for Hound Backend if only one frequency is set

#CSAR - Added localization options, added some SRS options (backend, provider)
This commit is contained in:
Applevangelist
2026-02-26 15:44:14 +01:00
parent a949b7ae8c
commit 486dc6d218
2 changed files with 270 additions and 47 deletions
+253 -39
View File
@@ -31,7 +31,7 @@
-- @image OPS_CSAR.jpg
---
-- Last Update Jan 2026
-- Last Update Feb 2026
-------------------------------------------------------------------------
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
@@ -137,7 +137,10 @@
-- mycsar.SRSport = 5002 -- and SRS Server port
-- mycsar.SRSCulture = "en-GB" -- SRS voice culture
-- mycsar.SRSVoice = nil -- SRS voice for downed pilot, relevant for Google TTS
-- mycsar.SRSGPathToCredentials = nil -- Path to your Google credentials json file, set this if you want to use Google TTS
-- mycsar.SRSGPathToCredentials = nil -- Path to your Google credentials json file, set this if you want to use Google TTS as provider
-- mycsar.SRSBackend = MSRS.Backend.SRSEXE -- default backend is windows
-- mycsar.SRSProvider = MSRS.Provider.WINDOWS -- default TTS provider is windows
-- mycsar.SRSSpeed = 1.0 -- default speech speed - does not work with all providers
-- mycsar.SRSVolume = 1 -- Volume, between 0 and 1
-- mycsar.SRSGender = "male" -- male or female voice
-- mycsar.CSARVoice = MSRS.Voices.Google.Standard.en_US_Standard_A -- SRS voice for CSAR Controller, relevant for Google TTS
@@ -231,6 +234,57 @@
-- **Caveat:**
-- Dropped troop noMessage and forcedesc parameters aren't saved.
--
-- ## 6. Message localization
--
-- Use the following option to use one of the build-in translations,"en" is the default one:
--
-- mycsar.locale = "fr" -- available are "en", "de" and "fr" (English, German, French)
--
-- To add your own text, you can do this by adding your locale and translations for these texts before calling `CSAR:New()`:
-- (NOTE - the lua placeholders like %s, %d must remain the same in type and number!)
--
-- CSAR.Messages.EN = {
-- HEARYOULONG = "%s: %s. I hear you! Finally, that is music in my ears!\nI'll pop a smoke when you are %s away.\nLand or hover by the smoke.",
-- HEARYOUSHORT = "%s: %s. I hear you! Finally, that is music in my ears!\nRequest a flare or smoke if you need.",
-- WEARECRAMMED = "%s, %s. We\'re already crammed with %d guys! Sorry!",
-- IAMINHELO = "%s: %s I\'m in! Get to the MASH ASAP! ",
-- YOUARECLOSE = "%s: %s. You\'re close now! Land or hover at the smoke.",
-- YOUARECLOSELONG = "%s: %s. You\'re close now! Land in a safe place, I will go there ",
-- WAITMORE = "Wait till %s gets in. \nETA %d more seconds.",
-- OPENTHEDOORIN = "Open the door to let me in!",
-- HOVERABOVE = "Hovering above %s. \n\nHold hover for %d seconds to winch them up. \n\nIf the countdown stops you\'re too far away!",
-- TOOHIGHWINCH = "Too high to winch %s \nReduce height and hover for 10 seconds!",
-- OPENTHEDOOROUT = "Open the door to let me out!",
-- TAKECLINIC = "%s: The %d pilot(s) have been taken to the\nmedical clinic. Good job!",
-- KILOMETERS = " kilometer",
-- NAUTMILES = " nautical miles",
-- FIRINGFLARE = "%s - Firing signal flare at your %s o\'clock. Distance %s",
-- NOPILOTSINRANGE = "No Pilots within %s",
-- IRSTROBE = "%s - IR Strobe active at your %s o\'clock. Distance %s",
-- POPPINGSMOKE = "%s - Popping smoke at your %s o\'clock. Distance %s",
-- POPPINGSMOKEMASH = "%s - Popping smoke at the closest rescue point: %s",
-- NORESCUEPOINTWITHIN = "No rescue point within %s",
-- NOPILOTSONBOARD = "No Rescued Pilots onboard",
-- MENUTOP = "CSAR",
-- MENUACTIVE = "List Active CSAR",
-- MENUCHECK = "Check Onboard",
-- MENUFLARE = "Request Signal Flare",
-- MENUSMOKE = "Request Smoke",
-- MENUSTROBE = "Request IR Strobe",
-- MENUMASH = "Smoke Closest MASH",
-- BOARDED = "Onboard - RTB to FARP/Airfield or MASH: ",
-- },
--
-- e.g. for Spanish:
--
-- CSAR.Messages.ES = {
-- HEARYOULONG = "%s: %s. ¡Te escucho! ¡Por fin, eso es música para mis oídos!\nLanzaré una señal de humo cuando estés a %s de distancia.\nAterrice o quédese en vuelo estacionario junto al humo.",
-- HEARYOUSHORT = "%s: %s. ¡Te escucho! ¡Por fin, eso es música para mis oídos!\nSolicite una bengala o humo si lo necesita.",
-- WEARECRAMMED = "%s, %s. ¡Ya estamos abarrotados con %d personas! ¡Lo siento!",
-- IAMINHELO = "%s: %s ¡Estoy dentro! ¡Dirígete al MASH lo antes posible!",
-- ...
-- }
--
-- @field #CSAR
CSAR = {
ClassName = "CSAR",
@@ -275,6 +329,105 @@ CSAR = {
IRStrobeRuntime = 300,
FARPRescueDistance = 500,
EnableMenuSmokeMASH = true,
locale = "en",
}
---
-- @field Messages
CSAR.Messages = {
EN = {
HEARYOULONG = "%s: %s. I hear you! Finally, that is music in my ears!\nI'll pop a smoke when you are %s away.\nLand or hover by the smoke.",
HEARYOUSHORT = "%s: %s. I hear you! Finally, that is music in my ears!\nRequest a flare or smoke if you need.",
WEARECRAMMED = "%s, %s. We\'re already crammed with %d guys! Sorry!",
IAMINHELO = "%s: %s I\'m in! Get to the MASH ASAP! ",
YOUARECLOSE = "%s: %s. You\'re close now! Land or hover at the smoke.",
YOUARECLOSELONG = "%s: %s. You\'re close now! Land in a safe place, I will go there ",
WAITMORE = "Wait till %s gets in. \nETA %d more seconds.",
OPENTHEDOORIN = "Open the door to let me in!",
HOVERABOVE = "Hovering above %s. \n\nHold hover for %d seconds to winch them up. \n\nIf the countdown stops you\'re too far away!",
TOOHIGHWINCH = "Too high to winch %s \nReduce height and hover for 10 seconds!",
OPENTHEDOOROUT = "Open the door to let me out!",
TAKECLINIC = "%s: The %d pilot(s) have been taken to the\nmedical clinic. Good job!",
KILOMETERS = " kilometer",
NAUTMILES = " nautical miles",
FIRINGFLARE = "%s - Firing signal flare at your %s o\'clock. Distance %s",
NOPILOTSINRANGE = "No Pilots within %s",
IRSTROBE = "%s - IR Strobe active at your %s o\'clock. Distance %s",
POPPINGSMOKE = "%s - Popping smoke at your %s o\'clock. Distance %s",
POPPINGSMOKEMASH = "%s - Popping smoke at the closest rescue point: %s",
NORESCUEPOINTWITHIN = "No rescue point within %s",
NOPILOTSONBOARD = "No Rescued Pilots onboard",
MENUTOP = "CSAR",
MENUACTIVE = "List Active CSAR",
MENUCHECK = "Check Onboard",
MENUFLARE = "Request Signal Flare",
MENUSMOKE = "Request Smoke",
MENUSTROBE = "Request IR Strobe",
MENUMASH = "Smoke Closest MASH",
BOARDED = "Onboard - RTB to FARP/Airfield or MASH: ",
},
DE = {
HEARYOULONG = "%s: %s. Ich höre Sie! Endlich, das ist Musik in meinen Ohren!\nIch zünde eine Rauchgranate, wenn Sie %s entfernt sind.\nLanden Sie oder hovern Sie beim Rauch.",
HEARYOUSHORT = "%s: %s. Ich höre Sie! Endlich, das ist Musik in meinen Ohren!\nFordern Sie eine Leuchtrakete oder Rauch an, falls nötig.",
IAMINHELO = "%s: %s Ich bin drin! Jetzt sofort zum Lazarett! ",
YOUARECLOSE = "%s: %s. Sie sind jetzt nah dran! Landen Sie oder hovern Sie beim Rauch.",
YOUARECLOSELONG = "%s: %s. Sie sind jetzt nah dran! Landen Sie an einem sicheren Ort, ich komme dorthin.",
WAITMORE = "Warten Sie, bis %s eingestiegen ist. \nNoch %d Sekunden.",
OPENTHEDOORIN = "Öffnen Sie die Tür, damit ich einsteigen kann!",
HOVERABOVE = "Hovere über %s. \n\nPositon für %d Sekunden halten, um zu winschen. \n\nWenn der Countdown stoppt, sind Sie zu weit entfernt!",
TOOHIGHWINCH = "Zu hoch, um %s zu winschen. \nHöhe reduzieren und %d Sekunden halten!",
OPENTHEDOOROUT = "Öffnen Sie die Tür, damit ich aussteigen kann!",
FIRINGFLARE = "%s - Feuere Signalrakete auf Ihrer %s-Uhr-Position ab. Entfernung %s",
NOPILOTSINRANGE = "Keine Piloten in %s Reichweite",
IRSTROBE = "%s - IR-Blinklicht aktiv auf Ihrer %s-Uhr-Position. Entfernung %s",
POPPINGSMOKE = "%s - Zünde Rauchgranate auf Ihrer %s-Uhr-Position. Entfernung %s",
POPPINGSMOKEMASH = "%s - Zünde Rauchgranate am nächsten Rettungspunkt: %s",
NORESCUEPOINTWITHIN = "Kein Rettungspunkt innerhalb von %s",
NOPILOTSONBOARD = "Keine geretteten Piloten an Bord",
MENUTOP = "CSAR",
MENUACTIVE = "Aktive CSAR",
MENUCHECK = "Ladung prüfen",
MENUFLARE = "Signalrakete anfordern",
MENUSMOKE = "Rauch anfordern",
MENUSTROBE = "IR-Blinklicht anfordern",
MENUMASH = "Nächstes MASH markieren",
WEARECRAMMED = "%s, %s. Wir sind bereits voll mit %d Mann! Tut mir leid!",
TAKECLINIC = "%s: Die %d Pilot(en) wurden ins\nLazarett gebracht. Gute Arbeit!",
KILOMETERS = " Kilometer",
NAUTMILES = " Meilen",
BOARDED = "An Bord - RTB zu FARP/Flugplatz oder Lazarett: ",
},
FR = {
HEARYOULONG = "%s: %s. Je vous entends! Enfin, c'est de la musique dans mes oreilles!\nJe lancerai une fumée quand vous serez à %s.\nAtterrissez ou survolez la fumée.",
HEARYOUSHORT = "%s: %s. Je vous entends! Enfin, c'est de la musique dans mes oreilles!\nDemandez une fusée éclairante ou de la fumée si nécessaire.",
IAMINHELO = "%s: %s Je suis à bord! Direction le MASH immédiatement! ",
YOUARECLOSE = "%s: %s. Vous êtes proche maintenant! Atterrissez ou survolez la fumée.",
YOUARECLOSELONG = "%s: %s. Vous êtes proche maintenant! Atterrissez dans un endroit sûr, j'y vais.",
WAITMORE = "Attendez que %s monte à bord. \nEncore %d secondes.",
OPENTHEDOORIN = "Ouvrez la porte pour me laisser entrer!",
HOVERABOVE = "En vol stationnaire au-dessus de %s. \n\nMaintenir la position pendant %d secondes pour hélitreuiller. \n\nSi le compte à rebours s'arrête, vous êtes trop loin!",
TOOHIGHWINCH = "Trop haut pour hélitreuiller %s. \nRéduisez l'altitude et maintenez la position pendant %d secondes!",
OPENTHEDOOROUT = "Ouvrez la porte pour me laisser sortir!",
FIRINGFLARE = "%s - Tir d'une fusée éclairante à vos %s heures. Distance %s",
NOPILOTSINRANGE = "Aucun pilote dans un rayon de %s",
IRSTROBE = "%s - Stroboscope IR actif à vos %s heures. Distance %s",
POPPINGSMOKE = "%s - Lancement de fumée à vos %s heures. Distance %s",
POPPINGSMOKEMASH = "%s - Lancement de fumée au point de sauvetage le plus proche: %s",
NORESCUEPOINTWITHIN = "Aucun point de sauvetage dans un rayon de %s",
NOPILOTSONBOARD = "Aucun pilote secouru à bord",
MENUTOP = "CSAR",
MENUACTIVE = "Lister les CSAR actifs",
MENUCHECK = "Vérifier qui est à bord",
MENUFLARE = "Demander une fusée éclairante",
MENUSMOKE = "Demander un fumigène",
MENUSTROBE = "Demander un stroboscope IR",
MENUMASH = "Fumée au MASH le plus proche",
WEARECRAMMED = "%s, %s. Nous sommes déjà pleins avec %d hommes! Désolé!",
TAKECLINIC = "%s: Les %d pilote(s) ont été transportés à \n l'hôpital. Bon travail!",
KILOMETERS = " kilomètres",
NAUTMILES = " milles nautiques",
BOARDED = "À bord - RTB vers FARP/Aérodrome ou MASH: ",
},
}
--- Downed pilots info.
@@ -320,7 +473,7 @@ CSAR.AircraftType["MH-6J"] = 2
--- CSAR class version.
-- @field #string version
CSAR.version="1.0.36"
CSAR.version="1.1.37"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
@@ -329,6 +482,7 @@ CSAR.version="1.0.36"
-- DONE: SRS Integration (to be tested)
-- TODO: Maybe - add option to smoke/flare closest MASH
-- DONE: shagrat Add cargoWeight to helicopter when pilot boarded
-- DONE: Localization
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -499,7 +653,11 @@ function CSAR:New(Coalition, Template, Alias)
self.SRSGender = "male" -- male or female
self.CSARVoice = MSRS.Voices.Google.Standard.en_US_Standard_A
self.CSARVoiceMS = MSRS.Voices.Microsoft.Hedda
self.SRSBackend = MSRS.Backend.SRSEXE
self.SRSProvider = MSRS.Provider.WINDOWS
self.SRSSpeed = 1.0
self.coordinate = nil -- Core.Point#COORDINATE
self.locale = "en"
local AliaS = string.gsub(self.alias," ","_")
self.filename = string.format("CSAR_%s_Persist.csv",AliaS)
@@ -649,6 +807,23 @@ end
--- Helper Functions ---
------------------------
--- [Internal] Init localization
-- @param #CSAR self
-- @return #CSAR self
function CSAR:_InitLocalization()
self:T(self.lid.."_InitLocalization")
self.gettext = TEXTANDSOUND:New("CSAR","en") -- Core.TextAndSound#TEXTANDSOUND
for locale,table in pairs(self.Messages) do
local Locale = string.lower(tostring(locale))
self:T("**** Adding locale: "..Locale)
for ID,Text in pairs(table) do
self:T(string.format('Adding ID %s',tostring(ID)))
self.gettext:AddEntry(Locale,tostring(ID),Text)
end
end
return self
end
--- (Internal) Function to insert downed pilot tracker object.
-- @param #CSAR self
-- @param Wrapper.Group#GROUP Group The #GROUP object
@@ -1459,9 +1634,11 @@ function CSAR:_CheckWoundedGroupStatus(heliname,woundedgroupname)
local dist = UTILS.MetersToNM(self.autosmokedistance)
disttext = string.format("%.0fnm",dist)
end
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nI'll pop a smoke when you are %s away.\nLand or hover by the smoke.", self:_GetCustomCallSign(_heliName), _pilotName, disttext), self.messageTime,false,true)
local text = self.gettext:GetEntry("HEARYOULONG",self.locale)
self:_DisplayMessageToSAR(_heliUnit, string.format(text, self:_GetCustomCallSign(_heliName), _pilotName, disttext), self.messageTime,false,true)
else
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nRequest a flare or smoke if you need.", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
local text = self.gettext:GetEntry("HEARYOUSHORT",self.locale)
self:_DisplayMessageToSAR(_heliUnit, string.format(text, self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
end
--mark as shown for THIS heli and THIS group
self.heliVisibleMessage[_lookupKeyHeli] = true
@@ -1525,7 +1702,8 @@ function CSAR:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupNam
_maxUnits = self.max_units
end
if _unitsInHelicopter + 1 > _maxUnits then
self:_DisplayMessageToSAR(_heliUnit, string.format("%s, %s. We\'re already crammed with %d guys! Sorry!", _pilotName, self:_GetCustomCallSign(_heliName), _unitsInHelicopter, _unitsInHelicopter), self.messageTime,false,false,true)
local text = self.gettext:GetEntry("WEARECRAMMED",self.locale)
self:_DisplayMessageToSAR(_heliUnit, string.format(text, _pilotName, self:_GetCustomCallSign(_heliName), _unitsInHelicopter, _unitsInHelicopter), self.messageTime,false,false,true)
return self
end
@@ -1542,8 +1720,9 @@ function CSAR:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupNam
_woundedGroup:Destroy(false)
self:_RemoveNameFromDownedPilots(_woundedGroupName,true)
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s I\'m in! Get to the MASH ASAP! ", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,true,true)
local text = self.gettext:GetEntry("IAMINHELO",self.locale)
self:_DisplayMessageToSAR(_heliUnit, string.format(text, self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,true,true)
self:_UpdateUnitCargoMass(_heliName)
@@ -1613,9 +1792,11 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
self:T(self.lid .. "[Pickup Debug] Helo closer than 500m: ".._lookupKeyHeli)
if self.heliCloseMessage[_lookupKeyHeli] == nil then
if self.autosmoke == true then
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land or hover at the smoke.", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
local text = self.gettext:GetEntry("YOUARECLOSE",self.locale)
self:_DisplayMessageToSAR(_heliUnit, string.format(text, self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
else
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land in a safe place, I will go there ", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
local text = self.gettext:GetEntry("YOUARECLOSELONG",self.locale)
self:_DisplayMessageToSAR(_heliUnit, string.format(text, self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
end
self.heliCloseMessage[_lookupKeyHeli] = true
end
@@ -1633,7 +1814,9 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
_time = self.landedStatus[_lookupKeyHeli]
_woundedGroup:OptionAlarmStateGreen()
self:_OrderGroupToMoveToPoint(_woundedGroup, _heliUnit:GetCoordinate())
self:_DisplayMessageToSAR(_heliUnit, "Wait till " .. _pilotName .. " gets in. \nETA " .. _time .. " more seconds.", self.messageTime, false)
local text = self.gettext:GetEntry("WAITMORE",self.locale)
text = string.format(text,_pilotName, _time)
self:_DisplayMessageToSAR(_heliUnit, text, self.messageTime, false)
else
_time = self.landedStatus[_lookupKeyHeli] - 10
self.landedStatus[_lookupKeyHeli] = _time
@@ -1643,7 +1826,8 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
if _distance < self.loadDistance + 5 or _distance <= 13 then
self:T(self.lid .. "[Pickup Debug] Pilot close enough - YES ".._lookupKeyHeli)
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
local text = self.gettext:GetEntry("OPENTHEDOORIN",self.locale)
self:_DisplayMessageToSAR(_heliUnit, text, self.messageTime, true, true)
self:T(self.lid .. "[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli)
return false
else
@@ -1660,7 +1844,8 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
self:T(self.lid .. "[Pickup Debug] Helo close enough, door check ".._lookupKeyHeli)
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
self:T(self.lid .. "[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli)
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
local text = self.gettext:GetEntry("OPENTHEDOORIN",self.locale)
self:_DisplayMessageToSAR(_heliUnit, text, self.messageTime, true, true)
return false
else
self:T(self.lid .. "[Pickup Debug] Pick up Pilot ".._lookupKeyHeli)
@@ -1701,11 +1886,14 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
self:T(self.lid .. "[Pickup Debug] Check hover timer ".._lookupKeyHeli)
if _time > 0 then
self:T(self.lid .. "[Pickup Debug] Helo hovering not long enough ".._lookupKeyHeli)
self:_DisplayMessageToSAR(_heliUnit, "Hovering above " .. _pilotName .. ". \n\nHold hover for " .. _time .. " seconds to winch them up. \n\nIf the countdown stops you\'re too far away!", self.messageTime, true)
local text = self.gettext:GetEntry("HOVERABOVE",self.locale)
text = string.format(text,_pilotName,_time)
self:_DisplayMessageToSAR(_heliUnit, text, self.messageTime, true)
else
self:T(self.lid .. "[Pickup Debug] Helo hovering long enough - door check ".._lookupKeyHeli)
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
local text = self.gettext:GetEntry("OPENTHEDOORIN",self.locale)
self:_DisplayMessageToSAR(_heliUnit, text, self.messageTime, true, true)
self:T(self.lid .. "[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli)
return false
else
@@ -1718,7 +1906,8 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
_reset = false
else
self:T(self.lid .. "[Pickup Debug] Helo hovering too high ".._lookupKeyHeli)
self:_DisplayMessageToSAR(_heliUnit, "Too high to winch " .. _pilotName .. " \nReduce height and hover for 10 seconds!", self.messageTime, true,true)
local text = self.gettext:GetEntry("TOOHIGHWINCH",self.locale)
self:_DisplayMessageToSAR(_heliUnit,string.format(text,_pilotName), self.messageTime, true,true)
self:T(self.lid .. "[Pickup Debug] Hovering too high, try again next loop ".._lookupKeyHeli)
return false
end
@@ -1782,7 +1971,8 @@ function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule, I
if ( _dist < self.FARPRescueDistance or isairport ) and ((_heliUnit:InAir() == false) or (IsHeloBase == true)) then
self:T(self.lid.."[Drop off debug] Distance ok, door check")
if self.pilotmustopendoors and self:_IsLoadingDoorOpen(heliname) == false then
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me out!", self.messageTime, true, true)
local text = self.gettext:GetEntry("OPENTHEDOOROUT",self.locale)
self:_DisplayMessageToSAR(_heliUnit, text, self.messageTime, true, true)
self:T(self.lid.."[Drop off debug] Door closed, try again next loop")
else
self:T(self.lid.."[Drop off debug] Rescued!")
@@ -1815,8 +2005,9 @@ function CSAR:_RescuePilots(_heliUnit)
local PilotsSaved = self:_PilotsOnboard(_heliName)
self.inTransitGroups[_heliName] = nil
local _txt = string.format("%s: The %d pilot(s) have been taken to the\nmedical clinic. Good job!", self:_GetCustomCallSign(_heliName), PilotsSaved)
local text = self.gettext:GetEntry("OPENTHEDOOROUT",self.locale)
local _txt = string.format(text, self:_GetCustomCallSign(_heliName), PilotsSaved)
self:_DisplayMessageToSAR(_heliUnit, _txt, self.messageTime)
@@ -1863,8 +2054,10 @@ function CSAR:_DisplayMessageToSAR(_unit, _text, _time, _clear, _speak, _overrid
if coord then
self.msrs:SetCoordinate(coord)
end
_text = string.gsub(_text,"km"," kilometer")
_text = string.gsub(_text,"nm"," nautical miles")
local km = self.gettext:GetEntry("KILOMETERS",self.locale)
local nm = self.gettext:GetEntry("NAUTMILES",self.locale)
_text = string.gsub(_text,"km",km)
_text = string.gsub(_text,"nm",nm)
self.SRSQueue:NewTransmission(_text,duration,self.msrs,tstart,2,subgroups,subtitle,subduration,self.SRSchannel,self.SRSModulation,gender,culture,self.SRSVoice,volume,label,coord)
end
return self
@@ -2035,7 +2228,8 @@ function CSAR:_SignalFlare(_unitName)
else
_distance = string.format("%.1fkm",_closest.distance/1000)
end
local _msg = string.format("%s - Firing signal flare at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance)
local text = self.gettext:GetEntry("FIRINGFLARE",self.locale)
local _msg = string.format(text, self:_GetCustomCallSign(_unitName), _clockDir, _distance)
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
local _coord = _closest.pilot:GetCoordinate()
@@ -2048,7 +2242,8 @@ function CSAR:_SignalFlare(_unitName)
else
dtext = string.format("%.1fkm",smokedist/1000)
end
self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",dtext), self.messageTime, false, false, true)
local text = self.gettext:GetEntry("NOPILOTSINRANGE",self.locale)
self:_DisplayMessageToSAR(_heli, string.format(text,dtext), self.messageTime, false, false, true)
end
return self
end
@@ -2103,7 +2298,8 @@ function CSAR:_ReqIRStrobe( _unitName )
else
_distance = string.format("%.1fkm",_closest.distance/1000)
end
local _msg = string.format("%s - IR Strobe active at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance)
local text = self.gettext:GetEntry("IRSTROBE",self.locale)
local _msg = string.format(text, self:_GetCustomCallSign(_unitName), _clockDir, _distance)
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
_closest.pilot:NewIRMarker(true,self.IRStrobeRuntime or 300)
else
@@ -2113,7 +2309,8 @@ function CSAR:_ReqIRStrobe( _unitName )
else
_distance = string.format("%.1fkm",smokedist/1000)
end
self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime, false, false, true)
local text = self.gettext:GetEntry("NOPILOTSINRANGE",self.locale)
self:_DisplayMessageToSAR(_heli, string.format(text,_distance), self.messageTime, false, false, true)
end
return self
end
@@ -2138,7 +2335,8 @@ function CSAR:_Reqsmoke( _unitName )
else
_distance = string.format("%.1fkm",_closest.distance/1000)
end
local _msg = string.format("%s - Popping smoke at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance)
local text = self.gettext:GetEntry("POPPINGSMOKE",self.locale)
local _msg = string.format(text, self:_GetCustomCallSign(_unitName), _clockDir, _distance)
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
local _coord = _closest.pilot:GetCoordinate()
local color = self.smokecolor
@@ -2150,7 +2348,8 @@ function CSAR:_Reqsmoke( _unitName )
else
_distance = string.format("%.1fkm",smokedist/1000)
end
self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime, false, false, true)
local text = self.gettext:GetEntry("NOPILOTSINRANGE",self.locale)
self:_DisplayMessageToSAR(_heli, string.format(text,_distance), self.messageTime, false, false, true)
end
return self
end
@@ -2174,7 +2373,8 @@ function CSAR:_ReqsmokeMash( _unitName )
else
disttext = string.format("%.1fkm",distance/1000)
end
local _msg = string.format("%s - Popping smoke at the closest rescue point: %s", self:_GetCustomCallSign(_unitName), disttext)
local text = self.gettext:GetEntry("POPPINGSMOKEMASH",self.locale)
local _msg = string.format(text, self:_GetCustomCallSign(_unitName), disttext)
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
local color = self.smokecolor
coordinate:Smoke(color)
@@ -2185,7 +2385,8 @@ function CSAR:_ReqsmokeMash( _unitName )
else
_distance = string.format("%.1fkm",smokedist/1000)
end
self:_DisplayMessageToSAR(_heli, string.format("No rescue point within %s",_distance), self.messageTime, false, false, true)
local text = self.gettext:GetEntry("NORESCUEPOINTWITHIN",self.locale)
self:_DisplayMessageToSAR(_heli, string.format(text,_distance), self.messageTime, false, false, true)
end
return self
end
@@ -2263,9 +2464,10 @@ function CSAR:_CheckOnboard(_unitName)
--list onboard pilots
local _inTransit = self.inTransitGroups[_unitName]
if _inTransit == nil then
self:_DisplayMessageToSAR(_unit, "No Rescued Pilots onboard", self.messageTime, false, false, true)
local text = self.gettext:GetEntry("NOPILOTSONBOARD",self.locale)
self:_DisplayMessageToSAR(_unit, text, self.messageTime, false, false, true)
else
local _text = "Onboard - RTB to FARP/Airfield or MASH: "
local _text = self.gettext:GetEntry("BOARDED",self.locale)
for _, _onboard in pairs(self.inTransitGroups[_unitName]) do
_text = _text .. "\n" .. _onboard.desc
end
@@ -2305,17 +2507,24 @@ function CSAR:_AddMedevacMenuItem()
local groupname = _group:GetName()
if self.addedTo[groupname] == nil then
self.addedTo[groupname] = true
local menuname = self.topmenuname or "CSAR"
local menuname = self.gettext:GetEntry("MENUTOP",self.locale)
menuname = self.topmenuname or menuname
local Menu1T = self.gettext:GetEntry("MENUACTIVE",self.locale)
local Menu2T = self.gettext:GetEntry("MENUCHECK",self.locale)
local Menu3T = self.gettext:GetEntry("MENUFLARE",self.locale)
local Menu4T = self.gettext:GetEntry("MENUSMOKE",self.locale)
local Menu5T = self.gettext:GetEntry("MENUSTROBE",self.locale)
local Menu6T = self.gettext:GetEntry("MENUMASH",self.locale)
local _rootPath = MENU_GROUP:New(_group,menuname)
local _rootMenu1 = MENU_GROUP_COMMAND:New(_group,"List Active CSAR",_rootPath, self._DisplayActiveSAR,self,_unitName)
local _rootMenu2 = MENU_GROUP_COMMAND:New(_group,"Check Onboard",_rootPath, self._CheckOnboard,self,_unitName)
local _rootMenu3 = MENU_GROUP_COMMAND:New(_group,"Request Signal Flare",_rootPath, self._SignalFlare,self,_unitName)
local _rootMenu4 = MENU_GROUP_COMMAND:New(_group,"Request Smoke",_rootPath, self._Reqsmoke,self,_unitName)
local _rootMenu1 = MENU_GROUP_COMMAND:New(_group,Menu1T,_rootPath, self._DisplayActiveSAR,self,_unitName)
local _rootMenu2 = MENU_GROUP_COMMAND:New(_group,Menu2T,_rootPath, self._CheckOnboard,self,_unitName)
local _rootMenu3 = MENU_GROUP_COMMAND:New(_group,Menu3T,_rootPath, self._SignalFlare,self,_unitName)
local _rootMenu4 = MENU_GROUP_COMMAND:New(_group,Menu4T,_rootPath, self._Reqsmoke,self,_unitName)
if self.AllowIRStrobe then
local _rootMenu5 = MENU_GROUP_COMMAND:New(_group,"Request IR Strobe",_rootPath, self._ReqIRStrobe,self,_unitName):Refresh()
local _rootMenu5 = MENU_GROUP_COMMAND:New(_group,Menu5T,_rootPath, self._ReqIRStrobe,self,_unitName):Refresh()
end
if self.EnableMenuSmokeMASH then
local _rootMenu6 = MENU_GROUP_COMMAND:New(_group,"Smoke Closest MASH",_rootPath, self._ReqsmokeMash,self,_unitName)
local _rootMenu6 = MENU_GROUP_COMMAND:New(_group,Menu6T,_rootPath, self._ReqsmokeMash,self,_unitName)
else
_rootMenu4:Refresh()
end
@@ -2580,6 +2789,9 @@ function CSAR:onafterStart(From, Event, To)
self.msrs = MSRS:New(path,channel,modulation) -- Sound.SRS#MSRS
self.msrs:SetPort(self.SRSport)
self.msrs:SetLabel("CSAR")
self.msrs:SetBackend(self.SRSBackend)
self.msrs:SetProvider(self.SRSProvider)
self.msrs.speed = self.SRSSpeed
self.msrs:SetCulture(self.SRSCulture)
self.msrs:SetCoalition(self.coalition)
self.msrs:SetVoice(self.SRSVoice)
@@ -2601,7 +2813,9 @@ function CSAR:onafterStart(From, Event, To)
local filepath = self.filepath
self:__Save(interval,filepath,filename)
end
self:_InitLocalization(self.locale)
return self
end
+17 -8
View File
@@ -559,14 +559,14 @@ MSRS.Voices = {
["fr_FR_Wavenet_G"] = "fr-FR-Wavenet-G", -- Male
["fr_FR_Wavenet_F"] = "fr-FR-Wavenet-F", -- Female
-- 2025 catalog changes
["de_DE_Wavenet_A"] = 'de-DE-Wavenet-A', -- Female
["de_DE_Wavenet_B"] = 'de-DE-Wavenet-B', -- Male
["de_DE_Wavenet_C"] = 'de-DE-Wavenet-C', -- Female
["de_DE_Wavenet_D"] = 'de-DE-Wavenet-D', -- Male
["de_DE_Wavenet_E"] = 'de-DE-Wavenet-E', -- Male
["de_DE_Wavenet_F"] = 'de-DE-Wavenet-F', -- Female
["de_DE_Wavenet_G"] = 'de-DE-Wavenet-G', -- Female
["de_DE_Wavenet_H"] = 'de-DE-Wavenet-H', -- Male
["de_DE_Wavenet_A"] = 'de-DE-Wavenet-A', -- Female
["de_DE_Wavenet_B"] = 'de-DE-Wavenet-B', -- Male
["de_DE_Wavenet_C"] = 'de-DE-Wavenet-C', -- Female
["de_DE_Wavenet_D"] = 'de-DE-Wavenet-D', -- Male
["de_DE_Wavenet_E"] = 'de-DE-Wavenet-E', -- Male
["de_DE_Wavenet_F"] = 'de-DE-Wavenet-F', -- Female
["de_DE_Wavenet_G"] = 'de-DE-Wavenet-G', -- Female
["de_DE_Wavenet_H"] = 'de-DE-Wavenet-H', -- Male
-- ES
["es_ES_Wavenet_B"] = "es-ES-Wavenet-E", -- Male
["es_ES_Wavenet_C"] = "es-ES-Wavenet-F", -- Female
@@ -2033,12 +2033,18 @@ end
function MSRS:_HoundTextToSpeech(Message,Frequencies,Modulations,Volume,Label,Coalition,Point,Speed,Gender,Culture,Voice,UseGoogle)
self:I(self.lid.."_HoundTextToSpeech")
Frequencies = UTILS.EnsureTable(Frequencies)
Modulations = UTILS.EnsureTable(Modulations)
local ffs = {}
for _,_f in pairs(Frequencies or self.frequencies) do
table.insert(ffs,string.format("%.1f",_f))
end
local freqs = table.concat(ffs, ",")
local modus = table.concat(Modulations or self.modulations, ",")
local coal=Coalition or self.coalition
@@ -2135,6 +2141,9 @@ end
function MSRS:_HoundTestTone(Frequencies, Modulations, Coalition)
self:I(self.lid.."_HoundTestTone")
Frequencies = UTILS.EnsureTable(Frequencies)
Modulations = UTILS.EnsureTable(Modulations)
local ffs = {}
for _,_f in pairs(Frequencies or self.frequencies) do
table.insert(ffs,string.format("%.1f",_f))