diff --git a/CHANGELOG.md b/CHANGELOG.md index 30ea2d440..36c46fb92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ All notable changes to TTT2 will be documented here. Inspired by [keep a changel - Added a submenu to issue basic commands - Added a new `gameloop` module that contains all functions related to the round structure (by @Tim Goll) - Added a loadingscreen that hides the visible and audible lag introduced by the map cleanup on round change (by @TimGoll) +- Added a voicebattery module that handles the voice battery (by @TimGoll) ### Changed diff --git a/gamemodes/terrortown/gamemode/client/cl_main.lua b/gamemodes/terrortown/gamemode/client/cl_main.lua index c2db18ed3..6ec2124ee 100644 --- a/gamemodes/terrortown/gamemode/client/cl_main.lua +++ b/gamemodes/terrortown/gamemode/client/cl_main.lua @@ -519,7 +519,7 @@ function GM:ClearClientState() client:SetTargetPlayer(nil) - VOICE.InitBattery() + voicebattery.InitBattery() local plys = playerGetAll() diff --git a/gamemodes/terrortown/gamemode/client/cl_voice.lua b/gamemodes/terrortown/gamemode/client/cl_voice.lua index 07036cdf3..35664bcc5 100644 --- a/gamemodes/terrortown/gamemode/client/cl_voice.lua +++ b/gamemodes/terrortown/gamemode/client/cl_voice.lua @@ -486,9 +486,6 @@ function VOICE.CycleMuteState(force_state) return mute_state end -VOICE.battery_max = 100 -VOICE.battery_min = 10 - --- -- Scales a linear volume into a Power 4 value. -- @param number volume @@ -614,44 +611,12 @@ function VOICE.UpdatePlayerVoiceVolume(ply) end --- --- Initializes the voice battery +-- Checks if a player is using the role/team voice chat. This is not the global +-- voice chat. +-- @param player ply The player to check +-- @return boolean Returns true if the player is using the role voice chat -- @realm client -function VOICE.InitBattery() - LocalPlayer().voice_battery = VOICE.battery_max -end - -local function GetRechargeRate() - local r = GetGlobalFloat("ttt_voice_drain_recharge", 0.05) - - if LocalPlayer().voice_battery < VOICE.battery_min then - r = r * 0.5 - end - - return r -end - -local function GetDrainRate() - local ply = LocalPlayer() - - if - not IsValid(ply) - or ply:IsSpec() - or not GetGlobalBool("ttt_voice_drain", false) - or gameloop.GetRoundState() ~= ROUND_ACTIVE - then - return 0 - end - - local plyRoleData = ply:GetSubRoleData() - - if ply:IsAdmin() or (plyRoleData.isPublicRole and plyRoleData.isPolicingRole) then - return GetGlobalFloat("ttt_voice_drain_admin", 0) - else - return GetGlobalFloat("ttt_voice_drain_normal", 0) - end -end - -local function IsRoleChatting(ply) +function VOICE.IsRoleChatting(ply) local plyTeam = ply:GetTeam() local plyRoleData = ply:GetSubRoleData() @@ -664,31 +629,6 @@ local function IsRoleChatting(ply) and not ply[plyTeam .. "_gvoice"] end ---- --- Updates the voice battery --- @note Called every @{GM:Tick} --- @realm client --- @internal -function VOICE.Tick() - if not GetGlobalBool("ttt_voice_drain", false) then - return - end - - local client = LocalPlayer() - - if VOICE.IsSpeaking() and not IsRoleChatting(client) then - client.voice_battery = client.voice_battery - GetDrainRate() - - if not VOICE.CanSpeak() then - client.voice_battery = 0 - - permissions.EnableVoiceChat(false) - end - elseif client.voice_battery < VOICE.battery_max then - client.voice_battery = client.voice_battery + GetRechargeRate() - end -end - --- -- Returns whether a @{Player} is speaking -- @note @{Player:IsSpeaking} does not work for local @{Player} @@ -720,13 +660,13 @@ function VOICE.CanSpeak() return false end - if not GetGlobalBool("ttt_voice_drain", false) then + if not voicebattery.IsEnabled() then return true end local client = LocalPlayer() - return client.voice_battery > VOICE.battery_min or IsRoleChatting(client) + return voicebattery.IsCharged() or VOICE.IsRoleChatting(client) end --- diff --git a/gamemodes/terrortown/gamemode/server/sv_main.lua b/gamemodes/terrortown/gamemode/server/sv_main.lua index bb6fcbdf9..60546013c 100644 --- a/gamemodes/terrortown/gamemode/server/sv_main.lua +++ b/gamemodes/terrortown/gamemode/server/sv_main.lua @@ -112,26 +112,6 @@ local idle_enabled = CreateConVar("ttt_idle", "1", {FCVAR_NOTIFY, FCVAR_ARCHIVE} -- stylua: ignore local idle_time = CreateConVar("ttt_idle_limit", "180", {FCVAR_NOTIFY, FCVAR_ARCHIVE}) ---- --- @realm server --- stylua: ignore -local voice_drain = CreateConVar("ttt_voice_drain", "0", {FCVAR_NOTIFY, FCVAR_ARCHIVE}) - ---- --- @realm server --- stylua: ignore -local voice_drain_normal = CreateConVar("ttt_voice_drain_normal", "0.2", {FCVAR_NOTIFY, FCVAR_ARCHIVE}) - ---- --- @realm server --- stylua: ignore -local voice_drain_admin = CreateConVar("ttt_voice_drain_admin", "0.05", {FCVAR_NOTIFY, FCVAR_ARCHIVE}) - ---- --- @realm server --- stylua: ignore -local voice_drain_recharge = CreateConVar("ttt_voice_drain_recharge", "0.05", {FCVAR_NOTIFY, FCVAR_ARCHIVE}) - --- -- @realm server -- stylua: ignore @@ -499,11 +479,6 @@ function GM:SyncGlobals() SetGlobalInt(idle_time:GetName(), idle_time:GetInt()) SetGlobalBool(idle_enabled:GetName(), idle_enabled:GetBool()) - SetGlobalBool(voice_drain:GetName(), voice_drain:GetBool()) - SetGlobalFloat(voice_drain_normal:GetName(), voice_drain_normal:GetFloat()) - SetGlobalFloat(voice_drain_admin:GetName(), voice_drain_admin:GetFloat()) - SetGlobalFloat(voice_drain_recharge:GetName(), voice_drain_recharge:GetFloat()) - local rlsList = roles.GetList() for i = 1, #rlsList do @@ -531,22 +506,6 @@ cvars.AddChangeCallback(idle_enabled:GetName(), function(cv, old, new) SetGlobalBool(idle_enabled:GetName(), tobool(tonumber(new))) end) -cvars.AddChangeCallback(voice_drain:GetName(), function(cv, old, new) - SetGlobalBool(voice_drain:GetName(), tobool(tonumber(new))) -end) - -cvars.AddChangeCallback(voice_drain_normal:GetName(), function(cv, old, new) - SetGlobalFloat(voice_drain_normal:GetName(), tonumber(new)) -end) - -cvars.AddChangeCallback(voice_drain_admin:GetName(), function(cv, old, new) - SetGlobalFloat(voice_drain_admin:GetName(), tonumber(new)) -end) - -cvars.AddChangeCallback(voice_drain_recharge:GetName(), function(cv, old, new) - SetGlobalFloat(voice_drain_recharge:GetName(), tonumber(new)) -end) - --- -- This @{function} is used to load the shop equipments -- @realm server diff --git a/gamemodes/terrortown/gamemode/shared/hud_elements/tttvoice/pure_skin_voice.lua b/gamemodes/terrortown/gamemode/shared/hud_elements/tttvoice/pure_skin_voice.lua index ef0ac05db..f1c9c9c53 100644 --- a/gamemodes/terrortown/gamemode/shared/hud_elements/tttvoice/pure_skin_voice.lua +++ b/gamemodes/terrortown/gamemode/shared/hud_elements/tttvoice/pure_skin_voice.lua @@ -54,20 +54,16 @@ if CLIENT then local heightBar = h - 2 * self.padding local wNick = w - h - self.padding + local offset = 3 * self.scale + local heightBatteryBar = 2 * self.scale + draw.Box(xPos + self.padding, yPos + self.padding, w - self.padding, heightBar, color) - self:DrawLines( - xPos + self.padding, - yPos + self.padding, - w - self.padding, - heightBar, - color.a - ) for i = 1, #data do local yValue = math.floor(data[i] * 0.5 * heightBar - 4 * self.scale) draw.Box( - xPos + h + 3 + (i - 1) * (widthBar + 1), + xPos + h + offset + (i - 1) * (widthBar + 1), yPos + 0.5 * h - yValue - 1, widthBar, yValue, @@ -75,7 +71,7 @@ if CLIENT then ) if yValue > 1 then draw.Box( - xPos + h + 3 + (i - 1) * (widthBar + 1), + xPos + h + offset + (i - 1) * (widthBar + 1), yPos + 0.5 * h - yValue - 2, widthBar, self.scale, @@ -84,7 +80,7 @@ if CLIENT then end draw.Box( - xPos + h + 3 + (i - 1) * (widthBar + 1), + xPos + h + offset + (i - 1) * (widthBar + 1), yPos + 0.5 * h, widthBar, self.scale, @@ -92,7 +88,7 @@ if CLIENT then ) draw.Box( - xPos + h + 3 + (i - 1) * (widthBar + 1), + xPos + h + offset + (i - 1) * (widthBar + 1), yPos + 0.5 * h + 2, widthBar, yValue, @@ -100,7 +96,7 @@ if CLIENT then ) if yValue > 1 then draw.Box( - xPos + h + 3 + (i - 1) * (widthBar + 1), + xPos + h + offset + (i - 1) * (widthBar + 1), yPos + 0.5 * h + 2 + yValue, widthBar, self.scale, @@ -131,6 +127,36 @@ if CLIENT then true, self.scale ) + + if + voicebattery.IsEnabled() + and ply == LocalPlayer() + and VOICE.GetVoiceMode(ply) == VOICE_MODE_GLOBAL + then + draw.Box( + xPos + h, + yPos + h - self.padding - heightBatteryBar, + w - h, + heightBatteryBar, + colorVoiceBar + ) + + draw.Box( + xPos + h, + yPos + h - self.padding - heightBatteryBar, + voicebattery.GetChargePercent() * (w - h), + heightBatteryBar, + colorVoiceLine + ) + end + + self:DrawLines( + xPos + self.padding, + yPos + self.padding, + w - self.padding, + heightBar, + color.a + ) end function HUDELEMENT:Draw() diff --git a/gamemodes/terrortown/gamemode/shared/sh_init.lua b/gamemodes/terrortown/gamemode/shared/sh_init.lua index 0d8444883..5b58d1a67 100644 --- a/gamemodes/terrortown/gamemode/shared/sh_init.lua +++ b/gamemodes/terrortown/gamemode/shared/sh_init.lua @@ -599,6 +599,7 @@ include("ttt2/libraries/loadingscreen.lua") include("ttt2/libraries/marker_vision.lua") include("ttt2/libraries/weaponrenderer.lua") include("ttt2/libraries/game_effects.lua") +include("ttt2/libraries/voicebattery.lua") -- include ttt required files ttt_include("sh_decal") diff --git a/gamemodes/terrortown/gamemode/shared/sh_main.lua b/gamemodes/terrortown/gamemode/shared/sh_main.lua index 39d680ab5..2d6d29ac7 100644 --- a/gamemodes/terrortown/gamemode/shared/sh_main.lua +++ b/gamemodes/terrortown/gamemode/shared/sh_main.lua @@ -507,7 +507,7 @@ function GM:Tick() RADIO:StoreTarget() end - VOICE.Tick() + voicebattery.Tick() end end diff --git a/lua/ttt2/libraries/voicebattery.lua b/lua/ttt2/libraries/voicebattery.lua new file mode 100644 index 000000000..c4ec84f21 --- /dev/null +++ b/lua/ttt2/libraries/voicebattery.lua @@ -0,0 +1,150 @@ +--- +-- This is the voice battery module that handles everything related to +-- the voice drain caused by speaking. +-- @author Mineotopia +-- @module voicebattery + +if SERVER then + AddCSLuaFile() +end + +--- +-- @realm server +-- stylua: ignore +local cvVoiceDrain = CreateConVar("ttt_voice_drain", "0", SERVER and {FCVAR_NOTIFY, FCVAR_ARCHIVE, FCVAR_REPLICATED} or FCVAR_REPLICATED) + +--- +-- @realm server +-- stylua: ignore +local cvVoiceDrainNormal = CreateConVar("ttt_voice_drain_normal", "0.2", SERVER and {FCVAR_NOTIFY, FCVAR_ARCHIVE, FCVAR_REPLICATED} or FCVAR_REPLICATED) + +--- +-- @realm server +-- stylua: ignore +local cvVoiceDrainAdmin = CreateConVar("ttt_voice_drain_admin", "0.05", SERVER and {FCVAR_NOTIFY, FCVAR_ARCHIVE, FCVAR_REPLICATED} or FCVAR_REPLICATED) + +--- +-- @realm server +-- stylua: ignore +local cvVoiceDrainRecharge = CreateConVar("ttt_voice_drain_recharge", "0.05", SERVER and {FCVAR_NOTIFY, FCVAR_ARCHIVE, FCVAR_REPLICATED} or FCVAR_REPLICATED) + +voicebattery = {} + +voicebattery.maxCharge = 100 +voicebattery.minCharge = 10 + +--- +-- Returns true if the voice battery is enabled. +-- @return boolean Voice battery state +-- @realm shared +function voicebattery.IsEnabled() + return cvVoiceDrain:GetBool() +end + +if CLIENT then + --- + -- Initializes the voice battery. + -- @realm client + function voicebattery.InitBattery() + voicebattery.SetCharge(voicebattery.maxCharge) + end + + --- + -- Returns the current charge of the voice battery. + -- @return number The battery charge + -- @realm client + function voicebattery.GetCharge() + return voicebattery.currentCharge or voicebattery.maxCharge + end + + --- + -- Sets the current charge of the voice battery. + -- @param[default=0] number Charge The new battery charge + -- @realm client + function voicebattery.SetCharge(charge) + voicebattery.currentCharge = charge or 0 + end + + --- + -- Returns the current charge percentage of the voice battery. + -- @return number The battery charge as a value from 0 to 1 + -- @realm client + function voicebattery.GetChargePercent() + return voicebattery.GetCharge() / voicebattery.maxCharge + end + + --- + -- Checks if the voice battery is charged enough to talk. + -- @return boolean Returns true if the player can talk + -- @realm client + function voicebattery.IsCharged() + return voicebattery.GetCharge() > voicebattery.minCharge + end + + --- + -- Returns the current voice drain recharge while not speaking. + -- @return number The voice battery recharge rate + -- @realm client + function voicebattery.GetRechargeRate() + local rate = cvVoiceDrainRecharge:GetFloat() + + if voicebattery.GetCharge() < voicebattery.minCharge then + rate = rate * 0.5 + end + + return rate + end + + --- + -- Returns the current voice drain rate while speaking. + -- @return number The voice battery drain rate + -- @realm client + function voicebattery.GetDrainRate() + local client = LocalPlayer() + + if + not IsValid(client) + or client:IsSpec() + or not voicebattery.IsEnabled() + or GetRoundState() ~= ROUND_ACTIVE + then + return 0 + end + + local subRoleData = client:GetSubRoleData() + + if client:IsSuperAdmin() or (subRoleData.isPublicRole and subRoleData.isPolicingRole) then + return cvVoiceDrainAdmin:GetFloat() + else + return cvVoiceDrainNormal:GetFloat() + end + end + + --- + -- Updates the voice battery + -- @note Called every @{GM:Tick} + -- @realm client + -- @internal + function voicebattery.Tick() + if not voicebattery.IsEnabled() then + return + end + + if VOICE.IsSpeaking() and not VOICE.IsRoleChatting(LocalPlayer()) then + voicebattery.SetCharge(voicebattery.GetCharge() - voicebattery.GetDrainRate()) + + if not VOICE.CanSpeak() then + voicebattery.SetCharge(0) + + permissions.EnableVoiceChat(false) + end + elseif voicebattery.GetCharge() < voicebattery.maxCharge then + voicebattery.SetCharge( + math.min( + voicebattery.maxCharge, + voicebattery.GetCharge() + voicebattery.GetRechargeRate() + ) + ) + end + end +end