--[[ | This file was obtained through the combined efforts | of Madbluntz & Plymouth Antiquarian Society. | | Credits: lifestorm, Gregory Wayne Rossel JR., | Maloy, DrPepper10 @ RIP, Atle! | | Visit for more: https://plymouth.thetwilightzone.ru/ --]] ---- HUD stuff similar to weapon/ammo pickups but for game status messages -- This is some of the oldest TTT code, and some of the first Lua code I ever -- wrote. It's not the greatest. MSTACK = {} MSTACK.msgs = {} MSTACK.last = 0 -- Localise some libs local table = table local surface = surface local draw = draw local pairs = pairs -- Constants for configuration local msgfont = "DefaultBold" local margin = 6 local msg_width = 400 local text_width = msg_width - (margin * 3) -- three margins for a little more room local text_height = draw.GetFontHeight(msgfont) local top_y = margin local top_x = ScrW() - margin - msg_width local staytime = 12 local max_items = 8 local fadein = 0.1 local fadeout = 0.6 local movespeed = 2 -- Text colors to render the messages in local msgcolors = { traitor_text = COLOR_RED, generic_text = COLOR_WHITE, generic_bg = Color(0, 0, 0, 200) }; -- Total width we take up on screen, for other elements to read MSTACK.width = msg_width + margin function MSTACK:AddColoredMessage(text, clr) local item = {} item.text = text item.col = clr item.bg = msgcolors.generic_bg self:AddMessageEx(item) end function MSTACK:AddColoredBgMessage(text, bg_clr) local item = {} item.text = text item.col = msgcolors.generic_text item.bg = bg_clr self:AddMessageEx(item) end local ttt_msg_soundcue = CreateClientConVar("ttt_cl_msg_soundcue", "0", true) -- Internal function MSTACK:AddMessageEx(item) item.col = table.Copy(item.col or msgcolors.generic_text) item.col.a_max = item.col.a item.bg = table.Copy(item.bg or msgcolors.generic_bg) item.bg.a_max = item.bg.a item.text = self:WrapText(item.text, text_width) -- Height depends on number of lines, which is equal to number of table -- elements of the wrapped item.text item.height = (#item.text * text_height) + (margin * (1 + #item.text)) item.time = CurTime() item.sounded = not ttt_msg_soundcue:GetBool() item.move_y = -item.height -- Stagger the fading a bit if self.last > (item.time - 1) then item.time = self.last + 1 --item.time + 1 end -- Insert at the top table.insert(self.msgs, 1, item) self.last = item.time end -- Add a given message to the stack, will be rendered in a different color if it -- is a special traitor-only message that traitors should pay attention to. -- Use the newer AddColoredMessage if you want special colours. function MSTACK:AddMessage(text, traitor_only) self:AddColoredBgMessage(text, traitor_only and msgcolors.traitor_bg or msgcolors.generic_bg) end -- Oh joy, I get to write my own wrapping function. Thanks Lua! -- Splits a string into a table of strings that are under the given width. function MSTACK:WrapText(text, width) surface.SetFont(msgfont) -- Any wrapping required? local w, _ = surface.GetTextSize(text) if w <= width then return {text} -- Nope, but wrap in table for uniformity end local lines = {""} for i, wrd in ipairs(string.Explode(" ", text)) do -- No spaces means you're screwed local l = #lines local added = lines[l] .. " " .. wrd w, _ = surface.GetTextSize(added) if w > text_width then -- New line needed table.insert(lines, wrd) else -- Safe to tack it on lines[l] = added end end return lines end sound.Add({ name = "TTT.MessageCue", channel = CHAN_STATIC, volume = 1.0, level = SNDLVL_NONE, pitch = 100, sound = "ui/hint.wav" }) local msg_sound = Sound("TTT.MessageCue") local base_spec = { font = msgfont, xalign = TEXT_ALIGN_CENTER, yalign = TEXT_ALIGN_TOP }; function MSTACK:Draw(client) if next(self.msgs) == nil then return end -- fast empty check local running_y = top_y for k, item in pairs(self.msgs) do if item.time < CurTime() then if item.sounded == false then client:EmitSound(msg_sound, 80, 250) item.sounded = true end -- Apply move effects to y local y = running_y + margin + item.move_y item.move_y = (item.move_y < 0) and item.move_y + movespeed or 0 local delta = (item.time + staytime) - CurTime() delta = delta / staytime -- pct of staytime left -- Hurry up if we have too many if k >= max_items then delta = delta / 2 end local alpha = 255 -- These somewhat arcane delta and alpha equations are from gmod's -- HUDPickup stuff if delta > 1 - fadein then alpha = math.Clamp( (1.0 - delta) * (255 / fadein), 0, 255) elseif delta < fadeout then alpha = math.Clamp( delta * (255 / fadeout), 0, 255) end local height = item.height -- Background box item.bg.a = math.Clamp(alpha, 0, item.bg.a_max) draw.RoundedBox(8, top_x, y, msg_width, height, item.bg) -- Text item.col.a = math.Clamp(alpha, 0, item.col.a_max) local spec = base_spec spec.color = item.col for i = 1, #item.text do spec.text=item.text[i] local tx = top_x + (msg_width / 2) local ty = y + margin + (i - 1) * (text_height + margin) spec.pos={tx, ty} draw.TextShadow(spec, 1, alpha) end if alpha == 0 then self.msgs[k] = nil end running_y = y + height end end end -- Game state message channel local function ReceiveGameMsg() local text = net.ReadString() local special = net.ReadBit() == 1 print(text) MSTACK:AddMessage(text, special) end net.Receive("TTT_GameMsg", ReceiveGameMsg) local function ReceiveCustomMsg() local text = net.ReadString() local clr = Color(255, 255, 255) clr.r = net.ReadUInt(8) clr.g = net.ReadUInt(8) clr.b = net.ReadUInt(8) print(text) MSTACK:AddColoredMessage(text, clr) end net.Receive("TTT_GameMsgColor", ReceiveCustomMsg)