local chat = unity.RegisterModule( "chat" ) local network = unity.network function chat.SendMessage( msg ) network.Start( "unity_chatmessage" ) network.WriteString( msg ) network.Send() end local function ValidMessage( msg ) return msg and type(msg) == "string" and msg:len() > 0 end local PANEL = {} AccessorFunc( PANEL, "Padding", "Padding" ) AccessorFunc( PANEL, "Shadow", "ShadowEnabled" ) function PANEL:Init() self.text = "" self.lines = {} self.fonts = {} self.colors = {} self:SetShadowEnabled( true ) self:SetPadding( 5 ) end local function DrawText( x, y, color, font, text, alpha, shadow ) surface.SetFont( font ) if shadow then surface.SetTextColor( Color( 0, 0, 0, alpha and ( color.a * alpha * 0.95 ) or 242 ) ) surface.SetTextPos( x + 1, y + 1 ) surface.DrawText( text ) end surface.SetTextColor( alpha and Color( color.r, color.g, color.b, color.a * alpha ) or color ) surface.SetTextPos( x, y ) surface.DrawText( text ) end function PANEL:PaintLines( ox, oy, alpha ) local sx, sy = self:LocalToScreen( 0, 0 ) local w, h = self:GetSize() local l, t, r, b = sx, sy, sx + w, sy + h local parent = self:GetParent() while IsValid( parent ) do local x, y = parent:LocalToScreen( 0, 0 ) local w, h = parent:GetSize() if x > l then l = x end if x + w < r then r = x + w end if y > t then t = y end if y + h < b then b = y + h end parent = parent:GetParent() end rx, ry = l - sx, t - sy local rw, rh = r - l, t - b local text, lines, colors, fonts, padding, iox, ioy, alpha = self.text, self.lines, self.colors, self.fonts, self.Padding, ox, oy, alpha local shadow = self.Shadow local color, font = colors[ 0 ] or Color( 255, 255, 255, 255 ), fonts[ 0 ] or "UChatFont" local line_offset = lines[ 0 ] or 0 surface.SetTextColor( alpha and Color( color.r, color.g, color.b, color.a * alpha ) or color ) local ox, oy = ( iox or 0 ) + ( padding or 0 ), ( ioy or 0 ) + ( padding or 0 ) local lh = 0 local cur_text, char = "" for i=1, text:len() do char = text:sub( i, i ) if char ~= "\n" then cur_text = cur_text .. char end if colors[ i ] or fonts[ i ] or lines[ i ] then surface.SetFont( font ) local tw, th = surface.GetTextSize( cur_text ) if th > lh then lh = th end if oy + th >= ry and oy >= ry + rh and ox + tw >= rx and ox <= rx + rw then DrawText( ox, oy, color, font, cur_text, alpha, shadow ) end cur_text = "" if colors[ i ] or fonts[ i ] then ox = ox + tw font = fonts[ i ] or font color = colors[ i ] or color end if lines[ i ] then line_offset = lines[ i ] ox = ( iox or 0 ) + ( padding or 0 ) oy = oy + lh lh = 0 end end end surface.SetFont( font ) local tw, th = surface.GetTextSize( cur_text ) if th > lh then lh = th end if oy + th >= ry and oy >= ry + rh and ox + tw >= rx and ox <= rx + rw then DrawText( ox, oy, color, font, cur_text, alpha, shadow ) end end function PANEL:Paint( w, h ) self:PaintLines() end function PANEL:AppendText( str ) self.text = self.text .. str self:SetTall( self:RecalculateLines() ) self.LastUpdate = RealTime() --self:InvalidateLayout() end function PANEL:InsertColor( color ) self.colors[ self.text:len() ] = color end function PANEL:InsertFont( font ) self.fonts[ self.text:len() ] = font end function PANEL:RecalculateLines() self.lines = {} --local running_height, text, begin, lastspace, char, line, tw, th = 0, self.text, 1, 1 local text, char, cur_text, rh, lastspace = self.text, "", "", 0, 1 local should_space = false local lw, lh = 0, 0 surface.SetFont( self.fonts[ 0 ] or "UChatFont" ) for i = 1, text:len() do char = text:sub( i, i ) if char ~= "\n" then cur_text = cur_text .. char end tw, th = surface.GetTextSize( cur_text ) if self.fonts[ i ] then lw = lw + tw surface.SetFont( self.fonts[ i ] ) cur_text = "" end if th > lh then lh = th end if char == "\n" then self.lines[ i ] = rh rh = rh + lh lastspace = i + 1 should_space = false lw, lh = 0, 0 cur_text = "" else if char:find( "%s" ) then lastspace = i should_space = true end if lw + tw + self.Padding > self:GetWide() - self.Padding * 2 then if should_space then self.lines[ lastspace ] = rh cur_text = cur_text:sub( -( i - lastspace ) ) else self.lines[ i ] = rh cur_text = "" end rh = rh + lh lastspace = i + 1 should_space = false lw, lh = 0, 0 end end end rh = rh + lh return rh + self.Padding * 2 end function PANEL:PerformLayout() self:SetWidth( self:GetParent():GetWide() ) self:SetHeight( self:RecalculateLines() ) end vgui.Register( "UChatText", PANEL ) local PANEL = {} surface.CreateFont( "Verdana", 15, 700, true, false, "UChatFont" ) function PANEL:Init() self.TextPanel = vgui.Create( "UChatText", self ) self.ScrollPanel = vgui.Create( "DScrollPanel", self ) self.ScrollPanel:AddItem( self.TextPanel ) self.TextEntry = vgui.Create( "DTextEntry", self ) self.TextEntry:SetDrawBorder( false ) self.TextEntry:SetDrawBackground( false ) self.TextEntry:SetMultiline( false ) self.TextEntry:SetTextColor( 35, 35, 35, 255 ) self.TextEntry.Paint = function( entry, w, h ) surface.SetDrawColor( 200, 200, 200, 255 ) surface.DrawRect( 0, 0, w, h ) surface.SetDrawColor( 255, 255, 255, 255 ) surface.DrawRect( 1, 1, w - 2, h - 2 ) entry:DrawTextEntryText( Color( 35, 35, 35, 255 ), Color( 30, 130, 255, 255 ), Color( 35, 35, 35, 255 ) ) end self.TextEntry.OnKeyCodeTyped = function( entry, code ) if code == KEY_ENTER and not input.IsKeyDown( KEY_LCONTROL ) then entry:OnEnter() end end self.TextEntry:SetDrawLanguageIDAtLeft( true ) self.TextEntry:SetTextColor( color_black ) self.TextEntry:SetDrawBorder( true ) --self.TextEntry:Dock( BOTTOM ) self.TextEntry:SetAllowNonAsciiCharacters( true ) self.TextEntry.OnEnter = function( entry ) local msg = entry:GetValue() if not ValidMessage( msg ) then entry:GetParent():Close() return end --RunConsoleCommand( "say", msg ) chat.SendMessage( msg ) entry:SetText( "" ) entry:GetParent():Close() end function self.TextEntry:OnTextChanged() local msg = self:GetValue() hook.Call( "ChatTextChanged", GAMEMODE, msg ) end end function PANEL:PerformLayout() local w, h = self:GetSize() self.ScrollPanel:SetPos( 0, 0 ) self.ScrollPanel:SetSize( w, h - 15 ) self.TextEntry:SetPos( 0, h - 15 ) self.TextEntry:SetSize( w, 15 ) end function PANEL:Think() --self.BaseClass.Think( self ) if input.IsKeyDown(KEY_ESCAPE) then self:Close() return false end end function PANEL:SetOpen( b ) self.IsOpen = b self:SetVisible( b ) self.TextEntry:SetVisible( b ) local VBAR = chat.panel.ScrollPanel:GetVBar() if VBAR then VBAR:SetVisible( b ) end if b then hook.Call( "StartChat", GAMEMODE, false ) hook.Call( "ChatTextChanged", GAMEMODE, "" ) --gui.EnableScreenClicker( true ) self.TextEntry:RequestFocus() self:MakePopup() LocalPlayer():ConCommand("con_enable 0") else hook.Call( "ChatTextChanged", GAMEMODE, "" ) timer.Simple( 0, function() hook.Call( "FinishChat", GAMEMODE ) end ) --gui.EnableScreenClicker( false ) LocalPlayer():ConCommand("con_enable 1") end end function PANEL:Close() self:SetOpen( false ) end --[[function PANEL:Paint( w, h ) surface.SetDrawColor( 0, 0, 0, 200 ) surface.DrawRect( 0, 0, w, h ) end]] vgui.Register( "UChat", PANEL, "EditablePanel" ) local o_AddText = _G.chat.AddText function _G.chat.AddText( ... ) if o_AddText then o_AddText( ... ) end if not chat.panel then return end local textpanel = chat.panel.TextPanel textpanel:InsertColor( Color( 255, 255, 255, 255 ) ) textpanel:InsertFont( "UChatFont" ) for _, v in ipairs( { ... } ) do if type( v ) == "Player" and IsValid( v ) then local c = team.GetColor( v:Team() ) textpanel:InsertColor( c ) textpanel:AppendText( v:Nick() or "UNKNOWN" ) textpanel:InsertColor( Color( 255, 255, 255, 255 ) ) elseif type( v ) == "Entity" and IsValid( v ) then elseif type( v ) == "string" then textpanel:AppendText( v ) elseif type( v ) == "table" and v.r and v.b and v.g and v.a then textpanel:InsertColor( v ) end end textpanel:AppendText( "\n" ) chat.panel.ScrollPanel:PerformLayout() local VBAR = chat.panel.ScrollPanel:GetVBar() if VBAR then VBAR:SetScroll( textpanel:GetTall() ) end end function chat.hook.OnPlayerChat( ply, str, teamSay, dead ) local tab = {} if ( dead ) then table.insert( tab, Color( 255, 30, 40 ) ) table.insert( tab, "*DEAD* " ) end if ( teamSay ) then table.insert( tab, Color( 30, 160, 40 ) ) table.insert( tab, "(TEAM) " ) end if ( IsValid( ply ) ) then table.insert( tab, ply ) else table.insert( tab, "Console" ) end table.insert( tab, Color( 255, 255, 255 ) ) table.insert( tab, ": "..str ) _G.chat.AddText( unpack(tab) ) return true end function chat.hook.PlayerBindPress( ply, bind, pressed ) if not pressed then return end if bind == "messagemode" or bind == "messagemode2" or bind == "say" then if not chat.panel then chat.panel = vgui.Create( "UChat" ) if not chat.panel then return end chat.panel:SetSize( 500, 200 ) chat.panel:SetPos( 50, ScrH() - 350 ) end chat.panel:SetOpen( true ) return true --[[elseif bind == "messagemode2" then return true]] end end function chat.hook.HUDPaint() if not IsValid( chat.panel ) or chat.panel.IsOpen then return end if hook.Call( "BlockUnityChatboxOverlay", GAMEMODE ) then return end local tph = chat.panel.TextPanel:GetTall() local w, h = chat.panel.ScrollPanel:GetSize() local x, y = chat.panel.ScrollPanel:LocalToScreen( 0, 0 ) local lastupdate = chat.panel.TextPanel.LastUpdate or RealTime() local alpha = math.Clamp( ( lastupdate - RealTime() + 10 ) / 2, 0, 1 ) if alpha <= 0 then return end render.SetScissorRect( x, y, x + w, y + h, true ) chat.panel.TextPanel:PaintLines( x, y + h - tph, alpha ) render.SetScissorRect( 0, 0, 0, 0, false ) end function chat.hook.ChatText( _, _, msg, msg_type ) if not IsValid( chat.panel ) then return end chat.panel.TextPanel:InsertColor( Color( 151, 211, 255, 255 ) ) chat.panel.TextPanel:AppendText( tostring( msg ) ) chat.panel.TextPanel:AppendText( "\n" ) end function chat.hook.HUDShouldDraw( name ) if name == "CHudChat" then return false end end function chat.hook.InitPostEntity( name ) if not chat.panel then chat.panel = vgui.Create( "UChat" ) if not chat.panel then return end chat.panel:SetSize( 500, 200 ) chat.panel:SetPos( 50, ScrH() - 350 ) end chat.panel:SetOpen( false ) end