Voice Battery Drain like TTT but for other game modes?

Is there a way to implement this:

But for other game modes such as: Prop Hunt, Hide and Seek, and Murder?

My guess is you would have to do it manually with

and

Starts here on TTT

No idea how to even use that. I’d willing to pay for an addon that I could plop into any game mode.

It’s really easy, don’t waste your time on paying for one. I’ll see if I can’t quickly throw together a clientsided only one.

Can’t be clientsided only :frowning:
It might take me a little longer.

That would be awesome, thank you!

This would be far easier if the client could selectively mute people, or the server knew ( without asking the client ) when a player started or stopped talking. There isn’t, so we have to fudge it.

This is a pure client implementation:


if SERVER then
	local flags = FCVAR_ARCHIVE + FCVAR_REPLICATED + FCVAR_NOTIFY
	CreateConVar( "g_voice_drain", "0", flags, "Enables or disables voice drain"  )
	CreateConVar( "g_voice_drain_amt", ".2", flags, "How much to drain voice power by each tick" )
	CreateConVar( "g_voice_drain_admin", ".05", flags, "How much an admin's voice is drained each tick" )
	CreateConVar( "g_voice_drain_recharge", ".05", flags, "How much to recharge a voice by each tick" )
else
	local drain_enabled = GetConVar( "g_voice_drain" )
	local drain_rate = GetConVar( "g_voice_drain_amt" )
	local drain_admin = GetConVar( "g_voice_drain_admin" )
	local drain_recharge = GetConVar( "g_voice_drain_recharge" )
	
	local function PlayerStartVoice( pl )
		pl.Speaking = true
	end
	
	local function PlayerEndVoice( pl )
		pl.Speaking = false
	end
	
	local function Tick( )
		local k, v
		
		for k, v in pairs( player.GetHumans( ) ) do
			v.fVoicePower = v.fVoicePower or 100
			
			if v.Speaking then
				v.fVoicePower = math.max( 0, v.fVoicePower - ( v:IsAdmin( ) and drain_admin:GetFloat( ) or drain_rate:GetFloat( ) )
			else
				v.fVoicePower = math.min( 100, v.fVoicePower + drain_recharge:GetFloat( ) )
			end
			
			if v.Speaking and v.fVoicePower == 0 then
				v:SetMuted( true )
			end
			
			if not v.Speaking and v.fVoicePower == 100 then
				v:SetMuted( false )
			end
		end
	end
	
	hook.Add( "PlayerStartVoice", "VoiceBattery.PlayerStartVoice", PlayerStartVoice )
	hook.Add( "PlayerEndVoice", "VoiceBattery.PlayerEndVoice", PlayerEndVoice )
	hook.Add( "Tick", "VoiceBattery.Tick", Tick )
end

I haven’t tested it, but the gist of it is that each client is responsible for tracking the battery themselves and the server just handles the configuration, so you end up with a few problems:

It isn’t synchronized - some people will be muted to some players and not to others, depending on how much they are talking and when they joined - until they go the recharge period without speaking. This isn’t ideal because it isn’t completely obvious.

It relies on fudging the mute state, which I don’t know if it messes with the PlayerStartVoice / PlayerEndVoice hooks. I also don’t know how SetMuted interacts with IsSpeaking, so if they don’t conflict a hooking the Start/End events wouldn’t be needed.

A mixed approach using PlayerCanHearPlayerVoice and having the client report when they are talking ( and completely mute them when they aren’t ) would be better, but would require more time.

Instead of muting people it would be better to just stop them from talking. Then the person talking knows when they are done and you don’t have to worry about people being muted when they shouldn’t.



--Made by pandaman09
if CLIENT then
	CreateClientConVar( "voice_enabled", 0, false, true )

	local function VoiceDrainStart(ply)
		--Entity(1):ChatPrint("Chat Start")
		local cl = LocalPlayer()
		if !IsValid(cl) or !(ply==cl) then return end
		
		net.Start("voice_toggle")
			net.WriteBit(true)
		net.SendToServer()

	end
	hook.Add("PlayerStartVoice", "voice_drain_start", VoiceDrainStart)

	local function VoiceDrainEnd(ply)
		--Entity(1):ChatPrint("Chat End")
		local cl = LocalPlayer()
		if !IsValid(cl) or !(ply==cl) then return end
		
		net.Start("voice_toggle")
			net.WriteBit(false)
		net.SendToServer()

	end
	hook.Add("PlayerEndVoice", "voice_drain_end", VoiceDrainEnd)

	net.Receive( "voice_toggle_cl", function( length, client )
		RunConsoleCommand("-voicerecord")
   	end )

else
	util.AddNetworkString( "voice_toggle" )
	util.AddNetworkString( "voice_toggle_cl" )
        --config
	local voice_max_time = 5
	local voice_drain = 0.1 --in a 1/10 of a second
	local voice_regen = 0.05 --in a 1/10 of a second
	local use3d = false
        --config
	local next_think = CurTime()
	
	net.Receive( "voice_toggle", function( length, client )
            client.isTalking = net.ReadBit()
   	end )

	local function VoiceDrainThink()
		if !(CurTime()>=next_think) then return end
		for k,v in pairs(player.GetAll()) do
			if !v.talkTime then v.talkTime = 5 end
			local voice_enabled = v.isTalking or false
			local voice_time = v.talkTime
			local time = 0

			if voice_enabled==1 and (voice_time > 0) then
				time = voice_time - voice_drain
			elseif voice_enabled==0 and (voice_time < voice_max_time) then
				time = voice_time + voice_regen
			end
			v.talkTime = math.Clamp(time,0,voice_max_time)
			if v.talkTime <= 0 and v.isTalking then
				net.Start("voice_toggle_cl")
					net.WriteBit(false)
				net.Send(v)
			end
			--Entity(1):ChatPrint("P:"..v:Nick().."E:"..tostring(voice_enabled or false).." T:"..(voice_time or 0))
		end
		next_think = CurTime() + 0.1
	end
	hook.Add("Think","voice_drain_think", VoiceDrainThink)
end
--hook.Remove("PlayerStartVoice", "voice_drain_start") hook.Remove("PlayerEndVoice", "voice_drain_end") hook.Remove("Think","voice_drain_think") hook.Remove("PlayerCanHearPlayersVoice","voice_drain_hear")