diff --git a/Moose Development/Moose/Ops/Awacs.lua b/Moose Development/Moose/Ops/Awacs.lua index 5c7256fc8..f9bd30be8 100644 --- a/Moose Development/Moose/Ops/Awacs.lua +++ b/Moose Development/Moose/Ops/Awacs.lua @@ -63,6 +63,7 @@ do -- @field Utilities.FiFo#FIFO RadioQueue -- @field Utilities.FiFo#FIFO PrioRadioQueue -- @field Utilities.FiFo#FIFO CAPAirwings +-- @field Utilities.FiFo#FIFO TacticalQueue -- @field #number AwacsTimeOnStation -- @field #number AwacsTimeStamp -- @field #number EscortsTimeOnStation @@ -539,6 +540,7 @@ AWACS = { ContactsAO = {}, -- Utilities.FiFo#FIFO RadioQueue = {}, -- Utilities.FiFo#FIFO PrioRadioQueue = {}, -- Utilities.FiFo#FIFO + TacticalQueue = {}, -- Utilities.FiFo#FIFO AwacsTimeOnStation = 4, AwacsTimeStamp = 0, EscortsTimeOnStation = 4, @@ -1124,6 +1126,7 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station self.Volume = 1.0 self.RadioQueue = FIFO:New() -- Utilities.FiFo#FIFO self.PrioRadioQueue = FIFO:New() -- Utilities.FiFo#FIFO + self.TacticalQueue = FIFO:New() -- Utilities.FiFo#FIFO self.maxspeakentries = 3 self.GoogleTTSPadding = 1 self.WindowsTTSPadding = 2.5 @@ -1384,32 +1387,65 @@ end -- @param #number Increase Increase to use, defaults to 0.5, thus channels created are 130, 130.5, 131 .. etc. -- @param #number Modulation Modulation to use, defaults to radio.modulation.AM. -- @param #number Interval Seconds between each update call. +-- @param #number Number Number of Frequencies to create, can be 1..10. -- @return #AWACS self -function AWACS:SetTacticalRadios(BaseFreq,Increase,Modulation,Interval) +function AWACS:SetTacticalRadios(BaseFreq,Increase,Modulation,Interval,Number) self:T(self.lid.."SetTacticalRadios") self.TacticalMenu = true self.TacticalBaseFreq = BaseFreq or 130 self.TacticalIncrFreq = Increase or 0.5 self.TacticalModulation = Modulation or radio.modulation.AM self.TacticalInterval = Interval or 120 - for i=1,10 do + local number = Number or 10 + if number < 1 then number = 1 end + if number > 10 then number = 10 end + for i=1,number do local freq = self.TacticalBaseFreq + ((i-1)*self.TacticalIncrFreq) self.TacticalFrequencies[freq] = freq end + if self.AwacsSRS then + self.TacticalSRS = MSRS:New(self.PathToSRS,self.TacticalBaseFreq,self.TacticalModulation,self.Volume) + self.TacticalSRS:SetCoalition(self.coalition) + self.TacticalSRS:SetGender(self.Gender) + self.TacticalSRS:SetCulture(self.Culture) + self.TacticalSRS:SetVoice(self.Voice) + self.TacticalSRS:SetPort(self.Port) + self.TacticalSRS:SetLabel("AWACS") + if self.PathToGoogleKey then + self.TacticalSRS:SetGoogle(self.PathToGoogleKey) + end + self.TacticalSRSQ = MSRSQUEUE:New("Tactical AWACS") + end return self end - --- TODO +-- [Internal] _RefreshMenuNonSubscribed +-- @param #AWACS self +-- @return #AWACS self function AWACS:_RefreshMenuNonSubscribed() self:T(self.lid.."_RefreshMenuNonSubscribed") - local menustr = self.clientmenus:ReadByID(gname) - local menu = menustr.tactical -- Core.Menu#MENU_GROUP - menu:RemoveSubMenus() - for _,_freq in UTILS.spairs(self.TacticalFrequencies) do - local modu = UTILS.GetModulationName(self.TacticalModulation) - local text = string.format("Subscribe to %.3f %s",_freq,modu) - local entry = MENU_GROUP_COMMAND:New(Group,text,menu,self._SubScribeTactRadio,self,Group,_freq) + local aliveset = self.clientset:GetAliveSet() + + for _,_group in pairs(aliveset) do + -- go through set and re-build the sub-menu + local grp = _group -- Wrapper.Client#CLIENT + local Group = grp:GetGroup() + local gname = nil + if Group and Group:IsAlive() then + gname = Group:GetName() + self:T(gname) + end + local menustr = self.clientmenus:ReadByID(gname) + local menu = menustr.tactical -- Core.Menu#MENU_GROUP + if not self.TacticalSubscribers[gname] and menu then + menu:RemoveSubMenus() + for _,_freq in UTILS.spairs(self.TacticalFrequencies) do + local modu = UTILS.GetModulationName(self.TacticalModulation) + local text = string.format("Subscribe to %.3f %s",_freq,modu) + local entry = MENU_GROUP_COMMAND:New(Group,text,menu,self._SubScribeTactRadio,self,Group,_freq) + end + end end return self end @@ -1466,8 +1502,11 @@ function AWACS:_SubScribeTactRadio(Group,Frequency) self:_NewRadioEntry(text,text,GID,true,true,true,false,true) local menustr = self.clientmenus:ReadByID(gname) local menu = menustr.tactical -- Core.Menu#MENU_GROUP - menu:RemoveSubMenus() - local entry = MENU_GROUP_COMMAND:New(Group,"Unsubscribe",menu,self._UnsubScribeTactRadio,self,Group) + if menu then + menu:RemoveSubMenus() + local text = string.format("Unsubscribe %.3f %s",Frequency,modu) + local entry = MENU_GROUP_COMMAND:New(Group,text,menu,self._UnsubScribeTactRadio,self,Group) + end elseif self.AwacsFG then -- no, unknown local nocheckin = self.gettext:GetEntry("NOTCHECKEDIN",self.locale) @@ -1550,8 +1589,9 @@ end -- @param #boolean IsNew New -- @param #boolean FromAI From AI -- @param #boolean IsPrio Priority entry +-- @param #boolean Tactical Is for tactical info -- @return #AWACS self -function AWACS:_NewRadioEntry(TextTTS, TextScreen,GID,IsGroup,ToScreen,IsNew,FromAI,IsPrio) +function AWACS:_NewRadioEntry(TextTTS, TextScreen,GID,IsGroup,ToScreen,IsNew,FromAI,IsPrio,Tactical) self:T(self.lid.."_NewRadioEntry") local RadioEntry = {} -- #AWACS.RadioEntry RadioEntry.IsNew = IsNew @@ -1562,7 +1602,9 @@ function AWACS:_NewRadioEntry(TextTTS, TextScreen,GID,IsGroup,ToScreen,IsNew,Fro RadioEntry.Duration = STTS.getSpeechTime(TextTTS,0.95,false) or 8 RadioEntry.FromAI = FromAI RadioEntry.IsGroup = IsGroup - if IsPrio then + if Tactical then + self.TacticalQueue:Push(RadioEntry) + elseif IsPrio then self.PrioRadioQueue:Push(RadioEntry) else self.RadioQueue:Push(RadioEntry) @@ -2813,8 +2855,9 @@ end -- @param #AWACS self -- @param #string Callsign Callsign to address -- @param #number GID GroupID for comms +-- @param #boolean Tactical Is for tactical info -- @return #AWACS self -function AWACS:_CreateBogeyDope(Callsign,GID) +function AWACS:_CreateBogeyDope(Callsign,GID,Tactical) self:T(self.lid.."_CreateBogeyDope for "..Callsign.." GID "..GID) local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup @@ -2840,7 +2883,7 @@ function AWACS:_CreateBogeyDope(Callsign,GID) local tag = contact.TargetGroupNaming local reportingname = contact.ReportingName -- DONE - add tag - self:_AnnounceContact(contact,false,group,true,tag,false,reportingname) + self:_AnnounceContact(contact,false,group,true,tag,false,reportingname,Tactical) end end @@ -2965,8 +3008,9 @@ end --- [Internal] AWACS Menu for Bogey Dope -- @param #AWACS self -- @param Wrapper.Group#GROUP Group Group to use +-- @param #boolean Tactical Check for tactical info -- @return #AWACS self -function AWACS:_BogeyDope(Group) +function AWACS:_BogeyDope(Group,Tactical) self:T(self.lid.."_BogeyDope") local text = "" local textScreen = "" @@ -2977,8 +3021,7 @@ function AWACS:_BogeyDope(Group) -- no intel yet! local clean = self.gettext:GetEntry("CLEAN",self.locale) text = string.format(clean,self:_GetCallSign(Group,GID) or "Ghost 1", self.callsigntxt) - self:_NewRadioEntry(text,text,0,false,true,true,false,true) - + self:_NewRadioEntry(text,text,0,false,true,true,false,true,Tactical) return self end @@ -3020,7 +3063,7 @@ function AWACS:_BogeyDope(Group) local clean = self.gettext:GetEntry("CLEAN",self.locale) text = string.format(clean,self:_GetCallSign(Group,GID) or "Ghost 1", self.callsigntxt) - self:_NewRadioEntry(text,textScreen,GID,Outcome,Outcome,true,false,true) + self:_NewRadioEntry(text,textScreen,GID,Outcome,Outcome,true,false,true,Tactical) else @@ -3039,9 +3082,9 @@ function AWACS:_BogeyDope(Group) textScreen = string.format("%s%d %s.\n",textScreen,contactsAO,groupstxt) end - self:_NewRadioEntry(text,textScreen,GID,Outcome,true,true,false,true) + self:_NewRadioEntry(text,textScreen,GID,Outcome,true,true,false,true,Tactical) - self:_CreateBogeyDope(self:_GetCallSign(Group,GID) or "Ghost 1",GID) + self:_CreateBogeyDope(self:_GetCallSign(Group,GID) or "Ghost 1",GID,Tactical) end end @@ -3049,7 +3092,7 @@ function AWACS:_BogeyDope(Group) -- no, unknown local nocheckin = self.gettext:GetEntry("NOTCHECKEDIN",self.locale) text = string.format(nocheckin,self:_GetCallSign(Group,GID) or "Ghost 1", self.callsigntxt) - self:_NewRadioEntry(text,text,GID,Outcome,true,true,false) + self:_NewRadioEntry(text,text,GID,Outcome,true,true,false,Tactical) end return self @@ -4953,8 +4996,9 @@ end -- @param #string Tag Tag name for this contact. Alpha, Brave, Charlie ... -- @param #boolean IsPopup This is a pop-up group -- @param #string ReportingName The NATO code reporting name for the contact, e.g. "Foxbat". "Bogey" if unknown. +-- @param #boolean Tactical -- @return #AWACS self -function AWACS:_AnnounceContact(Contact,IsNew,Group,IsBogeyDope,Tag,IsPopup,ReportingName) +function AWACS:_AnnounceContact(Contact,IsNew,Group,IsBogeyDope,Tag,IsPopup,ReportingName,Tactical) self:T(self.lid.."_AnnounceContact") -- do we have a group to talk to? local tag = "" @@ -5081,7 +5125,7 @@ function AWACS:_AnnounceContact(Contact,IsNew,Group,IsBogeyDope,Tag,IsPopup,Repo BRAText = string.gsub(BRAText,"BRA","brah") local prio = IsNew or IsBogeyDope - self:_NewRadioEntry(BRAText,TextScreen,GID,isGroup,true,IsNew,false,prio) + self:_NewRadioEntry(BRAText,TextScreen,GID,isGroup,true,IsNew,false,prio,Tactical) return self end @@ -5469,6 +5513,15 @@ function AWACS:_MergedCall(GID) local merge = self.gettext:GetEntry("MERGED",self.locale) local text = string.format("%s. %s. %s.",self.callsigntxt,pilotcallsign,merge) self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true) + if GID and GID ~= 0 then + local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup + if managedgroup and managedgroup.Group and managedgroup.Group:IsAlive() then + local name = managedgroup.GroupName + if self.TacticalSubscribers[name] then + self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true,true) + end + end + end return self end @@ -5844,6 +5897,10 @@ function AWACS:onafterStart(From, Event, To) self:__Started(-5) end + if self.TacticalMenu then + self:__CheckTacticalQueue(55) + end + self:__Status(-30) return self end @@ -6457,6 +6514,77 @@ function AWACS:onafterLostCluster(From,Event,To,Cluster,Mission) return self end +--- [Internal] onafterCheckTacticalQueue +-- @param #AWACS self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @return #AWACS self +function AWACS:onafterCheckTacticalQueue(From,Event,To) + self:T({From, Event, To}) + -- do we have messages queued? + + if self.clientset:CountAlive() == 0 then + self:T(self.lid.."No player connected.") + self:__CheckTacticalQueue(-5) + return self + end + + for _name,_freq in pairs(self.TacticalSubscribers) do + local Group = nil + if _name then + Group = GROUP:FindByName(_name) + end + if Group and Group:IsAlive() then + self:_BogeyDope(Group,true) + end + end + + if (self.TacticalQueue:IsNotEmpty()) then + + while self.TacticalQueue:Count() > 0 do + + local RadioEntry = self.TacticalQueue:Pull() -- #AWACS.RadioEntry + self:T({RadioEntry}) + local frequency = self.TacticalBaseFreq + if RadioEntry.GroupID and RadioEntry.GroupID ~= 0 then + local managedgroup = self.ManagedGrps[RadioEntry.GroupID] -- #AWACS.ManagedGroup + if managedgroup and managedgroup.Group and managedgroup.Group:IsAlive() then + local name = managedgroup.GroupName + frequency = self.TacticalSubscribers[name] + end + end + -- AI AWACS Speaking + local gtext = RadioEntry.TextTTS + if self.PathToGoogleKey then + gtext = string.format("%s",gtext) + end + self.TacticalSRSQ:NewTransmission(gtext,nil,self.TacticalSRS,nil,0.5,nil,nil,nil,frequency,self.TacticalModulation,nil,nil,nil,nil,nil) + + self:T(RadioEntry.TextTTS) + + if RadioEntry.ToScreen and RadioEntry.TextScreen and (not self.SuppressScreenOutput) then + if RadioEntry.GroupID and RadioEntry.GroupID ~= 0 then + local managedgroup = self.ManagedGrps[RadioEntry.GroupID] -- #AWACS.ManagedGroup + if managedgroup and managedgroup.Group and managedgroup.Group:IsAlive() then + MESSAGE:New(RadioEntry.TextScreen,20,"AWACS"):ToGroup(managedgroup.Group) + self:T(RadioEntry.TextScreen) + end + else + MESSAGE:New(RadioEntry.TextScreen,20,"AWACS"):ToCoalition(self.coalition) + end + end + end + + end -- end while + + if self:Is("Running") then + self:__CheckTacticalQueue(-self.TacticalInterval) + end + return self +end + + --- [Internal] onafterCheckRadioQueue -- @param #AWACS self -- @param #string From