From b40c1e4575bd7b8a234b4ddef390c8ac4c886918 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 4 Jan 2024 18:49:47 +0100 Subject: [PATCH 01/20] Fixes --- Moose Development/Moose/Functional/Stratego.lua | 17 +++++++++++------ Moose Development/Moose/Ops/Legion.lua | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Functional/Stratego.lua b/Moose Development/Moose/Functional/Stratego.lua index af7eb3d6f..e236544b2 100644 --- a/Moose Development/Moose/Functional/Stratego.lua +++ b/Moose Development/Moose/Functional/Stratego.lua @@ -394,6 +394,7 @@ function STRATEGO:AnalyseBases() zone = abzone, coord = coord, type = abtype, + opszone = opszone, } airbasetable[abname] = tbl nonconnectedab[abname] = true @@ -494,10 +495,10 @@ end --- [USER] Manually add a route, for e.g. Island hopping or to connect isolated networks. Use **after** STRATEGO has been started! -- @param #STRATEGO self --- @param #string Startpoint --- @param #string Endpoint +-- @param #string Startpoint Starting Point, e.g. AIRBASE.Syria.Hatay +-- @param #string Endpoint End Point, e.g. AIRBASE.Syria.H4 -- @param #table Color (Optional) RGB color table {r, g, b}, e.g. {1,0,0} for red. Defaults to lila. --- @param #number LineType (Optional) Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 5. +-- @param #number Linetype (Optional) Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 5. -- @param #boolean Draw (Optional) If true, draw route on the F10 map. Defaukt false. -- @return #STRATEGO self function STRATEGO:AddRoutesManually(Startpoint,Endpoint,Color,Linetype,Draw) @@ -1002,9 +1003,11 @@ end -- @param #string End The name of the end node. -- @param #number Hops Max iterations to find a route. -- @param #boolean Draw If true, draw the route on the map. +-- @param #table Color (Optional) RGB color table {r, g, b}, e.g. {1,0,0} for red. Defaults to black. +-- @param #number LineType (Optional) Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 6. -- @return #table Route Table of #string name entries of the route -- @return #boolean Complete If true, the route was found end-to-end. -function STRATEGO:FindRoute(Start,End,Hops,Draw) +function STRATEGO:FindRoute(Start,End,Hops,Draw,Color,LineType) self:I({Start,End,Hops}) --local bases = UTILS.DeepCopy(self.airbasetable) local Route = {} @@ -1046,7 +1049,9 @@ function STRATEGO:FindRoute(Start,End,Hops,Draw) local p2=Route[i+1] local c1 = self.airbasetable[p1].coord -- Core.Point#COORDINATE local c2 = self.airbasetable[p2].coord -- Core.Point#COORDINATE - c1:LineToAll(c2,-1,{0,0,0},1,6) + local line = LineType or 6 + local color = Color or {0,0,0} + c1:LineToAll(c2,-1,color,1,line) end end @@ -1076,7 +1081,7 @@ function STRATEGO:FindRoute(Start,End,Hops,Draw) end end end - if self.debug or Draw then DrawRoute(Route) end + if (self.debug or Draw) then DrawRoute(Route) end return Route, routecomplete end diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index 0f6535e99..610636593 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -2265,7 +2265,7 @@ function LEGION:RecruitAssetsForMission(Mission) end end - self:T(self.lid..string.format("Largest cargo bay available=%.1f", MaxWeight)) + self:T(self.lid..string.format("Largest cargo bay available=%.1f", MaxWeight or 0)) end From 65315251b5f3db591a8e8c6a41b345111b7e98c2 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 5 Jan 2024 12:13:04 +0100 Subject: [PATCH 02/20] PLAYERTASK, AWACS - small fix for the revamped SRS --- Moose Development/Moose/Ops/Awacs.lua | 22 ++++++++++++++-------- Moose Development/Moose/Ops/PlayerTask.lua | 14 +++++++++----- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Moose Development/Moose/Ops/Awacs.lua b/Moose Development/Moose/Ops/Awacs.lua index de6668415..583a7f30f 100644 --- a/Moose Development/Moose/Ops/Awacs.lua +++ b/Moose Development/Moose/Ops/Awacs.lua @@ -17,7 +17,7 @@ -- === -- -- ### Author: **applevangelist** --- @date Last Update Nov 2023 +-- @date Last Update Jan 2024 -- @module Ops.AWACS -- @image OPS_AWACS.jpg @@ -507,7 +507,7 @@ do -- @field #AWACS AWACS = { ClassName = "AWACS", -- #string - version = "0.2.59", -- #string + version = "0.2.60", -- #string lid = "", -- #string coalition = coalition.side.BLUE, -- #number coalitiontxt = "blue", -- #string @@ -1405,15 +1405,17 @@ function AWACS:SetTacticalRadios(BaseFreq,Increase,Modulation,Interval,Number) self.TacticalFrequencies[freq] = freq end if self.AwacsSRS then - self.TacticalSRS = MSRS:New(self.PathToSRS,self.TacticalBaseFreq,self.TacticalModulation,self.Volume) + self.TacticalSRS = MSRS:New(self.PathToSRS,self.TacticalBaseFreq,self.TacticalModulation) 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") + self.TacticalSRS:SetVolume(self.Volume) if self.PathToGoogleKey then - self.TacticalSRS:SetGoogle(self.PathToGoogleKey) + --self.TacticalSRS:SetGoogle(self.PathToGoogleKey) + self.TacticalSRS:SetProviderOptionsGoogle(self.PathToGoogleKey,self.AccessKey) end self.TacticalSRSQ = MSRSQUEUE:New("Tactical AWACS") end @@ -2079,8 +2081,9 @@ end -- Note that this must be installed on your windows system. Can also be Google voice types, if you are using Google TTS. -- @param #number Volume Volume - between 0.0 (silent) and 1.0 (loudest) -- @param #string PathToGoogleKey Path to your google key if you want to use google TTS +-- @param #string AccessKey Your Google API access key. This is necessary if DCS-gRPC is used as backend. -- @return #AWACS self -function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey) +function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey) self:T(self.lid.."SetSRS") self.PathToSRS = PathToSRS or "C:\\Program Files\\DCS-SimpleRadio-Standalone" self.Gender = Gender or "male" @@ -2088,17 +2091,20 @@ function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey self.Port = Port or 5002 self.Voice = Voice self.PathToGoogleKey = PathToGoogleKey + self.AccessKey = AccessKey self.Volume = Volume or 1.0 - self.AwacsSRS = MSRS:New(self.PathToSRS,self.MultiFrequency,self.MultiModulation,self.Volume) + self.AwacsSRS = MSRS:New(self.PathToSRS,self.MultiFrequency,self.MultiModulation) self.AwacsSRS:SetCoalition(self.coalition) self.AwacsSRS:SetGender(self.Gender) self.AwacsSRS:SetCulture(self.Culture) self.AwacsSRS:SetVoice(self.Voice) self.AwacsSRS:SetPort(self.Port) self.AwacsSRS:SetLabel("AWACS") + self.AwacsSRS:SetVolume(Volume) if self.PathToGoogleKey then - self.AwacsSRS:SetGoogle(self.PathToGoogleKey) + --self.AwacsSRS:SetGoogle(self.PathToGoogleKey) + self.AwacsSRS:SetProviderOptionsGoogle(self.PathToGoogleKey,self.AccessKey) end return self @@ -6595,7 +6601,7 @@ function AWACS:onafterCheckTacticalQueue(From,Event,To) 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.TacticalSRSQ:NewTransmission(gtext,nil,self.TacticalSRS,nil,0.5,nil,nil,nil,frequency,self.TacticalModulation) self:T(RadioEntry.TextTTS) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 87b9921cb..79ffe5803 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -21,7 +21,7 @@ -- === -- @module Ops.PlayerTask -- @image OPS_PlayerTask.jpg --- @date Last Update Oct 2023 +-- @date Last Update Jan 2024 do @@ -1552,7 +1552,7 @@ PLAYERTASKCONTROLLER.Messages = { --- PLAYERTASK class version. -- @field #string version -PLAYERTASKCONTROLLER.version="0.1.63" +PLAYERTASKCONTROLLER.version="0.1.64" --- Create and run a new TASKCONTROLLER instance. -- @param #PLAYERTASKCONTROLLER self @@ -4005,9 +4005,10 @@ end -- Note that this must be installed on your windows system. Can also be Google voice types, if you are using Google TTS. -- @param #number Volume (Optional) Volume - between 0.0 (silent) and 1.0 (loudest) -- @param #string PathToGoogleKey (Optional) Path to your google key if you want to use google TTS +-- @param #string AccessKey Your Google API access key. This is necessary if DCS-gRPC is used as backend. -- @param Core.Point#COORDINATE Coordinate Coordinate from which the controller radio is sending -- @return #PLAYERTASKCONTROLLER self -function PLAYERTASKCONTROLLER:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,Coordinate) +function PLAYERTASKCONTROLLER:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey,Coordinate) self:T(self.lid.."SetSRS") self.PathToSRS = PathToSRS or "C:\\Program Files\\DCS-SimpleRadio-Standalone" -- self.Gender = Gender or "male" -- @@ -4015,6 +4016,7 @@ function PLAYERTASKCONTROLLER:SetSRS(Frequency,Modulation,PathToSRS,Gender,Cultu self.Port = Port or 5002 -- self.Voice = Voice -- self.PathToGoogleKey = PathToGoogleKey -- + self.AccessKey = AccessKey self.Volume = Volume or 1.0 -- self.UseSRS = true self.Frequency = Frequency or {127,251} -- @@ -4022,15 +4024,17 @@ function PLAYERTASKCONTROLLER:SetSRS(Frequency,Modulation,PathToSRS,Gender,Cultu self.Modulation = Modulation or {radio.modulation.FM,radio.modulation.AM} -- self.BCModulation = self.Modulation -- set up SRS - self.SRS=MSRS:New(self.PathToSRS,self.Frequency,self.Modulation,self.Volume) + self.SRS=MSRS:New(self.PathToSRS,self.Frequency,self.Modulation) self.SRS:SetCoalition(self.Coalition) self.SRS:SetLabel(self.MenuName or self.Name) self.SRS:SetGender(self.Gender) self.SRS:SetCulture(self.Culture) self.SRS:SetPort(self.Port) self.SRS:SetVoice(self.Voice) + self.SRS:SetVolume(self.Volume) if self.PathToGoogleKey then - self.SRS:SetGoogle(self.PathToGoogleKey) + --self.SRS:SetGoogle(self.PathToGoogleKey) + self.SRS:SetProviderOptionsGoogle(self.PathToGoogleKey,self.AccessKey) end if Coordinate then self.SRS:SetCoordinate(Coordinate) From e2bf1f727d9e712674c20a131839c0d4110c0f58 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 5 Jan 2024 15:37:52 +0100 Subject: [PATCH 03/20] FLIGHTGROUP - Amending landing on an AFB w/o runways SRS - some improvements --- Moose Development/Moose/Ops/FlightGroup.lua | 15 ++++++++++++--- Moose Development/Moose/Sound/SRS.lua | 16 ++++++++++++++-- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index ba55abbfb..1be7c0dbe 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -3230,13 +3230,22 @@ function FLIGHTGROUP:_LandAtAirbase(airbase, SpeedTo, SpeedHold, SpeedLand) local TaskFinal = self.group:TaskFunction("FLIGHTGROUP._OnFinal", self) -- Final approach waypoint. - local papp=airbase:GetCoordinate():Translate(x1, runway.heading-180):SetAltitude(h1) + local rheading + if runway then + rheading = runway.heading-180 + else + -- AB HeloBase w/o runway eg Naqoura + local wind = airbase:GetCoordinate():GetWind() + rheading = -wind + end + + local papp=airbase:GetCoordinate():Translate(x1, rheading):SetAltitude(h1) wp[#wp+1]=papp:WaypointAirTurningPoint("BARO", UTILS.KnotsToKmph(SpeedLand), {TaskFinal}, "Final Approach") -- Okay, it looks like it's best to specify the coordinates not at the airbase but a bit away. This causes a more direct landing approach. - local pland=airbase:GetCoordinate():Translate(x2, runway.heading-180):SetAltitude(h2) + local pland=airbase:GetCoordinate():Translate(x2, rheading):SetAltitude(h2) wp[#wp+1]=pland:WaypointAirLanding(UTILS.KnotsToKmph(SpeedLand), airbase, {}, "Landing") - + elseif airbase:IsShip() or airbase:IsHelipad() then --- diff --git a/Moose Development/Moose/Sound/SRS.lua b/Moose Development/Moose/Sound/SRS.lua index 559d23c56..d440ed974 100644 --- a/Moose Development/Moose/Sound/SRS.lua +++ b/Moose Development/Moose/Sound/SRS.lua @@ -516,8 +516,20 @@ end -- @return #MSRS self function MSRS:SetBackend(Backend) self:F( {Backend=Backend} ) - self.backend=Backend or MSRS.Backend.SRSEXE - + Backend = Backend or MSRS.Backend.SRSEXE -- avoid nil + local function Checker(back) + local ok = false + for _,_backend in pairs(MSRS.Backend) do + if tostring(back) == _backend then ok = true end + end + return ok + end + + if Checker(Backend) then + self.backend=Backend or MSRS.Backend.SRSEXE + else + MESSAGE:New("ERROR: Backend "..tostring(Backend).." is not supported!",30,"MSRS",true):ToLog():ToAll() + end return self end From f2f7c8829968ab5b9e3e4a0a67fbc1f453bf81e5 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 5 Jan 2024 15:42:11 +0100 Subject: [PATCH 04/20] SRS changes --- Moose Development/Moose/Core/Message.lua | 6 ++-- Moose Development/Moose/Sound/SRS.lua | 45 +++++++++++++++--------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index 46c896f0d..ce95f03c8 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -480,7 +480,7 @@ _MESSAGESRS = {} -- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS() -- function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,Gender,Culture,Voice,Coalition,Volume,Label,Coordinate) - _MESSAGESRS.MSRS = MSRS:New(PathToSRS,Frequency or 243,Modulation or radio.modulation.AM,Volume) + _MESSAGESRS.MSRS = MSRS:New(PathToSRS,Frequency or 243,Modulation or radio.modulation.AM) _MESSAGESRS.frequency = Frequency _MESSAGESRS.modulation = Modulation or radio.modulation.AM @@ -497,7 +497,7 @@ function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,G _MESSAGESRS.MSRS:SetGender(Gender) _MESSAGESRS.Gender = Gender or "female" - _MESSAGESRS.MSRS:SetGoogle(PathToCredentials) + _MESSAGESRS.MSRS:SetProviderOptionsGoogle(PathToCredentials) _MESSAGESRS.MSRS:SetLabel(Label or "MESSAGE") _MESSAGESRS.label = Label or "MESSAGE" @@ -543,7 +543,7 @@ function MESSAGE:ToSRS(frequency,modulation,gender,culture,voice,coalition,volum _MESSAGESRS.MSRS:SetCoordinate(coordinate) end local category = string.gsub(self.MessageCategory,":","") - _MESSAGESRS.SRSQ:NewTransmission(self.MessageText,nil,_MESSAGESRS.MSRS,nil,nil,nil,nil,nil,frequency or _MESSAGESRS.frequency,modulation or _MESSAGESRS.modulation, gender or _MESSAGESRS.Gender,culture or _MESSAGESRS.Culture,nil,volume or _MESSAGESRS.volume,category,coordinate or _MESSAGESRS.coordinate) + _MESSAGESRS.SRSQ:NewTransmission(self.MessageText,nil,_MESSAGESRS.MSRS,0.5,1,nil,nil,nil,frequency or _MESSAGESRS.frequency,modulation or _MESSAGESRS.modulation, gender or _MESSAGESRS.Gender,culture or _MESSAGESRS.Culture,nil,volume or _MESSAGESRS.volume,category,coordinate or _MESSAGESRS.coordinate) end return self end diff --git a/Moose Development/Moose/Sound/SRS.lua b/Moose Development/Moose/Sound/SRS.lua index 559d23c56..b470264eb 100644 --- a/Moose Development/Moose/Sound/SRS.lua +++ b/Moose Development/Moose/Sound/SRS.lua @@ -516,8 +516,20 @@ end -- @return #MSRS self function MSRS:SetBackend(Backend) self:F( {Backend=Backend} ) - self.backend=Backend or MSRS.Backend.SRSEXE - + Backend = Backend or MSRS.Backend.SRSEXE -- avoid nil + local function Checker(back) + local ok = false + for _,_backend in pairs(MSRS.Backend) do + if tostring(back) == _backend then ok = true end + end + return ok + end + + if Checker(Backend) then + self.backend=Backend + else + MESSAGE:New("ERROR: Backend "..tostring(Backend).." is not supported!",30,"MSRS",true):ToLog():ToAll() + end return self end @@ -1184,8 +1196,8 @@ end -- @param Core.Point#COORDINATE Coordinate Coordinate. -- @return #MSRS self function MSRS:PlayTextExt(Text, Delay, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label, Coordinate) - self:F( {Text, Delay, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label, Coordinate} ) - + self:T(( {Text, Delay, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label, Coordinate} ) + self:T((self.lid.."Backend "..self.backend) if Delay and Delay>0 then self:ScheduleOnce(Delay, MSRS.PlayTextExt, self, Text, 0, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label, Coordinate) else @@ -1205,6 +1217,7 @@ function MSRS:PlayTextExt(Text, Delay, Frequencies, Modulations, Gender, Culture self:_ExecCommand(command) elseif self.backend==MSRS.Backend.GRPC then + --BASE:I("MSRS.Backend.GRPC") self:_DCSgRPCtts(Text, Frequencies, Gender, Culture, Voice, Volume, Label, Coordinate) @@ -1831,7 +1844,7 @@ end -- @param #MSRSQUEUE self -- @return #MSRSQUEUE self The MSRSQUEUE object. function MSRSQUEUE:Clear() - self:I(self.lid.."Clearing MSRSQUEUE") + self:T((self.lid.."Clearing MSRSQUEUE") self.queue={} return self end @@ -1842,7 +1855,6 @@ end -- @param #MSRSQUEUE.Transmission transmission The transmission data table. -- @return #MSRSQUEUE self function MSRSQUEUE:AddTransmission(transmission) - -- Init. transmission.isplaying=false transmission.Tstarted=nil @@ -1921,20 +1933,20 @@ function MSRSQUEUE:NewTransmission(text, duration, msrs, tstart, interval, subgr transmission.Tplay=tstart or timer.getAbsTime() transmission.subtitle=subtitle transmission.interval=interval or 0 - transmission.frequency=frequency - transmission.modulation=modulation + transmission.frequency=frequency or msrs.frequencies + transmission.modulation=modulation or msrs.modulations transmission.subgroups=subgroups if transmission.subtitle then transmission.subduration=subduration or transmission.duration else transmission.subduration=0 --nil end - transmission.gender = gender - transmission.culture = culture - transmission.voice = voice - transmission.volume = volume - transmission.label = label - transmission.coordinate = coordinate + transmission.gender = gender or msrs.gender + transmission.culture = culture or msrs.culture + transmission.voice = voice or msrs.voice + transmission.volume = volume or msrs.volume + transmission.label = label or msrs.Label + transmission.coordinate = coordinate or msrs.coordinate -- Add transmission to queue. self:AddTransmission(transmission) @@ -1946,7 +1958,8 @@ end -- @param #MSRSQUEUE self -- @param #MSRSQUEUE.Transmission transmission The transmission. function MSRSQUEUE:Broadcast(transmission) - + self:T((self.lid.."Broadcast") + if transmission.frequency then transmission.msrs:PlayTextExt(transmission.text, nil, transmission.frequency, transmission.modulation, transmission.gender, transmission.culture, transmission.voice, transmission.volume, transmission.label, transmission.coordinate) else @@ -2115,7 +2128,7 @@ function MSRSQUEUE:_CheckRadioQueue(delay) -- 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)) + self:T((self.lid..string.format("Broadcasting text=\"%s\" at T=%.3f", next.text, time)) -- Call SRS. self:Broadcast(next) From a1fb09285be71c08868f667c88e38750d0f265e4 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 5 Jan 2024 15:42:33 +0100 Subject: [PATCH 05/20] STRATEGO - Improvements --- .../Moose/Functional/Stratego.lua | 115 ++++++++++++++++-- 1 file changed, 104 insertions(+), 11 deletions(-) diff --git a/Moose Development/Moose/Functional/Stratego.lua b/Moose Development/Moose/Functional/Stratego.lua index e236544b2..f8c9e8c07 100644 --- a/Moose Development/Moose/Functional/Stratego.lua +++ b/Moose Development/Moose/Functional/Stratego.lua @@ -42,6 +42,7 @@ -- @field #number CaptureUnits -- @field #number CaptureThreatlevel -- @extends Core.Base#BASE +-- @extends Core.Fsm#FSM --- *If you see what is right and fail to act on it, you lack courage* --- Confucius @@ -175,7 +176,7 @@ STRATEGO = { debug = false, drawzone = false, markzone = false, - version = "0.2.1", + version = "0.2.2", portweight = 3, POIweight = 1, maxrunways = 3, @@ -244,8 +245,8 @@ STRATEGO.Type = { -- @param #number MaxDist Maximum distance of a single route in kilometers, defaults to 150. -- @return #STRATEGO self function STRATEGO:New(Name,Coalition,MaxDist) - -- Inherit everything from BASE class. - local self = BASE:Inherit(self, BASE:New()) -- #STRATEGO + -- Inherit everything from FSM class. + local self = BASE:Inherit(self, FSM:New()) -- #STRATEGO self.coalition = Coalition self.coalitiontext = UTILS.GetCoalitionName(Coalition) @@ -267,14 +268,56 @@ function STRATEGO:New(Name,Coalition,MaxDist) [3] = {0,0,1}, -- blue [4] = {1,0.65,0}, -- orange } - + + -- Start State. + self:SetStartState("Stopped") + + -- Add FSM transitions. + -- From State --> Event --> To State + self:AddTransition("Stopped", "Start", "Running") -- Start FSM. + self:AddTransition("*", "Update", "*") -- Start FSM. + self:AddTransition("*", "NodeEvent", "*") -- Start FSM. + self:AddTransition("Running", "Stop", "Stopped") -- Start FSM. + + ------------------------ + --- Pseudo Functions --- + ------------------------ + + --- Triggers the FSM event "Start". Starts the STRATEGO. Initializes parameters and starts event handlers. + -- @function [parent=#STRATEGO] Start + -- @param #STRATEGO self + + --- Triggers the FSM event "Start" after a delay. Starts the STRATEGO. Initializes parameters and starts event handlers. + -- @function [parent=#STRATEGO] __Start + -- @param #STRATEGO self + -- @param #number delay Delay in seconds. + + --- Triggers the FSM event "Stop". Stops the STRATEGO and all its event handlers. + -- @function [parent=#STRATEGO] Stop + -- @param #STRATEGO self + + --- Triggers the FSM event "Stop" after a delay. Stops the STRATEGO and all its event handlers. + -- @function [parent=#STRATEGO] __Stop + -- @param #STRATEGO self + -- @param #number delay Delay in seconds. + + --- FSM Function OnAfterNodeEvent. A node changed coalition. + -- @function [parent=#STRATEGO] OnAfterNodeEvent + -- @param #STRATEGO self + -- @param #string From State. + -- @param #string Event Trigger. + -- @param #string To State. + -- @param Ops.OpsZone#OPSZONE OpsZone The OpsZone triggering the event. + -- @param #number Coalition The coalition of the new owner. + -- @return #STRATEGO self + return self end ---- [USER] Do initial setup and get ready. +--- [INTERNAL] FSM function for initial setup and getting ready. -- @param #STRATEGO self -- @return #STRATEGO self -function STRATEGO:Start() +function STRATEGO:onafterStart(From,Event,To) self:T(self.lid.."Start") self:AnalyseBases() self:AnalysePOIs(self.ports,self.portweight,"PORT") @@ -282,12 +325,27 @@ function STRATEGO:Start() for i=self.maxrunways,1,-1 do self:AnalyseRoutes(i,i*self.routefactor,self.colors[(i%3)+1],i) - --self:AnalyseRoutes(2,2*self.routefactor,self.colors[2],2) - --self:AnalyseRoutes(1,1*self.routefactor,self.colors[3],3) end self:AnalyseUnconnected(self.colors[4]) self:I(self.lid.."Advisory ready.") + + self:__Update(180) + return self +end + +--- [INTERNAL] Update knot association +-- @param #STRATEGO self +-- @return #STRATEGO self +function STRATEGO:onafterUpdate(From,Event,To) + self:T(self.lid.."Update") + + self:UpdateNodeCoalitions() + + if self:GetState() == "Running" then + self:__Update(180) + end + return self end @@ -308,6 +366,7 @@ end -- @param #boolean DrawZones If true, draw the OpsZones on the F10 map. -- @param #boolean MarkZones if true, mark the OpsZones on the F10 map (with further information). function STRATEGO:SetDebug(Debug,DrawZones,MarkZones) + self:T(self.lid.."SetDebug") self.debug = Debug self.drawzone = DrawZones self.markzone = MarkZones @@ -322,6 +381,7 @@ end -- @param #number RouteFactor Defines which weight each route between two defined nodes gets: Weight * RouteFactor. -- @return #STRATEGO self function STRATEGO:SetWeights(MaxRunways,PortWeight,POIWeight,RouteFactor) + self:T(self.lid.."SetWeights") self.portweight = PortWeight or 3 self.POIweight = POIWeight or 1 self.maxrunways = MaxRunways or 3 @@ -334,6 +394,7 @@ end -- @param #number NeutralBenefit Pointsm defaults to 100. -- @return #STRATEGO self function STRATEGO:SetNeutralBenefit(NeutralBenefit) + self:T(self.lid.."SetNeutralBenefit") self.NeutralBenefit = NeutralBenefit or 100 return self end @@ -344,6 +405,7 @@ end -- @param #number CaptureThreatlevel Threat level needed, can be 0..10, defaults to one. -- @return #STRATEGO self function STRATEGO:SetCaptureOptions(CaptureUnits,CaptureThreatlevel) + self:T(self.lid.."SetCaptureOptions") self.CaptureUnits = CaptureUnits or 3 self.CaptureThreatlevel = CaptureThreatlevel or 1 return self @@ -438,6 +500,15 @@ function STRATEGO:GetNewOpsZone(Zone,Coalition) opszone:SetDrawZone(self.drawzone) opszone:SetMarkZone(self.markzone) opszone:Start() + + local function Captured(opszone,coalition) + self:__NodeEvent(1,opszone,coalition) + end + + function opszone:OnBeforeCaptured(From,Event,To,Coalition) + Captured(opszone,Coalition) + end + return opszone end @@ -502,6 +573,7 @@ end -- @param #boolean Draw (Optional) If true, draw route on the F10 map. Defaukt false. -- @return #STRATEGO self function STRATEGO:AddRoutesManually(Startpoint,Endpoint,Color,Linetype,Draw) + self:T(self.lid.."AddRoutesManually") local fromto,tofrom = self:GetToFrom(Startpoint,Endpoint) local startcoordinate = self.airbasetable[Startpoint].coord local targetcoordinate = self.airbasetable[Endpoint].coord @@ -631,7 +703,7 @@ end -- @return #table Table of nodes. -- @return #number Weight The consolidated weight associated with the nodes. function STRATEGO:GetHighestWeightNodes() - self:T(self.lid.."GetHighestWeightBases") + self:T(self.lid.."GetHighestWeightNodes") local weight = 0 local airbases = {} for _name,_data in pairs(self.airbasetable) do @@ -649,7 +721,7 @@ end -- @return #table Table of nodes. -- @return #number Weight The consolidated weight associated with the nodes. function STRATEGO:GetNextHighestWeightNodes(Weight) - self:T(self.lid.."GetNextHighestWeightBases") + self:T(self.lid.."GetNextHighestWeightNodes") local weight = 0 local airbases = {} for _name,_data in pairs(self.airbasetable) do @@ -667,6 +739,7 @@ end -- @param #string Name. -- @return #number Weight The weight or 0 if not found. function STRATEGO:GetNodeWeight(Name) + self:T(self.lid.."GetNodeWeight") if Name and self.airbasetable[Name] then return self.airbasetable[Name].weight or 0 else @@ -679,6 +752,7 @@ end -- @param #string Name. -- @return #number Weight The base weight or 0 if not found. function STRATEGO:GetNodeBaseWeight(Name) + self:T(self.lid.."GetNodeBaseWeight") if Name and self.airbasetable[Name] then return self.airbasetable[Name].baseweight or 0 else @@ -691,6 +765,7 @@ end -- @param #string Name. -- @return #number Coalition The coalition. function STRATEGO:GetNodeCoalition(Name) + self:T(self.lid.."GetNodeCoalition") if Name and self.airbasetable[Name] then return self.airbasetable[Name].coalition or coalition.side.NEUTRAL else @@ -703,6 +778,7 @@ end -- @param #string Name. -- @return #string Type Type of the node, e.g. STRATEGO.Type.AIRBASE or nil if not found. function STRATEGO:GetNodeType(Name) + self:T(self.lid.."GetNodeType") if Name and self.airbasetable[Name] then return self.airbasetable[Name].type else @@ -715,6 +791,7 @@ end -- @param #string Name. -- @return Core.Zone#ZONE Zone The Zone of the node or nil if not found. function STRATEGO:GetNodeZone(Name) + self:T(self.lid.."GetNodeZone") if Name and self.airbasetable[Name] then return self.airbasetable[Name].zone else @@ -727,6 +804,7 @@ end -- @param #string Name. -- @return Ops.OpsZone#OPSZONE OpsZone The OpsZone of the node or nil if not found. function STRATEGO:GetNodeOpsZone(Name) + self:T(self.lid.."GetNodeOpsZone") if Name and self.airbasetable[Name] then return self.airbasetable[Name].opszone else @@ -739,6 +817,7 @@ end -- @param #string Name. -- @return Core.Point#COORDINATE Coordinate The Coordinate of the node or nil if not found. function STRATEGO:GetNodeCoordinate(Name) + self:T(self.lid.."GetNodeCoordinate") if Name and self.airbasetable[Name] then return self.airbasetable[Name].coord else @@ -751,6 +830,7 @@ end -- @param #string Name. -- @return #boolean Outcome function STRATEGO:IsAirbase(Name) + self:T(self.lid.."IsAirbase") if Name and self.airbasetable[Name] then return self.airbasetable[Name].type == STRATEGO.Type.AIRBASE else @@ -763,6 +843,7 @@ end -- @param #string Name. -- @return #boolean Outcome function STRATEGO:IsPort(Name) + self:T(self.lid.."IsPort") if Name and self.airbasetable[Name] then return self.airbasetable[Name].type == STRATEGO.Type.PORT else @@ -775,6 +856,7 @@ end -- @param #string Name. -- @return #boolean Outcome function STRATEGO:IsPOI(Name) + self:T(self.lid.."IsPOI") if Name and self.airbasetable[Name] then return self.airbasetable[Name].type == STRATEGO.Type.POI else @@ -787,6 +869,7 @@ end -- @param #string Name. -- @return #boolean Outcome function STRATEGO:IsFARP(Name) + self:T(self.lid.."IsFARP") if Name and self.airbasetable[Name] then return self.airbasetable[Name].type == STRATEGO.Type.FARP else @@ -799,6 +882,7 @@ end -- @param #string Name. -- @return #boolean Outcome function STRATEGO:IsShip(Name) + self:T(self.lid.."IsShip") if Name and self.airbasetable[Name] then return self.airbasetable[Name].type == STRATEGO.Type.SHIP else @@ -881,6 +965,7 @@ end -- @param #STRATEGO self -- @return #table of #STRATEGO.Target data points function STRATEGO:FindStrategicTargets() + self:T(self.lid.."FindStrategicTargets") local targets = {} for _,_data in pairs(self.airbasetable) do local data = _data -- #STRATEGO.Data @@ -924,6 +1009,7 @@ end -- @param #STRATEGO self -- @return #table of #STRATEGO.Target data points function STRATEGO:FindConsolidationTargets() + self:T(self.lid.."FindConsolidationTargets") local targets = {} for _,_data in pairs(self.airbasetable) do local data = _data -- #STRATEGO.Data @@ -972,6 +1058,7 @@ end -- @param #boolean Friends (optional) If true, find only friendly or neutral neighbors. -- @return #table Neighbors Table of #STRATEGO.DistData entries indexed by neighbor node names. function STRATEGO:FindNeighborNodes(Name,Enemies,Friends) + self:T(self.lid.."FindNeighborNodes") local neighbors = {} local name = string.gsub(Name,"[%p%s]",".") for _route,_data in pairs(self.disttable) do @@ -1008,7 +1095,8 @@ end -- @return #table Route Table of #string name entries of the route -- @return #boolean Complete If true, the route was found end-to-end. function STRATEGO:FindRoute(Start,End,Hops,Draw,Color,LineType) - self:I({Start,End,Hops}) + self:T(self.lid.."FindRoute") + --self:I({Start,End,Hops}) --local bases = UTILS.DeepCopy(self.airbasetable) local Route = {} local hops = Hops or 4 @@ -1090,6 +1178,7 @@ end -- @param #number Number of points to add. -- @return #STRATEGO self function STRATEGO:AddBudget(Number) + self:T(self.lid.."AddBudget") self.Budget = self.Budget + Number return self end @@ -1099,6 +1188,7 @@ end -- @param #number Number of points to subtract. -- @return #STRATEGO self function STRATEGO:SubtractBudget(Number) + self:T(self.lid.."SubtractBudget") self.Budget = self.Budget - Number return self end @@ -1107,6 +1197,7 @@ end -- @param #STRATEGO self -- @return #number budget function STRATEGO:GetBudget() + self:T(self.lid.."GetBudget") return self.Budget end @@ -1114,6 +1205,7 @@ end -- @param #STRATEGO self -- @return #table Target Table with #STRATEGO.Target data or nil if none found. function STRATEGO:FindAffordableStrategicTarget() + self:T(self.lid.."FindAffordableStrategicTarget") local targets = self:FindStrategicTargets() -- #table of #STRATEGO.Target local budget = self.Budget --local leftover = self.Budget @@ -1145,6 +1237,7 @@ end -- @param #STRATEGO self -- @return #table Target Table with #STRATEGO.Target data or nil if none found. function STRATEGO:FindAffordableConsolidationTarget() + self:T(self.lid.."FindAffordableConsolidationTarget") local targets = self:FindConsolidationTargets() -- #table of #STRATEGO.Target local budget = self.Budget --local leftover = self.Budget From ff951c69d93eb4f58c4596561a0e3cfe4439261e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 5 Jan 2024 15:45:40 +0100 Subject: [PATCH 06/20] Error dfix --- Moose Development/Moose/Sound/SRS.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Sound/SRS.lua b/Moose Development/Moose/Sound/SRS.lua index b470264eb..efbc67059 100644 --- a/Moose Development/Moose/Sound/SRS.lua +++ b/Moose Development/Moose/Sound/SRS.lua @@ -1196,8 +1196,8 @@ end -- @param Core.Point#COORDINATE Coordinate Coordinate. -- @return #MSRS self function MSRS:PlayTextExt(Text, Delay, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label, Coordinate) - self:T(( {Text, Delay, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label, Coordinate} ) - self:T((self.lid.."Backend "..self.backend) + self:T({Text, Delay, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label, Coordinate} ) + if Delay and Delay>0 then self:ScheduleOnce(Delay, MSRS.PlayTextExt, self, Text, 0, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label, Coordinate) else From ca9913e38b49e59f0905f69fa71572f31677d19a Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 5 Jan 2024 15:51:09 +0100 Subject: [PATCH 07/20] nu aber --- Moose Development/Moose/Sound/SRS.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Sound/SRS.lua b/Moose Development/Moose/Sound/SRS.lua index efbc67059..0d8a8f05b 100644 --- a/Moose Development/Moose/Sound/SRS.lua +++ b/Moose Development/Moose/Sound/SRS.lua @@ -1844,7 +1844,7 @@ end -- @param #MSRSQUEUE self -- @return #MSRSQUEUE self The MSRSQUEUE object. function MSRSQUEUE:Clear() - self:T((self.lid.."Clearing MSRSQUEUE") + self:T(self.lid.."Clearing MSRSQUEUE") self.queue={} return self end @@ -1958,7 +1958,7 @@ end -- @param #MSRSQUEUE self -- @param #MSRSQUEUE.Transmission transmission The transmission. function MSRSQUEUE:Broadcast(transmission) - self:T((self.lid.."Broadcast") + self:T(self.lid.."Broadcast") if transmission.frequency then transmission.msrs:PlayTextExt(transmission.text, nil, transmission.frequency, transmission.modulation, transmission.gender, transmission.culture, transmission.voice, transmission.volume, transmission.label, transmission.coordinate) @@ -2128,7 +2128,7 @@ function MSRSQUEUE:_CheckRadioQueue(delay) -- 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)) + self:T(self.lid..string.format("Broadcasting text=\"%s\" at T=%.3f", next.text, time)) -- Call SRS. self:Broadcast(next) From 84230e2360d2d89f2ad3560e38caef9427948d8c Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 5 Jan 2024 16:08:46 +0100 Subject: [PATCH 08/20] Fixes for 4th SRS Parameter --- Moose Development/Moose/Functional/Range.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 5b4d52623..3019fe29c 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -1211,16 +1211,18 @@ function RANGE:SetSRS(PathToSRS, Port, Coalition, Frequency, Modulation, Volume, self.useSRS=true - self.controlmsrs=MSRS:New(PathToSRS or MSRS.path, Frequency or 256, Modulation or radio.modulation.AM, Volume or 1.0) + self.controlmsrs=MSRS:New(PathToSRS or MSRS.path, Frequency or 256, Modulation or radio.modulation.AM) self.controlmsrs:SetPort(Port or MSRS.port) self.controlmsrs:SetCoalition(Coalition or coalition.side.BLUE) self.controlmsrs:SetLabel("RANGEC") + self.controlmsrs:SetVolume(Volume or 1.0) self.controlsrsQ = MSRSQUEUE:New("CONTROL") - self.instructmsrs=MSRS:New(PathToSRS or MSRS.path, Frequency or 305, Modulation or radio.modulation.AM, Volume or 1.0) + self.instructmsrs=MSRS:New(PathToSRS or MSRS.path, Frequency or 305, Modulation or radio.modulation.AM) self.instructmsrs:SetPort(Port or MSRS.port) self.instructmsrs:SetCoalition(Coalition or coalition.side.BLUE) self.instructmsrs:SetLabel("RANGEI") + self.instructmsrs:SetVolume(Volume or 1.0) self.instructsrsQ = MSRSQUEUE:New("INSTRUCT") if PathToGoogleKey then From 048ab6acfea8d9dd44ee025113f11ffd9d84e2db Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 5 Jan 2024 16:09:05 +0100 Subject: [PATCH 09/20] Fixes for 4th SRS Parameter --- Moose Development/Moose/Functional/AICSAR.lua | 6 +++--- Moose Development/Moose/Functional/Autolase.lua | 3 ++- Moose Development/Moose/Functional/Range.lua | 6 ++++-- Moose Development/Moose/Ops/Airboss.lua | 1 + Moose Development/Moose/Ops/PlayerRecce.lua | 3 ++- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Functional/AICSAR.lua b/Moose Development/Moose/Functional/AICSAR.lua index f2bb13c3e..2dedc74c2 100644 --- a/Moose Development/Moose/Functional/AICSAR.lua +++ b/Moose Development/Moose/Functional/AICSAR.lua @@ -574,7 +574,7 @@ function AICSAR:SetSRSTTSRadio(OnOff,Path,Frequency,Modulation,Port,Voice,Cultur self.SRSModulation = Modulation or radio.modulation.AM self.SRSPort = Port or 5002 if OnOff then - self.SRS = MSRS:New(Path,Frequency,Modulation,1) + self.SRS = MSRS:New(Path,Frequency,Modulation) self.SRS:SetPort(self.SRSPort) self.SRS:SetCoalition(self.coalition) self.SRS:SetLabel("ACSR") @@ -600,7 +600,7 @@ end function AICSAR:SetPilotTTSVoice(Voice,Culture,Gender) self:T(self.lid .. "SetPilotTTSVoice") self.SRSPilotVoice = true - self.SRSPilot = MSRS:New(self.SRSPath,self.SRSFrequency,self.SRSModulation,1) + self.SRSPilot = MSRS:New(self.SRSPath,self.SRSFrequency,self.SRSModulation) self.SRSPilot:SetCoalition(self.coalition) self.SRSPilot:SetVoice(Voice) self.SRSPilot:SetCulture(Culture or "en-US") @@ -624,7 +624,7 @@ end function AICSAR:SetOperatorTTSVoice(Voice,Culture,Gender) self:T(self.lid .. "SetOperatorTTSVoice") self.SRSOperatorVoice = true - self.SRSOperator = MSRS:New(self.SRSPath,self.SRSFrequency,self.SRSModulation,1) + self.SRSOperator = MSRS:New(self.SRSPath,self.SRSFrequency,self.SRSModulation) self.SRSOperator:SetCoalition(self.coalition) self.SRSOperator:SetVoice(Voice) self.SRSOperator:SetCulture(Culture or "en-GB") diff --git a/Moose Development/Moose/Functional/Autolase.lua b/Moose Development/Moose/Functional/Autolase.lua index e593086b3..735706150 100644 --- a/Moose Development/Moose/Functional/Autolase.lua +++ b/Moose Development/Moose/Functional/Autolase.lua @@ -462,7 +462,7 @@ function AUTOLASE:SetUsingSRS(OnOff,Path,Frequency,Modulation,Label,Gender,Cultu self.Volume = Volume or 1.0 self.Label = Label -- set up SRS - self.SRS = MSRS:New(self.SRSPath,self.SRSFreq,self.SRSMod,self.Volume) + self.SRS = MSRS:New(self.SRSPath,self.SRSFreq,self.SRSMod) self.SRS:SetCoalition(self.coalition) self.SRS:SetLabel(self.MenuName or self.Name) self.SRS:SetGender(self.Gender) @@ -470,6 +470,7 @@ function AUTOLASE:SetUsingSRS(OnOff,Path,Frequency,Modulation,Label,Gender,Cultu self.SRS:SetPort(self.Port) self.SRS:SetVoice(self.Voice) self.SRS:SetCoalition(self.coalition) + self.SRS:SetVolume(Volume) if self.PathToGoogleKey then self.SRS:SetGoogle(self.PathToGoogleKey) end diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 5b4d52623..3019fe29c 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -1211,16 +1211,18 @@ function RANGE:SetSRS(PathToSRS, Port, Coalition, Frequency, Modulation, Volume, self.useSRS=true - self.controlmsrs=MSRS:New(PathToSRS or MSRS.path, Frequency or 256, Modulation or radio.modulation.AM, Volume or 1.0) + self.controlmsrs=MSRS:New(PathToSRS or MSRS.path, Frequency or 256, Modulation or radio.modulation.AM) self.controlmsrs:SetPort(Port or MSRS.port) self.controlmsrs:SetCoalition(Coalition or coalition.side.BLUE) self.controlmsrs:SetLabel("RANGEC") + self.controlmsrs:SetVolume(Volume or 1.0) self.controlsrsQ = MSRSQUEUE:New("CONTROL") - self.instructmsrs=MSRS:New(PathToSRS or MSRS.path, Frequency or 305, Modulation or radio.modulation.AM, Volume or 1.0) + self.instructmsrs=MSRS:New(PathToSRS or MSRS.path, Frequency or 305, Modulation or radio.modulation.AM) self.instructmsrs:SetPort(Port or MSRS.port) self.instructmsrs:SetCoalition(Coalition or coalition.side.BLUE) self.instructmsrs:SetLabel("RANGEI") + self.instructmsrs:SetVolume(Volume or 1.0) self.instructsrsQ = MSRSQUEUE:New("INSTRUCT") if PathToGoogleKey then diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index d7a467e44..28ccad0c9 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -3072,6 +3072,7 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum self.SRS:SetPort(Port or 5002) self.SRS:SetLabel(self.AirbossRadio.alias or "AIRBOSS") self.SRS:SetCoordinate(self.carrier:GetCoordinate()) + self.SRS:SetVolume(Volume) --self.SRS:SetModulations(Modulations) if GoogleCreds then self.SRS:SetGoogle(GoogleCreds) diff --git a/Moose Development/Moose/Ops/PlayerRecce.lua b/Moose Development/Moose/Ops/PlayerRecce.lua index 2561fa837..5a87c3be1 100644 --- a/Moose Development/Moose/Ops/PlayerRecce.lua +++ b/Moose Development/Moose/Ops/PlayerRecce.lua @@ -1508,13 +1508,14 @@ function PLAYERRECCE:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,V self.Modulation = Modulation or {radio.modulation.FM,radio.modulation.AM} -- self.BCModulation = self.Modulation -- set up SRS - self.SRS=MSRS:New(self.PathToSRS,self.Frequency,self.Modulation,self.Volume) + self.SRS=MSRS:New(self.PathToSRS,self.Frequency,self.Modulation) self.SRS:SetCoalition(self.Coalition) self.SRS:SetLabel(self.MenuName or self.Name) self.SRS:SetGender(self.Gender) self.SRS:SetCulture(self.Culture) self.SRS:SetPort(self.Port) self.SRS:SetVoice(self.Voice) + self.SRS:SetVolume(self.Volume) if self.PathToGoogleKey then self.SRS:SetGoogle(self.PathToGoogleKey) end From 4696569f8377cd8c94970bc1253c3f1722b16583 Mon Sep 17 00:00:00 2001 From: kaltokri Date: Sat, 6 Jan 2024 12:22:02 +0100 Subject: [PATCH 10/20] Added mission check for desanitized io --- .../Moose Templates/Moose_Static_Loader.lua | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/Moose Setup/Moose Templates/Moose_Static_Loader.lua b/Moose Setup/Moose Templates/Moose_Static_Loader.lua index 90098d916..788682234 100644 --- a/Moose Setup/Moose Templates/Moose_Static_Loader.lua +++ b/Moose Setup/Moose Templates/Moose_Static_Loader.lua @@ -5,37 +5,41 @@ -- This method is used by Moose developers and not mission builders. ModuleLoader = 'Scripts/Moose/Modules.lua' -local f=io.open(ModuleLoader,"r") -if f~=nil then - io.close(f) +if io then + local f=io.open(ModuleLoader,"r") + if f~=nil then + io.close(f) - env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' ) + env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' ) - local base = _G + local base = _G - __Moose = {} + __Moose = {} - __Moose.Include = function( IncludeFile ) - if not __Moose.Includes[ IncludeFile ] then - __Moose.Includes[IncludeFile] = IncludeFile - local f = assert( base.loadfile( IncludeFile ) ) - if f == nil then - error ("Moose: Could not load Moose file " .. IncludeFile ) - else - env.info( "Moose: " .. IncludeFile .. " dynamically loaded." ) - return f() + __Moose.Include = function( IncludeFile ) + if not __Moose.Includes[ IncludeFile ] then + __Moose.Includes[IncludeFile] = IncludeFile + local f = assert( base.loadfile( IncludeFile ) ) + if f == nil then + error ("Moose: Could not load Moose file " .. IncludeFile ) + else + env.info( "Moose: " .. IncludeFile .. " dynamically loaded." ) + return f() + end end end + + __Moose.Includes = {} + + __Moose.Include( 'Scripts/Moose/Modules.lua' ) + BASE:TraceOnOff( true ) + env.info( '*** MOOSE INCLUDE END *** ' ) + + -- Skip the static part of this file completly + do return end end - - __Moose.Includes = {} - - __Moose.Include( 'Scripts/Moose/Modules.lua' ) - BASE:TraceOnOff( true ) - env.info( '*** MOOSE INCLUDE END *** ' ) - - -- Skip the static part of this file completly - do return end +else + env.info( '*** MOOSE DYNAMIC INCLUDE NOT POSSIBLE (Desanitize io to use it) *** ' ) end -- Individual Moose files are not found. Use the static code below. From fce7b070145372a656fa2a842a78486334ac4d6e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 6 Jan 2024 18:21:35 +0100 Subject: [PATCH 11/20] Fixes for MSRS changes --- Moose Development/Moose/Core/Database.lua | 16 +++++-- Moose Development/Moose/Core/Message.lua | 58 +++++++++++++---------- Moose Development/Moose/Ops/ATIS.lua | 35 +++++++++----- 3 files changed, 69 insertions(+), 40 deletions(-) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index ac290aa2f..14b99fc76 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -1343,9 +1343,17 @@ function DATABASE:_RegisterAirbase(airbase) -- Unique ID. local airbaseUID=airbase:GetID(true) - + + local typename = airbase:GetTypeName() + + local category = airbase.category + + if category == Airbase.Category.SHIP and typename == "FARP_SINGLE_01" then + category = Airbase.Category.HELIPAD + end + -- Debug output. - local text=string.format("Register %s: %s (UID=%d), Runways=%d, Parking=%d [", AIRBASE.CategoryName[airbase.category], tostring(DCSAirbaseName), airbaseUID, #airbase.runways, airbase.NparkingTotal) + local text=string.format("Register %s: %s (UID=%d), Runways=%d, Parking=%d [", AIRBASE.CategoryName[category], tostring(DCSAirbaseName), airbaseUID, #airbase.runways, airbase.NparkingTotal) for _,terminalType in pairs(AIRBASE.TerminalType) do if airbase.NparkingTerminal and airbase.NparkingTerminal[terminalType] then text=text..string.format("%d=%d ", terminalType, airbase.NparkingTerminal[terminalType]) @@ -1893,7 +1901,7 @@ end --- Add a flight control to the data base. -- @param #DATABASE self --- @param Ops.FlightControl#FLIGHTCONTROL flightcontrol +-- @param OPS.FlightControl#FLIGHTCONTROL flightcontrol function DATABASE:AddFlightControl(flightcontrol) self:F2( { flightcontrol } ) self.FLIGHTCONTROLS[flightcontrol.airbasename]=flightcontrol @@ -1902,7 +1910,7 @@ end --- Get a flight control object from the data base. -- @param #DATABASE self -- @param #string airbasename Name of the associated airbase. --- @return Ops.FlightControl#FLIGHTCONTROL The FLIGHTCONTROL object.s +-- @return OPS.FlightControl#FLIGHTCONTROL The FLIGHTCONTROL object.s function DATABASE:GetFlightControl(airbasename) return self.FLIGHTCONTROLS[airbasename] end diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index ce95f03c8..31669d458 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -459,14 +459,14 @@ end _MESSAGESRS = {} ---- Set up MESSAGE generally to allow Text-To-Speech via SRS and TTS functions. --- @param #string PathToSRS Path to SRS Folder, defaults to "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone". --- @param #number Port Port number of SRS, defaults to 5002. --- @param #string PathToCredentials (optional) Path to credentials file for e.g. Google. +--- Set up MESSAGE generally to allow Text-To-Speech via SRS and TTS functions. `SetMSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible. +-- @param #string PathToSRS (optional) Path to SRS Folder, defaults to "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone" or your configuration file setting. +-- @param #number Port Port (optional) number of SRS, defaults to 5002 or your configuration file setting. +-- @param #string PathToCredentials (optional) Path to credentials file for Google. -- @param #number Frequency Frequency in MHz. Can also be given as a #table of frequencies. -- @param #number Modulation Modulation, i.e. radio.modulation.AM or radio.modulation.FM. Can also be given as a #table of modulations. --- @param #string Gender (optional) Gender, i.e. "male" or "female", defaults to "female". --- @param #string Culture (optional) Culture, e.g. "en-US", defaults to "en-GB" +-- @param #string Gender (optional) Gender, i.e. "male" or "female", defaults to "female" or your configuration file setting. +-- @param #string Culture (optional) Culture, e.g. "en-US", defaults to "en-GB" or your configuration file setting. -- @param #string Voice (optional) Voice. Will override gender and culture settings, e.g. MSRS.Voices.Microsoft.Hazel or MSRS.Voices.Google.Standard.de_DE_Standard_D. Hint on Microsoft voices - working voices are limited to Hedda, Hazel, David, Zira and Hortense. **Must** be installed on your Desktop or Server! -- @param #number Coalition (optional) Coalition, can be coalition.side.RED, coalition.side.BLUE or coalition.side.NEUTRAL. Defaults to coalition.side.NEUTRAL. -- @param #number Volume (optional) Volume, can be between 0.0 and 1.0 (loudest). @@ -480,42 +480,50 @@ _MESSAGESRS = {} -- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS() -- function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,Gender,Culture,Voice,Coalition,Volume,Label,Coordinate) - _MESSAGESRS.MSRS = MSRS:New(PathToSRS,Frequency or 243,Modulation or radio.modulation.AM) - _MESSAGESRS.frequency = Frequency - _MESSAGESRS.modulation = Modulation or radio.modulation.AM + _MESSAGESRS.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" - _MESSAGESRS.MSRS:SetCoalition(Coalition or coalition.side.NEUTRAL) - _MESSAGESRS.coalition = Coalition or coalition.side.NEUTRAL + _MESSAGESRS.frequency = Frequency or MSRS.frequencies or 243 + _MESSAGESRS.modulation = Modulation or MSRS.modulations or radio.modulation.AM + _MESSAGESRS.MSRS = MSRS:New(_MESSAGESRS.PathToSRS,_MESSAGESRS.frequency, _MESSAGESRS.modulation) + + _MESSAGESRS.coalition = Coalition or MSRS.coalition or coalition.side.NEUTRAL + _MESSAGESRS.MSRS:SetCoalition(_MESSAGESRS.coalition) + _MESSAGESRS.coordinate = Coordinate - _MESSAGESRS.MSRS:SetCoordinate(Coordinate) + if Coordinate then + _MESSAGESRS.MSRS:SetCoordinate(Coordinate) + end + + _MESSAGESRS.Culture = Culture or MSRS.culture or "en-GB" _MESSAGESRS.MSRS:SetCulture(Culture) - _MESSAGESRS.Culture = Culture or "en-GB" + _MESSAGESRS.Gender = Gender or MSRS.gender or "female" _MESSAGESRS.MSRS:SetGender(Gender) - _MESSAGESRS.Gender = Gender or "female" - _MESSAGESRS.MSRS:SetProviderOptionsGoogle(PathToCredentials) - - _MESSAGESRS.MSRS:SetLabel(Label or "MESSAGE") - _MESSAGESRS.label = Label or "MESSAGE" - - _MESSAGESRS.MSRS:SetPort(Port or 5002) - _MESSAGESRS.port = Port or 5002 + if PathToCredentials then + _MESSAGESRS.MSRS:SetProviderOptionsGoogle(PathToCredentials) + end - _MESSAGESRS.volume = Volume or 1 + _MESSAGESRS.label = Label or MSRS.Label or "MESSAGE" + _MESSAGESRS.MSRS:SetLabel(Label or "MESSAGE") + + _MESSAGESRS.port = Port or MSRS.port or 5002 + _MESSAGESRS.MSRS:SetPort(Port or 5002) + + _MESSAGESRS.volume = Volume or MSRS.volume or 1 _MESSAGESRS.MSRS:SetVolume(_MESSAGESRS.volume) if Voice then _MESSAGESRS.MSRS:SetVoice(Voice) end - _MESSAGESRS.voice = Voice --or MSRS.Voices.Microsoft.Hedda + _MESSAGESRS.voice = Voice or MSRS.voice --or MSRS.Voices.Microsoft.Hedda - _MESSAGESRS.SRSQ = MSRSQUEUE:New(Label or "MESSAGE") + _MESSAGESRS.SRSQ = MSRSQUEUE:New(_MESSAGESRS.label) end ---- Sends a message via SRS. +--- Sends a message via SRS. `ToSRS()` will try to use as many attributes configured with @{Core.Message#MESSAGE.SetMSRS}() and @{Sound.SRS#MSRS.LoadConfigFile}() as possible. -- @param #MESSAGE self -- @param #number frequency (optional) Frequency in MHz. Can also be given as a #table of frequencies. Only needed if you want to override defaults set with `MESSAGE.SetMSRS()` for this one setting. -- @param #number modulation (optional) Modulation, i.e. radio.modulation.AM or radio.modulation.FM. Can also be given as a #table of modulations. Only needed if you want to override defaults set with `MESSAGE.SetMSRS()` for this one setting. diff --git a/Moose Development/Moose/Ops/ATIS.lua b/Moose Development/Moose/Ops/ATIS.lua index 064ab1880..0fcf939b5 100644 --- a/Moose Development/Moose/Ops/ATIS.lua +++ b/Moose Development/Moose/Ops/ATIS.lua @@ -1526,7 +1526,7 @@ function ATIS:MarkRunways( markall ) end end ---- Use SRS Simple-Text-To-Speech for transmissions. No sound files necessary. +--- Use SRS Simple-Text-To-Speech for transmissions. No sound files necessary.`SetSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible. -- @param #ATIS self -- @param #string PathToSRS Path to SRS directory (only necessary if SRS exe backend is used). -- @param #string Gender Gender: "male" or "female" (default). @@ -1536,25 +1536,38 @@ end -- @param #string GoogleKey Path to Google JSON-Key (SRS exe backend) or Google API key (DCS-gRPC backend). -- @return #ATIS self function ATIS:SetSRS(PathToSRS, Gender, Culture, Voice, Port, GoogleKey) - if PathToSRS or MSRS.path then + --if PathToSRS or MSRS.path then self.useSRS=true - self.msrs=MSRS:New(PathToSRS, self.frequency, self.modulation) - self.msrs:SetGender(Gender) - self.msrs:SetCulture(Culture) - self.msrs:SetVoice(Voice) - self.msrs:SetPort(Port) + + local path = PathToSRS or MSRS.path + local gender = Gender or MSRS.gender + local culture = Culture or MSRS.culture + local voice = Voice or MSRS.voice + local port = Port or MSRS.port or 5002 + + self.msrs=MSRS:New(path, self.frequency, self.modulation) + self.msrs:SetGender(gender) + self.msrs:SetCulture(culture) + self.msrs:SetPort(port) self.msrs:SetCoalition(self:GetCoalition()) self.msrs:SetLabel("ATIS") - self.msrs:SetGoogle(GoogleKey) + if GoogleKey then + self.msrs:SetProviderOptionsGoogle(GoogleKey,GoogleKey) + end + -- Pre-configured Google? + if self.msrs:GetProvider() == MSRS.Provider.GOOGLE then + voice = Voice or MSRS.poptions.gcloud.voice + end + self.msrs:SetVoice(voice) self.msrs:SetCoordinate(self.airbase:GetCoordinate()) self.msrsQ = MSRSQUEUE:New("ATIS") self.msrsQ:SetTransmitOnlyWithPlayers(self.TransmitOnlyWithPlayers) if self.dTQueueCheck<=10 then self:SetQueueUpdateTime(90) end - else - self:E(self.lid..string.format("ERROR: No SRS path specified!")) - end + --else + --self:E(self.lid..string.format("ERROR: No SRS path specified!")) + --end return self end From 729c1f5e3393151945fdc8243e17297998a9293a Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 6 Jan 2024 18:22:18 +0100 Subject: [PATCH 12/20] Fixes for MSRS changes #STRATEGO * fix for an AB not having a zone --- .../Moose/Functional/Stratego.lua | 7 +++-- Moose Development/Moose/Ops/Awacs.lua | 27 +++++++++++-------- Moose Development/Moose/Ops/PlayerTask.lua | 24 ++++++++++------- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/Moose Development/Moose/Functional/Stratego.lua b/Moose Development/Moose/Functional/Stratego.lua index f8c9e8c07..43752ea7e 100644 --- a/Moose Development/Moose/Functional/Stratego.lua +++ b/Moose Development/Moose/Functional/Stratego.lua @@ -176,7 +176,7 @@ STRATEGO = { debug = false, drawzone = false, markzone = false, - version = "0.2.2", + version = "0.2.3", portweight = 3, POIweight = 1, maxrunways = 3, @@ -431,6 +431,9 @@ function STRATEGO:AnalyseBases() local numrwys = #runways if numrwys >= 1 then numrwys = numrwys * 0.5 end local abzone = ab:GetZone() + if not abzone then + abzone = ZONE_RADIUS:New(abname,ab:GetVec2(),500) + end local coa = ab:GetCoalition() + 1 local abtype = "AIRBASE" if ab:IsShip() then @@ -441,7 +444,7 @@ function STRATEGO:AnalyseBases() numrwys = 1 abtype = "FARP" end - local coord = abzone:GetCoordinate() + local coord = ab:GetCoordinate() if debug then abzone:DrawZone(-1,colors[coa],1,colors[coa],0.3,1) coord:TextToAll(tostring(numrwys),-1,{0,0,0},1,colors[coa],0.3,20) diff --git a/Moose Development/Moose/Ops/Awacs.lua b/Moose Development/Moose/Ops/Awacs.lua index 583a7f30f..4202e253f 100644 --- a/Moose Development/Moose/Ops/Awacs.lua +++ b/Moose Development/Moose/Ops/Awacs.lua @@ -2071,7 +2071,7 @@ function AWACS:AddGroupToDetection(Group) return self end ---- [User] Set AWACS SRS TTS details - see @{Sound.SRS} for details +--- [User] Set AWACS SRS TTS details - see @{Sound.SRS} for details. `SetSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible. -- @param #AWACS self -- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone" -- @param #string Gender Defaults to "male" @@ -2080,16 +2080,16 @@ end -- @param #string Voice (Optional) Use a specifc voice with the @{Sound.SRS#SetVoice} function, e.g, `:SetVoice("Microsoft Hedda Desktop")`. -- Note that this must be installed on your windows system. Can also be Google voice types, if you are using Google TTS. -- @param #number Volume Volume - between 0.0 (silent) and 1.0 (loudest) --- @param #string PathToGoogleKey Path to your google key if you want to use google TTS --- @param #string AccessKey Your Google API access key. This is necessary if DCS-gRPC is used as backend. +-- @param #string PathToGoogleKey (Optional) Path to your google key if you want to use google TTS; if you use a config file for MSRS, hand in nil here. +-- @param #string AccessKey (Optional) Your Google API access key. This is necessary if DCS-gRPC is used as backend; if you use a config file for MSRS, hand in nil here. -- @return #AWACS self function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey) self:T(self.lid.."SetSRS") - self.PathToSRS = PathToSRS or "C:\\Program Files\\DCS-SimpleRadio-Standalone" - self.Gender = Gender or "male" - self.Culture = Culture or "en-US" - self.Port = Port or 5002 - self.Voice = Voice + self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" + self.Gender = Gender or MSRS.gender or "male" + self.Culture = Culture or MSRS.culture or "en-US" + self.Port = Port or MSRS.port or 5002 + self.Voice = Voice or MSRS.voice self.PathToGoogleKey = PathToGoogleKey self.AccessKey = AccessKey self.Volume = Volume or 1.0 @@ -2098,7 +2098,6 @@ function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey self.AwacsSRS:SetCoalition(self.coalition) self.AwacsSRS:SetGender(self.Gender) self.AwacsSRS:SetCulture(self.Culture) - self.AwacsSRS:SetVoice(self.Voice) self.AwacsSRS:SetPort(self.Port) self.AwacsSRS:SetLabel("AWACS") self.AwacsSRS:SetVolume(Volume) @@ -2106,7 +2105,13 @@ function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey --self.AwacsSRS:SetGoogle(self.PathToGoogleKey) self.AwacsSRS:SetProviderOptionsGoogle(self.PathToGoogleKey,self.AccessKey) end - + -- Pre-configured Google? + if self.AwacsSRS:GetProvider() == MSRS.Provider.GOOGLE then + self.PathToGoogleKey = MSRS.poptions.gcloud.credentials + self.Voice = Voice or MSRS.poptions.gcloud.voice + self.AccessKey = AccessKey or MSRS.poptions.gcloud.key + end + self.AwacsSRS:SetVoice(self.Voice) return self end @@ -3669,7 +3674,7 @@ function AWACS:_CheckInAI(FlightGroup,Group,AuftragsNr) CAPVoice = self.CapVoices[math.floor(math.random(1,10))] end - FlightGroup:SetSRS(self.PathToSRS,self.CAPGender,self.CAPCulture,CAPVoice,self.Port,self.PathToGoogleKey,"FLIGHT") + FlightGroup:SetSRS(self.PathToSRS,self.CAPGender,self.CAPCulture,CAPVoice,self.Port,self.PathToGoogleKey,"FLIGHT",1) local checkai = self.gettext:GetEntry("CHECKINAI",self.locale) text = string.format(checkai,self.callsigntxt, managedgroup.CallSign, self.CAPTimeOnStation, self.AOName) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 79ffe5803..855b954ca 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -3993,7 +3993,7 @@ function PLAYERTASKCONTROLLER:SetupIntel(RecceName) return self end ---- [User] Set SRS TTS details - see @{Sound.SRS} for details +--- [User] Set SRS TTS details - see @{Sound.SRS} for details.`SetSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible. -- @param #PLAYERTASKCONTROLLER self -- @param #number Frequency Frequency to be used. Can also be given as a table of multiple frequencies, e.g. 271 or {127,251}. There needs to be exactly the same number of modulations! -- @param #number Modulation Modulation to be used. Can also be given as a table of multiple modulations, e.g. radio.modulation.AM or {radio.modulation.FM,radio.modulation.AM}. There needs to be exactly the same number of frequencies! @@ -4004,17 +4004,17 @@ end -- @param #string Voice (Optional) Use a specifc voice with the @{Sound.SRS#SetVoice} function, e.g, `:SetVoice("Microsoft Hedda Desktop")`. -- Note that this must be installed on your windows system. Can also be Google voice types, if you are using Google TTS. -- @param #number Volume (Optional) Volume - between 0.0 (silent) and 1.0 (loudest) --- @param #string PathToGoogleKey (Optional) Path to your google key if you want to use google TTS --- @param #string AccessKey Your Google API access key. This is necessary if DCS-gRPC is used as backend. +-- @param #string PathToGoogleKey (Optional) Path to your google key if you want to use google TTS; if you use a config file for MSRS, hand in nil here. +-- @param #string AccessKey (Optional) Your Google API access key. This is necessary if DCS-gRPC is used as backend; if you use a config file for MSRS, hand in nil here. -- @param Core.Point#COORDINATE Coordinate Coordinate from which the controller radio is sending -- @return #PLAYERTASKCONTROLLER self function PLAYERTASKCONTROLLER:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey,Coordinate) self:T(self.lid.."SetSRS") - self.PathToSRS = PathToSRS or "C:\\Program Files\\DCS-SimpleRadio-Standalone" -- - self.Gender = Gender or "male" -- - self.Culture = Culture or "en-US" -- - self.Port = Port or 5002 -- - self.Voice = Voice -- + self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" -- + self.Gender = Gender or MSRS.gender or "male" -- + self.Culture = Culture or MSRS.culture or "en-US" -- + self.Port = Port or MSRS.port or 5002 -- + self.Voice = Voice or MSRS.voice self.PathToGoogleKey = PathToGoogleKey -- self.AccessKey = AccessKey self.Volume = Volume or 1.0 -- @@ -4030,15 +4030,21 @@ function PLAYERTASKCONTROLLER:SetSRS(Frequency,Modulation,PathToSRS,Gender,Cultu self.SRS:SetGender(self.Gender) self.SRS:SetCulture(self.Culture) self.SRS:SetPort(self.Port) - self.SRS:SetVoice(self.Voice) self.SRS:SetVolume(self.Volume) if self.PathToGoogleKey then --self.SRS:SetGoogle(self.PathToGoogleKey) self.SRS:SetProviderOptionsGoogle(self.PathToGoogleKey,self.AccessKey) + end + -- Pre-configured Google? + if self.SRS:GetProvider() == MSRS.Provider.GOOGLE then + self.PathToGoogleKey = MSRS.poptions.gcloud.credentials + self.Voice = Voice or MSRS.poptions.gcloud.voice + self.AccessKey = AccessKey or MSRS.poptions.gcloud.key end if Coordinate then self.SRS:SetCoordinate(Coordinate) end + self.SRS:SetVoice(self.Voice) self.SRSQueue = MSRSQUEUE:New(self.MenuName or self.Name) self.SRSQueue:SetTransmitOnlyWithPlayers(self.TransmitOnlyWithPlayers) return self From 9280a1224d25d1e229e2a55b77af493ee6c462b0 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 7 Jan 2024 13:23:50 +0100 Subject: [PATCH 13/20] MSRS additions --- Moose Development/Moose/Core/Message.lua | 1 + Moose Development/Moose/Ops/ATIS.lua | 17 ++++++++++++++++- Moose Development/Moose/Sound/RadioQueue.lua | 6 ++++-- Moose Development/Moose/Sound/SRS.lua | 14 +++++++++----- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index 31669d458..1ffcb1516 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -505,6 +505,7 @@ function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,G if PathToCredentials then _MESSAGESRS.MSRS:SetProviderOptionsGoogle(PathToCredentials) + _MESSAGESRS.MSRS:SetProvider(MSRS.Provider.GOOGLE) end _MESSAGESRS.label = Label or MSRS.Label or "MESSAGE" diff --git a/Moose Development/Moose/Ops/ATIS.lua b/Moose Development/Moose/Ops/ATIS.lua index 0fcf939b5..d07c751f1 100644 --- a/Moose Development/Moose/Ops/ATIS.lua +++ b/Moose Development/Moose/Ops/ATIS.lua @@ -1553,9 +1553,10 @@ function ATIS:SetSRS(PathToSRS, Gender, Culture, Voice, Port, GoogleKey) self.msrs:SetLabel("ATIS") if GoogleKey then self.msrs:SetProviderOptionsGoogle(GoogleKey,GoogleKey) + self.msrs:SetProvider(MSRS.Provider.GOOGLE) end -- Pre-configured Google? - if self.msrs:GetProvider() == MSRS.Provider.GOOGLE then + if (not GoogleKey) and self.msrs:GetProvider() == MSRS.Provider.GOOGLE then voice = Voice or MSRS.poptions.gcloud.voice end self.msrs:SetVoice(voice) @@ -1571,6 +1572,20 @@ function ATIS:SetSRS(PathToSRS, Gender, Culture, Voice, Port, GoogleKey) return self end +--- Set an alternative provider to the one set in your MSRS configuration file. +-- @param #ATIS self +-- @param #string Provider The provider to use. Known providers are: `MSRS.Provider.WINDOWS` and `MSRS.Provider.GOOGLE` +-- @return #ATIS self +function ATIS:SetSRSProvider(Provider) + self:T(self.lid.."SetSRSProvider") + if self.msrs then + self.msrs:SetProvider(Provider) + else + MESSAGE:New(self.lid.."Set up SRS first before trying to change the provider!",30,"ATIS"):ToAll():ToLog() + end + return self +end + --- Set the time interval between radio queue updates. -- @param #ATIS self -- @param #number TimeInterval Interval in seconds. Default 5 sec. diff --git a/Moose Development/Moose/Sound/RadioQueue.lua b/Moose Development/Moose/Sound/RadioQueue.lua index 80ac49752..7f320cedc 100644 --- a/Moose Development/Moose/Sound/RadioQueue.lua +++ b/Moose Development/Moose/Sound/RadioQueue.lua @@ -183,8 +183,10 @@ end -- @param #number Port SRS port. Default 5002. -- @return #RADIOQUEUE self The RADIOQUEUE object. function RADIOQUEUE:SetSRS(PathToSRS, Port) - self.msrs=MSRS:New(PathToSRS, self.frequency/1000000, self.modulation) - self.msrs:SetPort(Port) + local path = PathToSRS or MSRS.path + local port = Port or MSRS.port + self.msrs=MSRS:New(path, self.frequency/1000000, self.modulation) + self.msrs:SetPort(port) return self end diff --git a/Moose Development/Moose/Sound/SRS.lua b/Moose Development/Moose/Sound/SRS.lua index 0d8a8f05b..b0ac95894 100644 --- a/Moose Development/Moose/Sound/SRS.lua +++ b/Moose Development/Moose/Sound/SRS.lua @@ -918,12 +918,16 @@ end -- @param #string Provider -- @return #MSRS self function MSRS:SetProvider(Provider) - self:F( {Provider=Provider} ) - self.provider = Provider or MSRS.Provider.WINDOWS - return self + BASE:F( {Provider=Provider} ) + if self then + self.provider = Provider or MSRS.Provider.WINDOWS + return self + else + MSRS.provider = Provider or MSRS.Provider.WINDOWS + end + return end - --- Get provider. -- @param #MSRS self -- @return #MSRS self @@ -940,7 +944,7 @@ end -- @param #string Region Region to use. -- @return #MSRS.ProviderOptions Provider optionas table. function MSRS:SetProviderOptions(Provider, CredentialsFile, AccessKey, SecretKey, Region) - self:F( {Provider, CredentialsFile, AccessKey, SecretKey, Region} ) + BASE:F( {Provider, CredentialsFile, AccessKey, SecretKey, Region} ) local option=MSRS._CreateProviderOptions(Provider, CredentialsFile, AccessKey, SecretKey, Region) if self then From 06c3ca00793265f72f6956c3a37fe131e721d53c Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 7 Jan 2024 13:25:32 +0100 Subject: [PATCH 14/20] MSRS additions --- Moose Development/Moose/Ops/Awacs.lua | 8 ++-- Moose Development/Moose/Ops/FlightControl.lua | 37 +++++++++++-------- Moose Development/Moose/Ops/OpsGroup.lua | 9 +++-- Moose Development/Moose/Ops/PlayerRecce.lua | 8 +++- Moose Development/Moose/Ops/PlayerTask.lua | 3 +- 5 files changed, 42 insertions(+), 23 deletions(-) diff --git a/Moose Development/Moose/Ops/Awacs.lua b/Moose Development/Moose/Ops/Awacs.lua index 4202e253f..704f52f6f 100644 --- a/Moose Development/Moose/Ops/Awacs.lua +++ b/Moose Development/Moose/Ops/Awacs.lua @@ -1416,6 +1416,7 @@ function AWACS:SetTacticalRadios(BaseFreq,Increase,Modulation,Interval,Number) if self.PathToGoogleKey then --self.TacticalSRS:SetGoogle(self.PathToGoogleKey) self.TacticalSRS:SetProviderOptionsGoogle(self.PathToGoogleKey,self.AccessKey) + self.TacticalSRS:SetProvider(MSRS.Provider.GOOGLE) end self.TacticalSRSQ = MSRSQUEUE:New("Tactical AWACS") end @@ -2104,9 +2105,10 @@ function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey if self.PathToGoogleKey then --self.AwacsSRS:SetGoogle(self.PathToGoogleKey) self.AwacsSRS:SetProviderOptionsGoogle(self.PathToGoogleKey,self.AccessKey) + self.AwacsSRS:SetProvider(MSRS.Provider.GOOGLE) end -- Pre-configured Google? - if self.AwacsSRS:GetProvider() == MSRS.Provider.GOOGLE then + if (not PathToGoogleKey) and self.AwacsSRS:GetProvider() == MSRS.Provider.GOOGLE then self.PathToGoogleKey = MSRS.poptions.gcloud.credentials self.Voice = Voice or MSRS.poptions.gcloud.voice self.AccessKey = AccessKey or MSRS.poptions.gcloud.key @@ -3524,7 +3526,7 @@ function AWACS:_Showtask(Group) local targetstatus = currenttask.Target:GetState() local ToDo = currenttask.ToDo local description = currenttask.ScreenText - local descTTS = currenttask.ScreenText + local descTTS = currenttask.ScreenText local callsign = Callsign if self.debug then @@ -3545,7 +3547,7 @@ function AWACS:_Showtask(Group) local alti = currenttask.Cluster.altitude or currenttask.Contact.altitude or currenttask.Contact.group:GetAltitude() local direction, direcTTS = self:_ToStringBRA(pposition,targetpos,alti) description = description .. "\nBRA "..direction - descTTS = descTTS ..";BRA "..direcTTS + descTTS = descTTS ..";BRA "..direcTTS end elseif currenttask.ToDo == AWACS.TaskDescription.ANCHOR or currenttask.ToDo == AWACS.TaskDescription.REANCHOR then local targetpos = currenttask.Target:GetCoordinate() diff --git a/Moose Development/Moose/Ops/FlightControl.lua b/Moose Development/Moose/Ops/FlightControl.lua index 651c6dc27..d918956e1 100644 --- a/Moose Development/Moose/Ops/FlightControl.lua +++ b/Moose Development/Moose/Ops/FlightControl.lua @@ -411,26 +411,36 @@ function FLIGHTCONTROL:New(AirbaseName, Frequency, Modulation, PathToSRS, Port, self:SetRunwayRepairtime() self.nosubs = false - -- Set SRS Port - self:SetSRSPort(Port or 5002) - -- Set Callsign Options self:SetCallSignOptions(true,true) -- Init msrs queue. self.msrsqueue=MSRSQUEUE:New(self.alias) + -- Init msrs bases + local path = PathToSRS or MSRS.path + local port = Port or MSRS.port or 5002 + + -- Set SRS Port + self:SetSRSPort(port) + -- SRS for Tower. - self.msrsTower=MSRS:New(PathToSRS, Frequency, Modulation) - self.msrsTower:SetPort(self.Port) - self.msrsTower:SetGoogle(GoogleKey) + self.msrsTower=MSRS:New(path, Frequency, Modulation) + self.msrsTower:SetPort(port) + if GoogleKey then + self.msrsTower:SetProviderOptionsGoogle(GoogleKey,GoogleKey) + self.msrsTower:SetProvider(MSRS.Provider.GOOGLE) + end self.msrsTower:SetCoordinate(self:GetCoordinate()) self:SetSRSTower() -- SRS for Pilot. self.msrsPilot=MSRS:New(PathToSRS, Frequency, Modulation) self.msrsPilot:SetPort(self.Port) - self.msrsPilot:SetGoogle(GoogleKey) + if GoogleKey then + self.msrsPilot:SetProviderOptionsGoogle(GoogleKey,GoogleKey) + self.msrsPilot:SetProvider(MSRS.Provider.GOOGLE) + end self.msrsTower:SetCoordinate(self:GetCoordinate()) self:SetSRSPilot() @@ -633,7 +643,6 @@ function FLIGHTCONTROL:_SetSRSOptions(msrs, Gender, Culture, Voice, Volume, Labe msrs:SetVoice(Voice) msrs:SetVolume(Volume) msrs:SetLabel(Label) - msrs:SetGoogle(PathToGoogleCredentials) msrs:SetCoalition(self:GetCoalition()) msrs:SetPort(Port or self.Port or 5002) end @@ -648,12 +657,11 @@ end -- @param #string Voice Specific voice. Overrides `Gender` and `Culture`. See [Google Voices](https://cloud.google.com/text-to-speech/docs/voices). -- @param #number Volume Volume. Default 1.0. -- @param #string Label Name under which SRS transmits. Default `self.alias`. --- @param #string PathToGoogleCredentials Path to google credentials json file. -- @return #FLIGHTCONTROL self -function FLIGHTCONTROL:SetSRSTower(Gender, Culture, Voice, Volume, Label, PathToGoogleCredentials) +function FLIGHTCONTROL:SetSRSTower(Gender, Culture, Voice, Volume, Label) if self.msrsTower then - self:_SetSRSOptions(self.msrsTower, Gender or "female", Culture or "en-GB", Voice, Volume, Label or self.alias, PathToGoogleCredentials) + self:_SetSRSOptions(self.msrsTower, Gender or "female", Culture or "en-GB", Voice, Volume, Label or self.alias) end return self @@ -666,12 +674,11 @@ end -- @param #string Voice Specific voice. Overrides `Gender` and `Culture`. -- @param #number Volume Volume. Default 1.0. -- @param #string Label Name under which SRS transmits. Default "Pilot". --- @param #string PathToGoogleCredentials Path to google credentials json file. -- @return #FLIGHTCONTROL self -function FLIGHTCONTROL:SetSRSPilot(Gender, Culture, Voice, Volume, Label, PathToGoogleCredentials) +function FLIGHTCONTROL:SetSRSPilot(Gender, Culture, Voice, Volume, Label) if self.msrsPilot then - self:_SetSRSOptions(self.msrsPilot, Gender or "male", Culture or "en-US", Voice, Volume, Label or "Pilot", PathToGoogleCredentials) + self:_SetSRSOptions(self.msrsPilot, Gender or "male", Culture or "en-US", Voice, Volume, Label or "Pilot") end return self @@ -876,7 +883,7 @@ end --- Set ATIS. -- @param #FLIGHTCONTROL self --- @param Ops.ATIS#ATIS ATIS ATIS. +-- @param Ops.ATIS#ATIS Atis ATIS. -- @return #FLIGHTCONTROL self function FLIGHTCONTROL:SetATIS(Atis) self.atis=Atis diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 1566e6634..fb9162521 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -2314,14 +2314,17 @@ end -- @return #OPSGROUP self function OPSGROUP:SetSRS(PathToSRS, Gender, Culture, Voice, Port, PathToGoogleKey, Label, Volume) self.useSRS=true - self.msrs=MSRS:New(PathToSRS, self.frequency, self.modulation) + local path = PathToSRS or MSRS.path + local port = Port or MSRS.port + self.msrs=MSRS:New(path, self.frequency, self.modulation) self.msrs:SetGender(Gender) self.msrs:SetCulture(Culture) self.msrs:SetVoice(Voice) - self.msrs:SetPort(Port) + self.msrs:SetPort(port) self.msrs:SetLabel(Label) if PathToGoogleKey then - self.msrs:SetGoogle(PathToGoogleKey) + self.msrs:SetProviderOptionsGoogle(PathToGoogleKey,PathToGoogleKey) + self.msrs:SetProvider(MSRS.Provider.GOOGLE) end self.msrs:SetCoalition(self:GetCoalition()) self.msrs:SetVolume(Volume) diff --git a/Moose Development/Moose/Ops/PlayerRecce.lua b/Moose Development/Moose/Ops/PlayerRecce.lua index 5a87c3be1..7cac793b1 100644 --- a/Moose Development/Moose/Ops/PlayerRecce.lua +++ b/Moose Development/Moose/Ops/PlayerRecce.lua @@ -1517,7 +1517,13 @@ function PLAYERRECCE:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,V self.SRS:SetVoice(self.Voice) self.SRS:SetVolume(self.Volume) if self.PathToGoogleKey then - self.SRS:SetGoogle(self.PathToGoogleKey) + self.SRS:SetProviderOptionsGoogle(self.PathToGoogleKey,self.PathToGoogleKey) + self.SRS:SetProvider(MSRS.Provider.GOOGLE) + end + -- Pre-configured Google? + if (not PathToGoogleKey) and self.AwacsSRS:GetProvider() == MSRS.Provider.GOOGLE then + self.PathToGoogleKey = MSRS.poptions.gcloud.credentials + self.Voice = Voice or MSRS.poptions.gcloud.voice end self.SRSQueue = MSRSQUEUE:New(self.MenuName or self.Name) self.SRSQueue:SetTransmitOnlyWithPlayers(self.TransmitOnlyWithPlayers) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 855b954ca..0b95512e4 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -4034,9 +4034,10 @@ function PLAYERTASKCONTROLLER:SetSRS(Frequency,Modulation,PathToSRS,Gender,Cultu if self.PathToGoogleKey then --self.SRS:SetGoogle(self.PathToGoogleKey) self.SRS:SetProviderOptionsGoogle(self.PathToGoogleKey,self.AccessKey) + self.SRS:SetProvider(MSRS.Provider.GOOGLE) end -- Pre-configured Google? - if self.SRS:GetProvider() == MSRS.Provider.GOOGLE then + if (not PathToGoogleKey) and self.SRS:GetProvider() == MSRS.Provider.GOOGLE then self.PathToGoogleKey = MSRS.poptions.gcloud.credentials self.Voice = Voice or MSRS.poptions.gcloud.voice self.AccessKey = AccessKey or MSRS.poptions.gcloud.key From 677d888d960e57390453e91ea4418a440a9f2419 Mon Sep 17 00:00:00 2001 From: ttrebuchon Date: Sun, 7 Jan 2024 07:26:58 -0500 Subject: [PATCH 15/20] Use total cargo weight when computing asset score for transport missions (#2065) * Optimize carrier assets for OPSTRANSPORT based on total cargo weight * Clean up code/comments for TotalWeight scoring * Add missing parameter documentation --- Moose Development/Moose/Ops/Legion.lua | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index 610636593..9c5861800 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -2745,7 +2745,7 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt, end -- Now we have a long list with assets. - LEGION._OptimizeAssetSelection(Assets, MissionTypeOpt, TargetVec2, false) + LEGION._OptimizeAssetSelection(Assets, MissionTypeOpt, TargetVec2, false, TotalWeight) -- Get payloads for air assets. @@ -2770,7 +2770,7 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt, end -- Now find the best asset for the given payloads. - LEGION._OptimizeAssetSelection(Assets, MissionTypeOpt, TargetVec2, true) + LEGION._OptimizeAssetSelection(Assets, MissionTypeOpt, TargetVec2, true, TotalWeight) -- Number of assets. At most NreqMax. local Nassets=math.min(#Assets, NreqMax) @@ -3114,8 +3114,9 @@ end -- @param #string MissionType Mission type for which the best assets are desired. -- @param DCS#Vec2 TargetVec2 Target 2D vector. -- @param #boolean IncludePayload If `true`, include the payload in the calulation if the asset has one attached. +-- @param #number TotalWeight The total weight of the cargo to be transported, if applicable. -- @return #number Mission score. -function LEGION.CalculateAssetMissionScore(asset, MissionType, TargetVec2, IncludePayload) +function LEGION.CalculateAssetMissionScore(asset, MissionType, TargetVec2, IncludePayload, TotalWeight) -- Mission score. local score=0 @@ -3209,8 +3210,18 @@ function LEGION.CalculateAssetMissionScore(asset, MissionType, TargetVec2, Inclu -- TRANSPORT specific. if MissionType==AUFTRAG.Type.OPSTRANSPORT then - -- Add 1 score point for each 10 kg of cargo bay. - score=score+UTILS.Round(asset.cargobaymax/10, 0) + if TotalWeight then + -- Add 1 score point for each 10 kg of cargo bay capacity up to the total cargo weight, + -- and then subtract 1 score point for each excess 10kg of cargo bay capacity. + if asset.cargobaymax < TotalWeight then + score=score+UTILS.Round(asset.cargobaymax/10, 0) + else + score=score+UTILS.Round(TotalWeight/10, 0) + end + else + -- Add 1 score point for each 10 kg of cargo bay. + score=score+UTILS.Round(asset.cargobaymax/10, 0) + end end -- TODO: This could be vastly improved. Need to gather ideas during testing. @@ -3231,14 +3242,15 @@ end -- @param #string MissionType Mission type. -- @param DCS#Vec2 TargetVec2 Target position as 2D vector. -- @param #boolean IncludePayload If `true`, include the payload in the calulation if the asset has one attached. -function LEGION._OptimizeAssetSelection(assets, MissionType, TargetVec2, IncludePayload) +-- @param #number TotalWeight The total weight of the cargo to be transported, if applicable. +function LEGION._OptimizeAssetSelection(assets, MissionType, TargetVec2, IncludePayload, TotalWeight) -- Calculate the mission score of all assets. for _,_asset in pairs(assets) do local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem -- Calculate the asset score. - asset.score=LEGION.CalculateAssetMissionScore(asset, MissionType, TargetVec2, IncludePayload) + asset.score=LEGION.CalculateAssetMissionScore(asset, MissionType, TargetVec2, IncludePayload, TotalWeight) if IncludePayload then From 4fd7d7cba91373491153ed0913d37482775e3985 Mon Sep 17 00:00:00 2001 From: "Mr.Alien" <124381209+MrAlien753@users.noreply.github.com> Date: Sun, 7 Jan 2024 13:27:23 +0100 Subject: [PATCH 16/20] Spawn all unit randomly inside a zone, instead of only the first unit in zone and the other within a radius (potentially outside the zone, and in some cases in the middle of a runway) (#2069) --- Moose Development/Moose/Core/Spawn.lua | 31 +++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Core/Spawn.lua b/Moose Development/Moose/Core/Spawn.lua index e4b559d98..8124e11a6 100644 --- a/Moose Development/Moose/Core/Spawn.lua +++ b/Moose Development/Moose/Core/Spawn.lua @@ -1458,6 +1458,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth ) else local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate + local SpawnZone = self.SpawnGroups[self.SpawnIndex].SpawnZone self:T( SpawnTemplate.name ) if SpawnTemplate then @@ -1483,6 +1484,23 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth ) if self.SpawnRandomizeUnits then for UnitID = 1, #SpawnTemplate.units do local RandomVec2 = PointVec3:GetRandomVec2InRadius( self.SpawnOuterRadius, self.SpawnInnerRadius ) + if (SpawnZone) then + local inZone = SpawnZone:IsVec2InZone(RandomVec2) + local numTries = 1 + while (not inZone) and (numTries < 20) do + if not inZone then + RandomVec2 = PointVec3:GetRandomVec2InRadius( self.SpawnOuterRadius, self.SpawnInnerRadius ) + numTries = numTries + 1 + inZone = SpawnZone:IsVec2InZone(RandomVec2) + self:I("Retrying " .. numTries .. "spawn " .. SpawnTemplate.name .. " in Zone " .. SpawnZone:GetName() .. "!") + self:I(SpawnZone) + end + end + if (not inZone) then + self:I("Could not place unit within zone and within radius!") + RandomVec2 = SpawnZone:GetRandomVec2() + end + end SpawnTemplate.units[UnitID].x = RandomVec2.x SpawnTemplate.units[UnitID].y = RandomVec2.y self:T( 'SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y ) @@ -1534,12 +1552,14 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth ) for UnitID = 1, #SpawnTemplate.units do - if UnitID > 1 then -- don't rotate position of unit #1 - local unitXOff = SpawnTemplate.units[UnitID].x - pivotX -- rotate position offset around unit #1 - local unitYOff = SpawnTemplate.units[UnitID].y - pivotY + if not self.SpawnRandomizeUnits then + if UnitID > 1 then -- don't rotate position of unit #1 + local unitXOff = SpawnTemplate.units[UnitID].x - pivotX -- rotate position offset around unit #1 + local unitYOff = SpawnTemplate.units[UnitID].y - pivotY - SpawnTemplate.units[UnitID].x = pivotX + (unitXOff * cosHeading) - (unitYOff * sinHeading) - SpawnTemplate.units[UnitID].y = pivotY + (unitYOff * cosHeading) + (unitXOff * sinHeading) + SpawnTemplate.units[UnitID].x = pivotX + (unitXOff * cosHeading) - (unitYOff * sinHeading) + SpawnTemplate.units[UnitID].y = pivotY + (unitYOff * cosHeading) + (unitXOff * sinHeading) + end end -- adjust heading of all units, including unit #1 @@ -3591,6 +3611,7 @@ function SPAWN:_RandomizeZones( SpawnIndex ) self:T( { SpawnVec2 = SpawnVec2 } ) local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate + self.SpawnGroups[SpawnIndex].SpawnZone = SpawnZone self:T( { Route = SpawnTemplate.route } ) From aca58462093f5d77cfd3fdbb149a8019d8270a6f Mon Sep 17 00:00:00 2001 From: "Mr.Alien" <124381209+MrAlien753@users.noreply.github.com> Date: Sun, 7 Jan 2024 13:28:12 +0100 Subject: [PATCH 17/20] Fix scoring to not het more points when not killed at once. + overridable method call on kill (#2079) --- .../Moose/Functional/Scoring.lua | 70 ++++++++++++++++--- 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua index 158d0d62f..b8c7218cf 100644 --- a/Moose Development/Moose/Functional/Scoring.lua +++ b/Moose Development/Moose/Functional/Scoring.lua @@ -276,9 +276,15 @@ function SCORING:New( GameName ) self:SetMessagesZone( true ) -- Scales + self:SetScaleDestroyScore( 10 ) self:SetScaleDestroyPenalty( 30 ) + -- Hitting a target multiple times before destoying it should not result in a higger score + -- Multiple hits is typically a results of bombs/missles missing their target but still inflict some spash damage + -- Making this configurable to anyone can enable this anyway if they want + self:SetScoreIncrementOnHit(0) + -- Default fratricide penalty level (maximum penalty that can be assigned to a player before he gets kicked). self:SetFratricide( self.ScaleDestroyPenalty * 3 ) self.penaltyonfratricide = true @@ -467,6 +473,16 @@ function SCORING:SetMessagesHit( OnOff ) return self end +--- Configure to increment score after a target has been hit. +-- @param #SCORING self +-- @param #number score amount of point to inclement score on each hit +-- @return #SCORING +function SCORING:SetScoreIncrementOnHit( score ) + + self.ScoreIncrementOnHit = score + return self +end + --- If to send messages after a target has been hit. -- @param #SCORING self -- @return #boolean @@ -885,6 +901,7 @@ function SCORING:OnEventBirth( Event ) Event.IniUnit.BirthTime = timer.getTime() if PlayerName then self:_AddPlayerFromUnit( Event.IniUnit ) + self.Players[PlayerName].PlayerKills = 0 self:SetScoringMenu( Event.IniGroup ) end end @@ -1015,7 +1032,7 @@ function SCORING:_EventOnHit( Event ) PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT -- After an instant kill we can't compute the thread level anymore. To fix this we compute at OnEventBirth if PlayerHit.UNIT.ThreatType == nil then - PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel() + PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel() -- if this fails for some reason, set a good default value if PlayerHit.ThreatType == nil then PlayerHit.ThreatLevel = 1 @@ -1025,7 +1042,7 @@ function SCORING:_EventOnHit( Event ) PlayerHit.ThreatLevel = PlayerHit.UNIT.ThreatLevel PlayerHit.ThreatType = PlayerHit.UNIT.ThreatType end - + -- Only grant hit scores if there was more than one second between the last hit. if timer.getTime() - PlayerHit.TimeStamp > 1 then PlayerHit.TimeStamp = timer.getTime() @@ -1060,10 +1077,8 @@ function SCORING:_EventOnHit( Event ) end self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) else - -- Hitting a target multiple times before destoying it should not result in a higger score - -- Multiple hits is typically a results of bombs/missles missing their target but still inflict some spash damage - -- Player.Score = Player.Score + 1 - -- PlayerHit.Score = PlayerHit.Score + 1 + Player.Score = Player.Score + self.ScoreIncrementOnHit + PlayerHit.Score = PlayerHit.Score + self.ScoreIncrementOnHit PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1 if TargetPlayerName ~= nil then -- It is a player hitting another player ... MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. @@ -1128,7 +1143,7 @@ function SCORING:_EventOnHit( Event ) PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT -- After an instant kill we can't compute the thread level anymore. To fix this we compute at OnEventBirth if PlayerHit.UNIT.ThreatType == nil then - PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel() + PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel() -- if this fails for some reason, set a good default value if PlayerHit.ThreatType == nil then PlayerHit.ThreatLevel = 1 @@ -1163,10 +1178,8 @@ function SCORING:_EventOnHit( Event ) :ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() ) self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) else - -- Hitting a target multiple times before destoying it should not result in a higger score - -- Multiple hits is typically a results of bombs/missles missing their target but still inflict some spash damage - -- Player.Score = Player.Score + 1 - -- PlayerHit.Score = PlayerHit.Score + 1 + Player.Score = Player.Score + self.ScoreIncrementOnHit + PlayerHit.Score = PlayerHit.Score + self.ScoreIncrementOnHit PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1 MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. "Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty, @@ -1274,13 +1287,18 @@ function SCORING:_EventOnDeadOrCrash( Event ) TargetDestroy.Penalty = TargetDestroy.Penalty + ThreatPenalty TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy + 1 + + self:OnKillPvP(Player, TargetPlayerName, true, TargetThreatLevel, Player.ThreatLevel, ThreatPenalty) + if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player + self:OnKillPvP(Player, TargetPlayerName, true) MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. "Penalty: -" .. ThreatPenalty .. " = " .. Player.Score - Player.Penalty, MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) else + self:OnKillPvE(Player, TargetUnitName, true, TargetThreatLevel, Player.ThreatLevel, ThreatPenalty) MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. "Penalty: -" .. ThreatPenalty .. " = " .. Player.Score - Player.Penalty, MESSAGE.Type.Information ) @@ -1303,12 +1321,19 @@ function SCORING:_EventOnDeadOrCrash( Event ) TargetDestroy.Score = TargetDestroy.Score + ThreatScore TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy + 1 if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player + if Player.PlayerKills ~= nil then + Player.PlayerKills = Player.PlayerKills + 1 + else + Player.PlayerKills = 1 + end + self:OnKillPvP(Player, TargetPlayerName, false, TargetThreatLevel, Player.ThreatLevel, ThreatScore) MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. "Score: +" .. ThreatScore .. " = " .. Player.Score - Player.Penalty, MESSAGE.Type.Information ) :ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() ) :ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() ) else + self:OnKillPvE(Player, TargetUnitName, false, TargetThreatLevel, Player.ThreatLevel, ThreatScore) MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. "Score: +" .. ThreatScore .. " = " .. Player.Score - Player.Penalty, MESSAGE.Type.Information ) @@ -1907,3 +1932,26 @@ function SCORING:SwitchAutoSave(OnOff) self.AutoSave = OnOff return self end + +--- Handles the event when one player kill another player +-- @param #SCORING self +-- @param #PLAYER Player the ataching player +-- @param #string TargetPlayerName the name of the killed player +-- @param #bool IsTeamKill true if this kill was a team kill +-- @param #number TargetThreatLevel Thread level of the target +-- @param #number PlayerThreatLevelThread level of the player +-- @param #number Score The score based on both threat levels +function SCORING:OnKillPvP(Player, TargetPlayerName, IsTeamKill, TargetThreatLevel, PlayerThreatLevel, Score) + +end +--- Handles the event when one player kill another player +-- @param #SCORING self +-- @param #PLAYER Player the ataching player +-- @param #string TargetUnitName the name of the killed unit +-- @param #bool IsTeamKill true if this kill was a team kill +-- @param #number TargetThreatLevel Thread level of the target +-- @param #number PlayerThreatLevelThread level of the player +-- @param #number Score The score based on both threat levels +function SCORING:OnKillPvE(Player, TargetUnitName, IsTeamKill, TargetThreatLevel, PlayerThreatLevel, Score) + +end \ No newline at end of file From fa762fe0fc6588ecc140a25ee5661dc55585fb44 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 7 Jan 2024 14:44:03 +0100 Subject: [PATCH 18/20] #MSRS * Added voice enumerator ofr gRPC using MS as provider MSRS.Voices.MicrosoftGRPC --- Moose Development/Moose/Sound/SRS.lua | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Sound/SRS.lua b/Moose Development/Moose/Sound/SRS.lua index b0ac95894..ec38d5862 100644 --- a/Moose Development/Moose/Sound/SRS.lua +++ b/Moose Development/Moose/Sound/SRS.lua @@ -272,6 +272,13 @@ MSRS.Voices = { ["Zira"] = "Microsoft Zira Desktop", -- en-US ["Hortense"] = "Microsoft Hortense Desktop", --fr-FR }, + MicrosoftGRPC = { + ["Hedda"] = "Hedda", -- de-DE + ["Hazel"] = "Hazel", -- en-GB + ["David"] = "David", -- en-US + ["Zira"] = "Zira", -- en-US + ["Hortense"] = "Hortense", --fr-FR + }, Google = { Standard = { ["en_AU_Standard_A"] = 'en-AU-Standard-A', -- [1] FEMALE @@ -1610,7 +1617,7 @@ end -- -- -- Moose MSRS default Config -- MSRS_Config = { --- Path = C:\\Program Files\\DCS-SimpleRadio-Standalone, -- Path to SRS install directory. +-- Path = "C:\\Program Files\\DCS-SimpleRadio-Standalone", -- Path to SRS install directory. -- Port = 5002, -- Port of SRS server. Default 5002. -- Backend = "srsexe", -- Interface to SRS: "srsexe" or "grpc". -- Frequency = {127, 243}, -- Default frequences. Must be a table 1..n entries! @@ -1622,8 +1629,7 @@ end -- Gender = "male", -- Voice = "Microsoft Hazel Desktop", -- Voice that is used if no explicit provider voice is specified. -- Label = "MSRS", --- Provider = "win", --Provider for generating TTS (win, gcloud, azure, aws). --- +-- Provider = "win", --Provider for generating TTS (win, gcloud, azure, aws). -- -- Windows -- win = { -- voice = "Microsoft Hazel Desktop", @@ -1649,7 +1655,7 @@ end -- }, -- } -- --- 3) The config file is automatically loaded when Moose starts. YOu can also load the config into the MSRS raw class manually before you do anything else: +-- 3) The config file is automatically loaded when Moose starts. You can also load the config into the MSRS raw class manually before you do anything else: -- -- MSRS.LoadConfigFile() -- Note the "." here -- @@ -1665,8 +1671,7 @@ end -- 4) Use the config in your code like so, variable names are basically the same as in the config file, but all lower case, examples: -- -- -- Needed once only --- MESSAGE.SetMSRS(MSRS.path,nil,MSRS.google,243,radio.modulation.AM,nil,nil, --- MSRS.Voices.Google.Standard.de_DE_Standard_B,coalition.side.BLUE) +-- MESSAGE.SetMSRS(MSRS.path,MSRS.port,nil,127,rado.modulation.FM,nil,nil,nil,nil,nil,"TALK") -- -- -- later on in your code -- From 4ddd278471574e4c562ea3c08d7c5facc75abb63 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 7 Jan 2024 15:40:17 +0100 Subject: [PATCH 19/20] #AWACS * Picture clean, correct order of callsigns --- Moose Development/Moose/Ops/Awacs.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/Awacs.lua b/Moose Development/Moose/Ops/Awacs.lua index 704f52f6f..50fb3ab5b 100644 --- a/Moose Development/Moose/Ops/Awacs.lua +++ b/Moose Development/Moose/Ops/Awacs.lua @@ -507,7 +507,7 @@ do -- @field #AWACS AWACS = { ClassName = "AWACS", -- #string - version = "0.2.60", -- #string + version = "0.2.61", -- #string lid = "", -- #string coalition = coalition.side.BLUE, -- #number coalitiontxt = "blue", -- #string @@ -2948,7 +2948,7 @@ function AWACS:_Picture(Group,IsGeneral) if not self.intel then -- no intel yet! local picclean = self.gettext:GetEntry("PICCLEAN",self.locale) - text = string.format(picclean,self.callsigntxt, gcallsign) + text = string.format(picclean,gcallsign,self.callsigntxt) textScreen = text self:_NewRadioEntry(text,text,GID,false,true,true,false) @@ -3526,7 +3526,7 @@ function AWACS:_Showtask(Group) local targetstatus = currenttask.Target:GetState() local ToDo = currenttask.ToDo local description = currenttask.ScreenText - local descTTS = currenttask.ScreenText + local descTTS = currenttask.ScreenText local callsign = Callsign if self.debug then @@ -3547,7 +3547,7 @@ function AWACS:_Showtask(Group) local alti = currenttask.Cluster.altitude or currenttask.Contact.altitude or currenttask.Contact.group:GetAltitude() local direction, direcTTS = self:_ToStringBRA(pposition,targetpos,alti) description = description .. "\nBRA "..direction - descTTS = descTTS ..";BRA "..direcTTS + descTTS = descTTS ..";BRA "..direcTTS end elseif currenttask.ToDo == AWACS.TaskDescription.ANCHOR or currenttask.ToDo == AWACS.TaskDescription.REANCHOR then local targetpos = currenttask.Target:GetCoordinate() From e26647c2cae496d26ad77078fee65e2e2ecb7be6 Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 7 Jan 2024 17:24:51 +0100 Subject: [PATCH 20/20] OPSTRANSPORT - Fixed SET not working with FilterActive --- Moose Development/Moose/Core/Set.lua | 45 +++++++++++++++----- Moose Development/Moose/Ops/OpsTransport.lua | 10 +++++ Moose Development/Moose/Wrapper/Group.lua | 10 ++++- 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 1ad9bdea6..9474d42b9 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -1578,7 +1578,7 @@ do function SET_GROUP:AddInDatabase( Event ) self:F3( { Event } ) - if Event.IniObjectCategory == 1 then + if Event.IniObjectCategory == Object.Category.UNIT then if not self.Database[Event.IniDCSGroupName] then self.Database[Event.IniDCSGroupName] = GROUP:Register( Event.IniDCSGroupName ) self:T3( self.Database[Event.IniDCSGroupName] ) @@ -2641,7 +2641,7 @@ do -- SET_UNIT function SET_UNIT:AddInDatabase( Event ) self:F3( { Event } ) - if Event.IniObjectCategory == 1 then + if Event.IniObjectCategory == Object.Category.UNIT then if not self.Database[Event.IniDCSUnitName] then self.Database[Event.IniDCSUnitName] = UNIT:Register( Event.IniDCSUnitName ) self:T3( self.Database[Event.IniDCSUnitName] ) @@ -4518,7 +4518,7 @@ do -- SET_CLIENT function SET_CLIENT:_EventPlayerEnterUnit(Event) self:I( "_EventPlayerEnterUnit" ) if Event.IniDCSUnit then - if Event.IniObjectCategory == 1 and Event.IniGroup and Event.IniGroup:IsGround() then + if Event.IniObjectCategory == Object.Category.UNIT and Event.IniGroup and Event.IniGroup:IsGround() then -- CA Slot entered local ObjectName, Object = self:AddInDatabase( Event ) self:I( ObjectName, UTILS.PrintTableToLog(Object) ) @@ -4537,7 +4537,7 @@ do -- SET_CLIENT function SET_CLIENT:_EventPlayerLeaveUnit(Event) self:I( "_EventPlayerLeaveUnit" ) if Event.IniDCSUnit then - if Event.IniObjectCategory == 1 and Event.IniGroup and Event.IniGroup:IsGround() then + if Event.IniObjectCategory == Object.Category.UNIT and Event.IniGroup and Event.IniGroup:IsGround() then -- CA Slot left local ObjectName, Object = self:FindInDatabase( Event ) if ObjectName then @@ -7837,6 +7837,29 @@ do -- SET_OPSGROUP return self end + --- Handles the OnBirth event for the Set. + -- @param #SET_OPSGROUP self + -- @param Core.Event#EVENTDATA Event Event data. + function SET_OPSGROUP:_EventOnBirth( Event ) + self:F3( { Event } ) + + if Event.IniDCSUnit and Event.IniDCSGroup then + local DCSgroup=Event.IniDCSGroup --DCS#Group + + if DCSgroup:getInitialSize() == DCSgroup:getSize() then -- This seems to be not a good check as even for the first birth event, getSize returns the total number of units in the group. + + local groupname, group = self:AddInDatabase( Event ) + + if group and group:CountAliveUnits()==DCSgroup:getInitialSize() then + if group and self:IsIncludeObject( group ) then + self:Add( groupname, group ) + end + end + + end + end + end + --- Handles the OnDead or OnCrash event for alive groups set. -- Note: The GROUP object in the SET_OPSGROUP collection will only be removed if the last unit is destroyed of the GROUP. -- @param #SET_OPSGROUP self @@ -7857,12 +7880,12 @@ do -- SET_OPSGROUP --- Handles the Database to check on an event (birth) that the Object was added in the Database. -- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! -- @param #SET_OPSGROUP self - -- @param Core.Event#EVENTDATA Event - -- @return #string The name of the GROUP - -- @return #table The GROUP + -- @param Core.Event#EVENTDATA Event Event data. + -- @return #string The name of the GROUP. + -- @return Wrapper.Group#GROUP The GROUP object. function SET_OPSGROUP:AddInDatabase( Event ) - if Event.IniObjectCategory==1 then + if Event.IniObjectCategory==Object.Category.UNIT then if not self.Database[Event.IniDCSGroupName] then self.Database[Event.IniDCSGroupName] = GROUP:Register( Event.IniDCSGroupName ) @@ -7877,8 +7900,8 @@ do -- SET_OPSGROUP -- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! -- @param #SET_OPSGROUP self -- @param Core.Event#EVENTDATA Event Event data table. - -- @return #string The name of the GROUP - -- @return #table The GROUP + -- @return #string The name of the GROUP. + -- @return Wrapper.Group#GROUP The GROUP object. function SET_OPSGROUP:FindInDatabase(Event) return Event.IniDCSGroupName, self.Database[Event.IniDCSGroupName] end @@ -8197,7 +8220,7 @@ do -- SET_SCENERY end --- Get a table of alive objects. - -- @param #SET_GROUP self + -- @param #SET_SCENERY self -- @return #table Table of alive objects -- @return Core.Set#SET_SCENERY SET of alive objects function SET_SCENERY:GetAliveSet() diff --git a/Moose Development/Moose/Ops/OpsTransport.lua b/Moose Development/Moose/Ops/OpsTransport.lua index 2db528f02..f5c8e84f2 100644 --- a/Moose Development/Moose/Ops/OpsTransport.lua +++ b/Moose Development/Moose/Ops/OpsTransport.lua @@ -605,6 +605,16 @@ function OPSTRANSPORT:AddCargoGroups(GroupSet, TransportZoneCombo, DisembarkActi self:AddCargoGroups(group, TransportZoneCombo, DisembarkActivation) end + + -- Use FSM function to keep the SET up-to-date. Note that it overwrites the user FMS function, which cannot be used any more now. + local groupset=GroupSet --Core.Set#SET_OPSGROUP + function groupset.OnAfterAdded(groupset, From, Event, To, ObjectName, Object) + + self:T(self.lid..string.format("Adding Cargo Group %s", tostring(ObjectName))) + self:AddCargoGroups(Object, TransportZoneCombo, DisembarkActivation, DisembarkZone, DisembarkCarriers) + + end + end -- Debug info. diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index d232bf604..080467e84 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -689,7 +689,15 @@ function GROUP:GetUnits() local DCSUnits = DCSGroup:getUnits() or {} local Units = {} for Index, UnitData in pairs( DCSUnits ) do - Units[#Units+1] = UNIT:Find( UnitData ) + + local unit=UNIT:Find( UnitData ) + if unit then + Units[#Units+1] = UNIT:Find( UnitData ) + else + local UnitName=UnitData:getName() + unit=_DATABASE:AddUnit(UnitName) + Units[#Units+1]=unit + end end self:T3( Units ) return Units