diff --git a/RELEASE.md b/RELEASE.md index c83762093..0631c548e 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -13,12 +13,14 @@ ### Changes - Updated weapon switch and pickup HUD elements to use the same logic for getting weapon names - Fixes very rare cases where they would say different things +- Ported "TTT: Add custom T Radio sound support and extra default sounds" from base TTT ### Fixes - Fixed illusionist not blocking traitor team voice chat - Fixed promoted impersonator and deputy who are searched by a detective not always showing their true role on the scoreboard ### Developer +- Ported "signed" parameter added to `util.BitsRequired` from base TTT - Added `state` parameter to `TTTTeamVoiceChatTargets` hook - Added `table.GetFirstItemWithPropertyValue` static method - Added `maxchange` parameter to `TTTVampireBodyEaten` hook diff --git a/gamemodes/terrortown/entities/entities/ttt_radio.lua b/gamemodes/terrortown/entities/entities/ttt_radio.lua index 909e178a1..ae181fec8 100644 --- a/gamemodes/terrortown/entities/entities/ttt_radio.lua +++ b/gamemodes/terrortown/entities/entities/ttt_radio.lua @@ -14,16 +14,15 @@ local MathRand = math.Rand local MathRandom = math.random local SoundPlay = sound.Play local TableAdd = table.Add -local TableHasValue = table.HasValue local TableInsert = table.insert local TableRandom = table.Random local TableRemove = table.remove local TimerSimple = timer.Simple if CLIENT then - -- this entity can be DNA-sampled so we need some display info - ENT.Icon = "vgui/ttt/icon_radio" - ENT.PrintName = "radio_name" + -- this entity can be DNA-sampled so we need some display info + ENT.Icon = "vgui/ttt/icon_radio" + ENT.PrintName = "radio_name" end ENT.Type = "anim" @@ -116,162 +115,73 @@ function ENT:AddSound(snd) end end -local simplesounds = { - scream = { - Sound("vo/npc/male01/pain07.wav"), - Sound("vo/npc/male01/pain08.wav"), - Sound("vo/npc/male01/pain09.wav"), - Sound("vo/npc/male01/no02.wav") - }, - explosion = { - Sound("BaseExplosionEffect.Sound") - } -}; - -local serialsounds = { - footsteps = { - sound = { - {Sound("player/footsteps/concrete1.wav"), Sound("player/footsteps/concrete2.wav")}, - {Sound("player/footsteps/concrete3.wav"), Sound("player/footsteps/concrete4.wav")} - }, - times = {8, 16}, - delay = 0.35, - ampl = 80 - }, - - burning = { - sound = { - Sound("General.BurningObject"), - Sound("General.StopBurning") - }, - times = {2, 2}, - delay = 4, - }, - - - beeps = { - sound = { Sound("weapons/c4/c4_beep1.wav") }, - delay = 0.75, - times = {8, 12}, - ampl = 70 - } -}; - -local gunsounds = { - shotgun = { - sound = Sound( "Weapon_XM1014.Single" ), - delay = 0.8, - times = {1, 3}, - burst = false - }, - - pistol = { - sound = Sound( "Weapon_FiveSeven.Single" ), - delay = 0.4, - times = {2, 4}, - burst = false - }, - - mac10 = { - sound = Sound( "Weapon_mac10.Single" ), - delay = 0.065, - times = {5, 10}, - burst = true - }, - - deagle = { - sound = Sound( "Weapon_Deagle.Single" ), - delay = 0.6, - times = {1, 3}, - burst = false - }, - - m16 = { - sound = Sound( "Weapon_M4A1.Single" ), - delay = 0.2, - times = {1, 5}, - burst = true - }, - - rifle = { - sound = Sound( "weapons/scout/scout_fire-1.wav" ), - delay = 1.5, - times = {1, 1}, - burst = false, - ampl = 80 - }, - - huge = { - sound = Sound( "Weapon_m249.Single" ), - delay = 0.055, - times = {6, 12}, - burst = true - } -}; - function ENT:PlayDelayedSound(snd, ampl, last) -- maybe we can get destroyed while a timer is still up - if IsValid(self) then - if istable(snd) then - snd = TableRandom(snd) - end + if not IsValid(self) then return end - if self.BroadcastSound then - self:BroadcastSound(snd, ampl) - else - SoundPlay(snd, self:GetPos(), ampl) - end - self.Playing = not last + if istable(snd) then + snd = TableRandom(snd) + end + + if self.BroadcastSound then + self:BroadcastSound(snd, ampl) + else + SoundPlay(snd, self:GetPos(), ampl) end + + self.Playing = not last end function ENT:PlaySound(snd) - local pos = self:GetPos() - local this = self - if simplesounds[snd] then - if self.BroadcastSound then - self:BroadcastSound(TableRandom(simplesounds[snd])) + local soundData = TRADIO.Sounds[snd] + if not soundData then return end + + if hook.Run("TTTRadioPlaySound", self, snd, soundData) == true then return end + + local sndlist = soundData.sound + local ampl = soundData.ampl + + local serial = soundData.serial + local times = soundData.times + if serial or times then + local num = istable(sndlist) and #sndlist or 1 + + if times then + times = istable(times) and MathRandom(times[1], times[2]) or times else - SoundPlay(TableRandom(simplesounds[snd]), pos) + times = num end - elseif gunsounds[snd] then - local gunsound = gunsounds[snd] - local times = MathRandom(gunsound.times[1], gunsound.times[2]) - local t = 0 - for i=1, times do - TimerSimple(t, - function() - if IsValid(this) then - this:PlayDelayedSound(gunsound.sound, gunsound.ampl or 90, i == times) - end - end) - - if gunsound.burst then - t = t + gunsound.delay - else - t = t + MathRand(gunsound.delay, gunsound.delay * 2) + + if times > 1 then + local delay = soundData.delay + local idx = 1 + + local t = 0 + for i = 1, times do + local sndpath = serial and sndlist[idx] or sndlist + + TimerSimple(t, + function() + -- maybe we can get destroyed while a timer is still up + if not IsValid(self) then return end + + self:PlayDelayedSound(sndpath, ampl, i == times) + end) + + local d = istable(delay) and MathRand(delay[1], delay[2]) or delay + t = t + d + + if serial then + idx = idx + 1 + if idx > num then idx = 1 end + end end - end - elseif serialsounds[snd] then - local serialsound = serialsounds[snd] - local num = #serialsound.sound - local times = MathRandom(serialsound.times[1], serialsound.times[2]) - local t = 0 - local idx = 1 - for i=1, times do - local chosen = serialsound.sound[idx] - TimerSimple(t, - function() - if IsValid(this) then - this:PlayDelayedSound(chosen, serialsound.ampl or 75, i == times) - end - end) - - t = t + serialsound.delay - idx = idx + 1 - if idx > num then idx = 1 end + + return end end + + self:PlayDelayedSound(sndlist, ampl, true) end local nextplay = 0 @@ -288,13 +198,6 @@ function ENT:Think() end if SERVER then - local soundtypes = { - "scream", "shotgun", "explosion", - "pistol", "mac10", "deagle", - "m16", "rifle", "huge", - "burning", "beeps", "footsteps" - }; - local function RadioCmd(ply, cmd, args) if not IsValid(ply) then return end if #args ~= 2 then return end @@ -308,7 +211,7 @@ if SERVER then if radio:GetOwner() ~= ply then return end if radio:GetClass() ~= "ttt_radio" then return end - if not TableHasValue(soundtypes, snd) then + if not TRADIO.Sounds[snd] then print("Received radio sound not in table from", ply) return end diff --git a/gamemodes/terrortown/gamemode/cl_radio.lua b/gamemodes/terrortown/gamemode/cl_radio.lua new file mode 100644 index 000000000..9117236dd --- /dev/null +++ b/gamemodes/terrortown/gamemode/cl_radio.lua @@ -0,0 +1,83 @@ +--- Traitor radio controls + +local math = math +local vgui = vgui + +local GetTranslation = LANG.GetTranslation +local TryTranslation = LANG.TryTranslation + +TRADIO.SoundOrder = { + "scream", "burning", "explosion", "footsteps", + "pistol", "shotgun", "mac10", "deagle", + "m16", "rifle", "huge", "glock", + "beeps", "sipistol", "teleport", "hstation" +}; + +local function PlayRadioSound(snd) + local r = LocalPlayer().radio + if IsValid(r) then + RunConsoleCommand("ttt_radio_play", tostring(r:EntIndex()), snd) + end +end + +local function ButtonClickPlay(s) PlayRadioSound(s.snd) end + +local columns = 4 +local rows = 5 + +local bh, bw = 50, 100 +local m = 5 + +local function CreateSoundBoard(parent) + local b = vgui.Create("DScrollPanel", parent) + + local sorder = TRADIO.SoundOrder + local ver = math.min(math.ceil(#sorder / columns), rows) + local sbar = ver == rows and b:GetVBar():GetWide() or 0 + + b:SetSize(bw * columns + m * (columns - 1) + sbar, bh * ver + m * (ver - 1)) + b:SetPos(m, 25) + b:CenterHorizontal() + + local grid = vgui.Create("DIconLayout", b) + grid:Dock(FILL) + grid:SetSpaceX(m) + grid:SetSpaceY(m) + + for ri, snd in ipairs(sorder) do + local but = grid:Add("DButton") + but:SetSize(bw, bh) + but:SetText(TryTranslation(TRADIO.Sounds[snd].name)) + but.snd = snd + but.DoClick = ButtonClickPlay + end + + return b +end + +function TRADIO.CreateMenu(parent) + local w, h = parent:GetSize() + + local client = LocalPlayer() + + local wrap = vgui.Create("DPanel", parent) + wrap:SetSize(w, h) + wrap:SetPaintBackground(false) + + local dhelp = vgui.Create("DLabel", wrap) + dhelp:SetFont("TabLarge") + dhelp:SetText(GetTranslation("radio_help")) + dhelp:SetTextColor(COLOR_WHITE) + + if IsValid(client.radio) then + CreateSoundBoard(wrap) + elseif client:HasWeapon("weapon_ttt_radio") then + dhelp:SetText(GetTranslation("radio_notplaced")) + end + + dhelp:SizeToContents() + dhelp:SetPos(10, 5) + dhelp:CenterHorizontal() + + return wrap +end \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/init.lua b/gamemodes/terrortown/gamemode/init.lua index c51ecf2da..213bcd561 100644 --- a/gamemodes/terrortown/gamemode/init.lua +++ b/gamemodes/terrortown/gamemode/init.lua @@ -24,6 +24,7 @@ AddCSLuaFile("lang_shd.lua") AddCSLuaFile("corpse_shd.lua") AddCSLuaFile("player_ext_shd.lua") AddCSLuaFile("weaponry_shd.lua") +AddCSLuaFile("radio_shd.lua") AddCSLuaFile("cl_radio.lua") AddCSLuaFile("cl_radar.lua") AddCSLuaFile("cl_tbuttons.lua") diff --git a/gamemodes/terrortown/gamemode/lang/english.lua b/gamemodes/terrortown/gamemode/lang/english.lua index 0da23eb01..bf13f54b3 100644 --- a/gamemodes/terrortown/gamemode/lang/english.lua +++ b/gamemodes/terrortown/gamemode/lang/english.lua @@ -150,7 +150,10 @@ L.radio_button_huge = "H.U.G.E burst" L.radio_button_c4 = "C4 beeping" L.radio_button_burn = "Burning" L.radio_button_steps = "Footsteps" - +L.radio_button_glock = "Glock shots" +L.radio_button_sipist = "Silenced shots" +L.radio_button_tele = "Teleport" +L.radio_button_heal = "Healing" -- Intro screen shown after joining L.intro_help = "If you're new to the game, press F1 for instructions!" diff --git a/gamemodes/terrortown/gamemode/radio_shd.lua b/gamemodes/terrortown/gamemode/radio_shd.lua new file mode 100644 index 000000000..26fe2e85a --- /dev/null +++ b/gamemodes/terrortown/gamemode/radio_shd.lua @@ -0,0 +1,189 @@ +--- Traitor radio sounds + +local table = table + +TRADIO = TRADIO or {} + +-- This table contains every sound that can be played by the Radio traitor item. +-- +-- It also contains settings that change how the sound is displayed on the client, +-- or how the sound is played on the server: +-- +-- name: The name of the sound shown in the T menu. Can be localized. +-- sound: The sound to be played, or a table of sounds to pick from randomly. +-- serial: If true, play through the sound table in sequential order instead of randomly. +-- times: The number of times to repeat the sound. If set to a table, randomizes the number of times within the range {min, max}. +-- delay: The delay between sound repetitions. If set to a table, randomizes the delay within the range {min, max}. +-- ampl: The sound level. See https://wiki.facepunch.com/gmod/Enums/SNDLVL +-- +-- If serial = true, you can nest multiple sound tables within the sound table. +-- This will cause the radio to choose a random sound from the first table, +-- then on the next repetition, choose a random sound from the next table, +-- and so on. See footsteps (lines 70-80) for an example of this. +-- +-- +-- If you want to add custom sounds to the radio, use TRADIO.AddNewSound in a shared lua file. +-- For example: +-- TRADIO.AddNewSound("glock", { +-- name = "Glock shots", +-- sound = Sound("Weapon_Glock.single"), +-- delay = 0.1, +-- times = {4, 8}, +-- ampl = 90 +-- }) +-- +-- If you want to overwrite an existing sound, you can simply modify TRADIO.Sounds directly. +-- For example: +-- TRADIO.Sounds.explosion = { +-- name = "Balloon pop!", +-- sound = Sound("garrysmod/balloon_pop_cute.wav") +-- } + +TRADIO.Sounds = { + -- Simple Sounds + scream = { + name = "radio_button_scream", + sound = { + Sound("vo/npc/male01/pain07.wav"), + Sound("vo/npc/male01/pain08.wav"), + Sound("vo/npc/male01/pain09.wav"), + Sound("vo/npc/male01/no02.wav") + } + }, + explosion = { + name = "radio_button_expl", + sound = Sound("BaseExplosionEffect.Sound") + }, + beeps = { + name = "radio_button_c4", + sound = Sound("weapons/c4/c4_beep1.wav"), + delay = 0.75, + times = {8, 12}, + ampl = 70 + }, + hstation = { + name = "radio_button_heal", + sound = Sound("items/medshot4.wav"), + delay = 2, + times = {4, 8} + }, + + -- Serial Sounds + footsteps = { + name = "radio_button_steps", + sound = { + {Sound("player/footsteps/concrete1.wav"), Sound("player/footsteps/concrete2.wav")}, + {Sound("player/footsteps/concrete3.wav"), Sound("player/footsteps/concrete4.wav")} + }, + serial = true, + times = {8, 16}, + delay = 0.35, + ampl = 80 + }, + + burning = { + name = "radio_button_burn", + sound = { + Sound("General.BurningObject"), + Sound("General.StopBurning") + }, + serial = true, + delay = 4, + }, + + teleport = { + name = "radio_button_tele", + sound = { + Sound("ambient/levels/labs/teleport_mechanism_windup1.wav"), + Sound("ambient/levels/labs/electric_explosion4.wav") + }, + serial = true, + delay = 1 + }, + + -- Gun Sounds + shotgun = { + name = "radio_button_shotgun", + sound = Sound( "Weapon_XM1014.Single" ), + delay = {0.8, 1.6}, + times = {1, 3}, + ampl = 90 + }, + + pistol = { + name = "radio_button_pistol", + sound = Sound( "Weapon_FiveSeven.Single" ), + delay = {0.4, 0.8}, + times = {2, 4}, + ampl = 90 + }, + + mac10 = { + name = "radio_button_mac10", + sound = Sound( "Weapon_mac10.Single" ), + delay = 0.065, + times = {5, 10}, + ampl = 90 + }, + + deagle = { + name = "radio_button_deagle", + sound = Sound( "Weapon_Deagle.Single" ), + delay = {0.6, 1.2}, + times = {1, 3}, + ampl = 90 + }, + + m16 = { + name = "radio_button_m16", + sound = Sound( "Weapon_M4A1.Single" ), + delay = 0.2, + times = {1, 5}, + ampl = 90 + }, + + rifle = { + name = "radio_button_rifle", + sound = Sound( "weapons/scout/scout_fire-1.wav" ), + ampl = 80 + }, + + huge = { + name = "radio_button_huge", + sound = Sound( "Weapon_m249.Single" ), + delay = 0.055, + times = {6, 12}, + ampl = 90 + }, + + glock = { + name = "radio_button_glock", + sound = Sound("Weapon_Glock.single"), + delay = 0.1, + times = {4, 8}, + ampl = 90 + }, + + sipistol = { + name = "radio_button_sipist", + sound = Sound("Weapon_USP.SilencedShot"), + delay = {0.38, 0.76}, + times = {2, 4}, + ampl = 50 + } +} + +function TRADIO.AddNewSound(key, soundData) + local newkey = key + local i = 1 + while TRADIO.Sounds[newkey] do + newkey = key .. tostring(i) + i = i + 1 + end + + TRADIO.Sounds[newkey] = soundData + + if CLIENT then + table.insert(TRADIO.SoundOrder, newkey) + end +end diff --git a/gamemodes/terrortown/gamemode/shared.lua b/gamemodes/terrortown/gamemode/shared.lua index def8ff8e3..7dd64e2fe 100644 --- a/gamemodes/terrortown/gamemode/shared.lua +++ b/gamemodes/terrortown/gamemode/shared.lua @@ -1553,6 +1553,7 @@ COLOR_CYAN = Color(0, 255, 255, 255) include("lang_shd.lua") -- uses some of util include("equip_items_shd.lua") +include("radio_shd.lua") function DetectiveMode() return GetGlobalBool("ttt_detective", false) end function HasteMode() return GetGlobalBool("ttt_haste", false) end