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/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 } ) 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 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..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 @@ -918,12 +925,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 +951,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 @@ -1606,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! @@ -1618,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", @@ -1645,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 -- @@ -1661,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 --