CapsAdmin

Untitled

Jan 26th, 2014
181
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 32.63 KB | None | 0 0
  1. setfenv(1, _G)
  2.  
  3. -- sorry but I use this somewhere else as well
  4. -- don't worry too much about using EXT if you're not sure how
  5. -- I can fix your mistakes
  6.  
  7. local EXT -- EXT for external
  8. local GMOD = gmod ~= nil
  9.  
  10. -- these are used by EXT.SetColor, EXT.SetFont etc
  11. local FONT = "chathud"
  12. local R, G, B, A = 255, 255, 255, 255
  13. local X, Y = 0, 0
  14.  
  15. if GMOD then
  16.     local TEMP_CLR = Color(R,G,B,A)
  17.     local TEMP_VEC = Vector(0, 0, 0)
  18.     local TEMP_ANG = Angle(0, 0, 0)
  19.  
  20.     local white = Material("vgui/white")
  21.    
  22.     EXT = {
  23.         Rand = math.Rand,
  24.         FormatPrint = function(fmt, ...) MsgN(string.format(fmt, ...)) end,
  25.         GetFrameTime = FrameTime,
  26.         GetTime = RealTime,
  27.         LoadString = function(str)
  28.             local func = CompileString(str, "chathud_expression", false)
  29.             if type(func) == "string" then
  30.                 return false, func
  31.             end
  32.             return func
  33.         end,
  34.        
  35.         CreateConVar = function(name, def) return CreateClientConVar(name, tostring(def), true, false) end,
  36.         GetConVarFloat = function(c) return c:GetFloat() end,
  37.        
  38.         HSVToColor = function(h,s,v) local c = HSVToColor(h%360, s, v) return c.r, c.g, c.b end,
  39.         SetMaterial = function(mat) surface.SetMaterial(mat or white) end,
  40.         SetColor = function(r,g,b,a) R=r G=g B=b A=a or 255 surface.SetTextColor(R,G,B,A) surface.SetDrawColor(R,G,B,A) end,
  41.         DrawRect = surface.DrawTexturedRect,
  42.         DrawText = function(str)
  43.             if FONT == chathud.fonts.default.name and surface.DrawPrettyText then
  44.                
  45.                 local data = chathud.fonts.default.data
  46.                
  47.                 TEMP_CLR.r = R
  48.                 TEMP_CLR.g = G
  49.                 TEMP_CLR.b = B
  50.                 TEMP_CLR.a = A
  51.                
  52.                 surface.DrawPrettyText(str, X, Y, data.font, data.size, data.weight, data.blursize, TEMP_CLR)
  53.             else
  54.                 surface.DrawText(str)
  55.             end
  56.         end,
  57.         SetTextPos = function(x, y) X=x Y=y surface.SetTextPos(x,y) end,
  58.         SetFont = function(str)
  59.            
  60.             str = chathud.font_translate[str] or str
  61.        
  62.             if not pcall(surface.SetFont, str) then
  63.                 str = chathud.fonts.default.name
  64.                 FONT = str
  65.                 surface.SetFont(str)
  66.             else
  67.                 FONT = str             
  68.             end
  69.         end,
  70.         GetTextSize = surface.GetTextSize,
  71.         SetAlphaMultiplier = surface.SetAlphaMultiplier,   
  72.         GetScreenHeight = ScrH,
  73.         GetScreenWidth = ScrW,
  74.        
  75.         SetCullClockWise = function(b) render.CullMode(b and MATERIAL_CULLMODE_CW or MATERIAL_CULLMODE_CCW) end,
  76.         FindMaterial = function(path)          
  77.             if _G.pac and path:find("http") then
  78.                 local mat = CreateMaterial("chathud_texture_tag" .. util.CRC(path) .. "_" .. FrameNumber(), "UnlitGeneric", {})
  79.  
  80.                 pac.urltex.GetMaterialFromURL(path, function(_mat)
  81.                     mat:SetTexture("$basetexture", _mat:GetTexture("$basetexture"))
  82.                 end, nil, "UnlitGeneric", size, false)
  83.  
  84.                 mat:SetFloat("$alpha", 0.999)
  85.            
  86.                 return mat
  87.             else
  88.                 local mat = Material(path)
  89.                 local shader = mat:GetShader()
  90.                
  91.                 if shader == "VertexLitGeneric" or shader == "Cable" then
  92.                     local tex_path = mat:GetString("$basetexture")
  93.                    
  94.                     if tex_path then
  95.                         local params = {}
  96.                        
  97.                         params["$basetexture"] = tex_path
  98.                         params["$vertexcolor"] = 1
  99.                         params["$vertexalpha"] = 1
  100.                        
  101.                         mat = CreateMaterial("markup_fixmat_" .. tex_path, "UnlitGeneric", params)
  102.                     end
  103.                 end
  104.  
  105.                 return mat
  106.             end
  107.         end,
  108.                
  109.         CreateMatrix = Matrix,
  110.        
  111.         TranslateMatrix = function(m, x, y, z) TEMP_VEC.x=x or 0 TEMP_VEC.y=y or 0 m:Translate(TEMP_VEC) end,
  112.         ScaleMatrix = function(m, x, y, z) TEMP_VEC.x=x or 0 TEMP_VEC.y=y or 0 m:Scale(TEMP_VEC) end,
  113.         RotateMatrix = function(m, a) TEMP_ANG.y=a or 0 m:Rotate(TEMP_ANG) end,
  114.        
  115.         PushMatrix = cam.PushModelMatrix,
  116.         PopMatrix = cam.PopModelMatrix,
  117.     }
  118. else
  119.     EXT = {
  120.         Rand = math.randomf,
  121.         FormatPrint = logf,
  122.         GetFrameTime = timer.GetFrameTime,
  123.         GetTime = timer.GetTime,
  124.         LoadString = loadstring,       
  125.         CreateConVar = console.CreateVariable,
  126.         GetConVarFloat = function(c) return c:Get() end,
  127.        
  128.         HSVToColor = function(h,s,v) local c = HSVToColor(h,s,v) return c.r, c.g, c.b end,
  129.        
  130.         SetMaterial = surface.SetTexture,
  131.         SetColor = function(r,g,b,a)
  132.             R=r G=g B=b A=a or 1
  133.            
  134.             if R>1 then R=R/255 end
  135.             if G>1 then R=G/255 end
  136.             if B>1 then R=B/255 end
  137.             if A>1 then R=A/255 end
  138.            
  139.             surface.Color(R,G,B,A)
  140.         end,
  141.         DrawRect = surface.DrawRect,
  142.         DrawText = surface.DrawText,
  143.         SetTextPos = function(x, y) X=x Y=y surface.SetTextPos(x,y) end,
  144.         SetFont = function(str)        
  145.             str = chathud.font_translate[str] or str
  146.             FONT = str
  147.             surface.SetFont(str)
  148.         end,
  149.         GetTextSize = surface.GetTextSize,
  150.         SetAlphaMultiplier = surface.SetAlphaMultiplier,   
  151.         GetScreenHeight = function() return select(2, surface.GetScreenSize()) end,
  152.         GetScreenWidth = function() return (surface.GetScreenSize()) end,
  153.        
  154.         SetCullClockWise = function(b) end,
  155.         FindMaterial = Image,
  156.         CreateMatrix = Matrix44,
  157.        
  158.         TranslateMatrix = function(m, x, y) m:Translate(x or 0, y or 0, 0) end,
  159.         ScaleMatrix = function(m, x, y) m:Scale(x or 0, y or 0, 1) end,
  160.         RotateMatrix = function(m, a) m:Rotate(a, 0, 0, 1) end,
  161.        
  162.         PushMatrix = render.PushWorldMatrixEx,
  163.         PopMatrix = render.PopWorldMatrix,
  164.     }
  165. end
  166.  
  167. -- config start
  168.  
  169. chathud = {
  170.     font_translate = {
  171.         -- usage
  172.         -- chathud.font_translate.chathud_default = "my_font"
  173.         -- to override fonts
  174.     },
  175.     config = {
  176.         max_width = 500,
  177.         max_height = 1200,
  178.         height_spacing = 3,
  179.         history_life = 20,
  180.        
  181.         extras = {
  182.             ["...."] = {type = "font", val = "DefaultFixed"},
  183.             ["!!!!"] = {type = "font", val = "Trebuchet24"},
  184.             ["!!!!!11"] = {type = "font", val = "DermaLarge"},
  185.         },
  186.        
  187.         smiley_translate =
  188.         {
  189.             v = "vee",
  190.         }, 
  191.  
  192.         shortcuts = {      
  193.             smug = "<texture=masks/smug>",
  194.             downs = "<texture=masks/downs>",
  195.             saddowns = "<texture=masks/saddowns>",
  196.             niggly = "<texture=masks/niggly>",
  197.             colbert = "<texture=masks/colbert>",
  198.             eli = "<texture=models/eli/eli_tex4z,4>",
  199.         }
  200.        
  201.     },
  202.    
  203.     fonts = {
  204.         default = {
  205.             name = "chathud_default",
  206.             data = {
  207.                 font = "DejaVu Sans",
  208.                 size = 14,
  209.                 antialias = true,
  210.                 outline = false,
  211.                 weight = 580,
  212.             } ,
  213.         },
  214.        
  215.         chatprint = {
  216.             name = "chathud_chatprint",
  217.             color = Color(201, 255, 41, 255),
  218.             data = {
  219.                 font = "Verdana",
  220.                 size = 16,
  221.                 weight = 600,
  222.                 antialias = true,
  223.                 shadow = true,
  224.             },
  225.         },
  226.     },     
  227.    
  228.     tags = {
  229.         hsv =
  230.         {
  231.             arguments = {0, 1, 1},
  232.            
  233.             draw = function(self, x,y,a, h, s, v)
  234.                 local r,g,b = EXT.HSVToColor(h, s, v)
  235.                 EXT.SetColor(r, g, b, 255)
  236.                 EXT.SetColor(r, g, b, 255)
  237.             end,
  238.         },
  239.        
  240.         color =
  241.         {
  242.             arguments = {255, 255, 255, 255},
  243.            
  244.             draw = function(self, x,y,a, r,g,b,a)
  245.                 EXT.SetColor(r, g, b, a)
  246.                 EXT.SetColor(r, g, b, a)
  247.             end,
  248.         },
  249.  
  250.         physics =
  251.         {
  252.             annoying = true,
  253.            
  254.             arguments = {1, 0, 0, 0, 0.99, 0.1},
  255.            
  256.             pre = function(self, gx, gy, vx, vy, drag, rand_mult)
  257.                 local part = {}
  258.                
  259.                 part =
  260.                 {
  261.                     pos = {x = 0, y = 0},
  262.                     vel = {x = vx, y = vy},
  263.                     siz = 10,
  264.                     rand_mult = rand_mult,
  265.                     drag = drag,
  266.                 }
  267.                
  268.                 self.part = part
  269.             end,
  270.            
  271.             draw = function(self, x,y,a, gravity_y, gravity_x, vx, vy, drag, rand_mult)
  272.                 local delta = EXT.GetFrameTime() * 5
  273.                
  274.                 local part = self.part
  275.                
  276.                 local cx = x
  277.                 local cy = y - 10
  278.                
  279.                 local W, H = C.max_width/2, EXT.GetScreenHeight()
  280.                
  281.                 W = W - cx
  282.                 H = H - cy
  283.                
  284.                 -- random velocity for some variation
  285.                 part.vel.y = part.vel.y + gravity_y + (EXT.Rand(-1,1) * rand_mult)
  286.                 part.vel.x = part.vel.x + gravity_x + (EXT.Rand(-1,1) * rand_mult)
  287.                
  288.                 -- velocity
  289.                 part.pos.x = part.pos.x + (part.vel.x * delta)
  290.                 part.pos.y = part.pos.y + (part.vel.y * delta)
  291.                
  292.                 -- friction
  293.                 part.vel.x = part.vel.x * part.drag
  294.                 part.vel.y = part.vel.y * part.drag
  295.                
  296.                 -- collision
  297.                 if part.pos.x - part.siz < -cx then
  298.                     part.pos.x = -cx + part.siz
  299.                     part.vel.x = part.vel.x * -part.drag
  300.                 end
  301.                
  302.                 if part.pos.x + part.siz > W then
  303.                     part.pos.x = W - part.siz
  304.                     part.vel.x = part.vel.x * -part.drag
  305.                 end
  306.                
  307.                 if part.pos.y - part.siz < -cy then
  308.                     part.pos.y = -cy + part.siz
  309.                     part.vel.y = part.vel.y * -part.drag
  310.                 end
  311.                
  312.                 if part.pos.y + part.siz > H then
  313.                     part.pos.y = H - part.siz
  314.                     part.vel.y = part.vel.y * -part.drag
  315.                 end
  316.                
  317.                 local mat = EXT.CreateMatrix()
  318.                
  319.                 EXT.TranslateMatrix(mat, part.pos.x, part.pos.y)
  320.                
  321.                 EXT.PushMatrix(mat)
  322.             end,
  323.            
  324.             post = function()
  325.                 EXT.PopMatrix()
  326.             end,
  327.         },
  328.        
  329.         font =
  330.         {
  331.             annoying = true,
  332.            
  333.             arguments = {"chathud_default"},
  334.            
  335.             draw = function(self, x,y,a, font)
  336.                 EXT.SetFont(font)
  337.             end,
  338.            
  339.             pre = function(self, font)
  340.                 EXT.SetFont(font)
  341.             end,
  342.         },
  343.        
  344.         texture =
  345.         {      
  346.             arguments = {"error", {default = 1, min = 1, max = 4}},
  347.            
  348.             pre = function(self, path)
  349.                 self.mat = EXT.FindMaterial(path)
  350.             end,
  351.  
  352.             get_size = function(self, path, size_mult)
  353.                 return 16 * size_mult, 16 * size_mult
  354.             end,
  355.            
  356.             draw = function(self, x,y,a, path)
  357.                 EXT.SetMaterial(self.mat)
  358.                 EXT.DrawRect(x, y, self.w, self.h)
  359.             end,
  360.         },
  361.     }
  362. }
  363.  
  364.  
  365. do -- matrix tag
  366.     local function detM2x2 (m11, m12, m21, m22)
  367.         return m11 * m22 - m12 * m21
  368.     end
  369.  
  370.     local function mulM2x2V2 (m11, m12, m21, m22, v1, v2)
  371.         return v1 * m11 + v2 * m12, v1 * m21 + v2 * m22
  372.     end
  373.  
  374.     local function normalizeV2(x, y)
  375.         local length = math.sqrt(x * x + y * y)
  376.         return x / length, y / length
  377.     end
  378.  
  379.     local function scaleV2(v1, v2, k)
  380.         return v1 * k, v2 * k
  381.     end
  382.  
  383.     local function eigenvector2(l, a, d)
  384.         -- (a - ?) u1 + d u2 = 0
  385.         if a - l == 0 then return 1, 0 end
  386.         if     d == 0 then return 0, 1 end
  387.        
  388.         return normalizeV2(-d / (a - l), 1)
  389.     end
  390.  
  391.     local function orthonormalM2x2ToVMatrix(m11, m12, m21, m22, mat)
  392.         local det = detM2x2(m11, m12, m21, m22)
  393.        
  394.         if det < 0 then
  395.             EXT.ScaleMatrix(mat, 1, -1)
  396.         end
  397.        
  398.         local angle = math.atan2 (m21, m11)
  399.         EXT.RotateMatrix(mat, math.deg(angle))
  400.        
  401.         return mat
  402.     end
  403.  
  404.     chathud.tags.translate =
  405.     {
  406.         annoying = true,
  407.         arguments = {0, 0},
  408.        
  409.         draw = function(self, x, y, a, dx, dy)
  410.             local mat = EXT.CreateMatrix()
  411.             EXT.TranslateMatrix(mat, dx, dy)
  412.            
  413.             EXT.PushMatrix(mat)
  414.         end,
  415.        
  416.         post = function()
  417.             EXT.PopMatrix()
  418.         end,
  419.     }
  420.    
  421.     chathud.tags.scale =
  422.     {
  423.         annoying = true,
  424.         arguments = {1, nil},
  425.        
  426.         draw = function(self, x, y, a, scaleX, scaleY)
  427.             local mat = EXT.CreateMatrix()
  428.            
  429.             scaleY = scaleY or scaleX
  430.             self.matrixDeterminant = scaleX * scaleY
  431.            
  432.             if math.abs (self.matrixDeterminant) > 10 then
  433.                 scaleX, scaleY = normalizeV2(scaleX, scaleY)
  434.                 scaleX, scaleY = scaleV2(scaleX, scaleY, 10)
  435.             end
  436.            
  437.             local centerY = y - self.message_height / 2
  438.            
  439.             EXT.TranslateMatrix(mat, x, centerY)
  440.                 EXT.ScaleMatrix(mat, scaleX, scaleY)
  441.                
  442.                 if scaleX < 0 then
  443.                     EXT.TranslateMatrix(mat, -self.message_width, 0)
  444.                 end
  445.             EXT.TranslateMatrix(mat, -x, -centerY)
  446.            
  447.             EXT.PushMatrix(mat)
  448.            
  449.             EXT.SetCullClockWise(self.matrixDeterminant < 0)
  450.         end,
  451.        
  452.         post = function(self)
  453.             if self.matrixDeterminant < 0 then
  454.                 EXT.SetCullClockWise(false)
  455.             end
  456.            
  457.             EXT.PopMatrix()
  458.         end,
  459.     }
  460.    
  461.     chathud.tags.rotate =
  462.     {
  463.         annoying = true,
  464.         arguments = {0},
  465.        
  466.         draw = function(self, x, y, a, angleInDegrees)
  467.             local mat = EXT.CreateMatrix()
  468.            
  469.             local centerX = x + self.message_width / 2
  470.             local centerY = y - self.message_height / 2
  471.            
  472.             EXT.TranslateMatrix(mat, centerX, centerY)
  473.                 EXT.RotateMatrix(mat, angleInDegrees)
  474.             EXT.TranslateMatrix(mat, -centerX, -centerY)
  475.            
  476.             EXT.PushMatrix(mat)
  477.         end,
  478.        
  479.         post = function()
  480.             EXT.PopMatrix()
  481.         end,
  482.     }
  483.  
  484.     chathud.tags.matrixez =
  485.     {
  486.         annoying = true,
  487.         arguments = {0,0,1,1,0},
  488.        
  489.         draw = function(self, x, y, a, X, Y, scaleX, scaleY, angleInDegrees)
  490.             local mat = EXT.CreateMatrix()
  491.            
  492.             self.matrixDeterminant = scaleX * scaleY
  493.            
  494.             if math.abs (self.matrixDeterminant) > 10 then
  495.                 scaleX, scaleY = normalizeV2(scaleX, scaleY)
  496.                 scaleX, scaleY = scaleV2(scaleX, scaleY, 10)
  497.             end
  498.            
  499.             local centerX = self.message_width / 2
  500.             local centerY = y - self.message_height / 2
  501.            
  502.             EXT.TranslateMatrix(mat, x, centerY)
  503.                 EXT.TranslateMatrix(mat, X,Y)
  504.                 EXT.ScaleMatrix(mat, scaleX, scaleY)
  505.                 if scaleX < 0 then
  506.                     EXT.TranslateMatrix(mat, -self.message_width, 0)
  507.                 end
  508.                 if angleInDegrees ~= 0 then
  509.                     EXT.TranslateMatrix(mat, centerX)
  510.                         EXT.RotateMatrix(mat, angleInDegrees)
  511.                     EXT.TranslateMatrix(mat, -centerX)
  512.                 end
  513.             EXT.TranslateMatrix(mat, x, -centerY)
  514.            
  515.             EXT.PushMatrix(mat)
  516.            
  517.             EXT.SetCullClockWise(self.matrixDeterminant < 0)
  518.         end,
  519.        
  520.         post = function(self)
  521.             if self.matrixDeterminant < 0 then
  522.                 EXT.SetCullClockWise(false)
  523.             end
  524.            
  525.             EXT.PopMatrix()
  526.         end,
  527.     }
  528.    
  529.     chathud.tags.matrix =
  530.     {
  531.         annoying = true,
  532.        
  533.         arguments = {1, 0, 0, 1, 0, 0},
  534.        
  535.         draw = function(self, x, y, a, a11, a12, a21, a22, dx, dy)
  536.             -- Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn
  537.            
  538.             -- A = Q1 ? Q2
  539.            
  540.             -- B = transpose (A) * A
  541.             local b11 = a11 * a11 + a21 * a21
  542.             local b12 = a11 * a12 + a21 * a22
  543.             local b21 = a12 * a11 + a22 * a21
  544.             local b22 = a12 * a12 + a22 * a22
  545.             local trB  = b11 + b22
  546.             local detB = detM2x2(b11, b12, b21, b22)
  547.            
  548.             -- Finding eigenvalues of B...
  549.             -- det (B - ?I) = 0
  550.             -- | a - ?        b | = 0
  551.             -- |     c    d - ? |
  552.             --
  553.             -- (a - ?) (d - ?) - bc = 0
  554.             -- ?² + (-a - d) ? + ad - bc = 0
  555.             --
  556.             --     a + d ± sqrt ((a + d)² - 4 (ad - bc))
  557.             -- ? = -------------------------------------
  558.             --                      2
  559.            
  560.             -- This is never negative
  561.             local sqrtInside = trB * trB - 4 * detB
  562.             local eigenvalue1 = 0.5 * (trB + math.sqrt(sqrtInside))
  563.             local eigenvalue2 = 0.5 * (trB - math.sqrt(sqrtInside))
  564.            
  565.             -- (B - ?I) u = 0
  566.             --
  567.             -- [ a - ?        b ] [ u1 ] = [ 0 ]
  568.             -- [     c    d - ? ] [ u2 ]   [ 0 ]
  569.             --
  570.             -- (a - ?) u1 +      b  u2 = 0
  571.             local q211, q221 = eigenvector2(eigenvalue1, b11, b12)
  572.             local q212, q222 = eigenvector2(eigenvalue2, b11, b12)
  573.            
  574.             if eigenvalue1 == eigenvalue2 then
  575.                 -- Make up an eigenvector
  576.                 q212, q222 = q221, -q211
  577.             end
  578.            
  579.             -- Those will never be negative as well #yolo
  580.             local scaleX = math.sqrt (eigenvalue1)
  581.             local scaleY = math.sqrt (eigenvalue2)
  582.            
  583.             local detQ2 = q211 * q222 - q212 * q221
  584.             local q111, q121 = mulM2x2V2(a11, a12, a21, a22, q211, q221)
  585.             local q112, q122 = mulM2x2V2(a11, a12, a21, a22, q212, q222)
  586.             q111, q121 = scaleV2(q111, q121, (scaleX ~= 0) and (1 / scaleX) or 0)
  587.            
  588.             if scaleY == 0 then
  589.                 q112, q122 = q121, -q111
  590.             else
  591.                 -- DOES THIS WORK LOL
  592.                 q112, q122 = scaleV2(q112, q122, (scaleY ~= 0) and (1 / scaleY) or 0)
  593.             end
  594.            
  595.             -- transpose Q2
  596.             q212, q221 = q221, q212
  597.            
  598.             -- End of Cthulhu summoning
  599.            
  600.             self.matrixDeterminant = detM2x2(a11, a12, a21, a22)
  601.            
  602.             local mat = EXT.CreateMatrix()
  603.            
  604.             local center = Vector(x, y)
  605.             EXT.TranslateMatrix(mat, x, y)
  606.                 EXT.TranslateMatrix(mat, dx, dy)
  607.                
  608.                 orthonormalM2x2ToVMatrix(q211, q212, q221, q222, mat)
  609.                 EXT.ScaleMatrix(mat, scaleX, scaleY)
  610.                 orthonormalM2x2ToVMatrix(q111, q112, q121, q122, mat)
  611.             EXT.TranslateMatrix(mat, -x, -y)
  612.            
  613.             EXT.PushMatrix(mat)
  614.            
  615.             EXT.SetCullClockWise(self.matrixDeterminant < 0)
  616.         end,
  617.        
  618.         post = function(self)
  619.             if self.matrixDeterminant < 0 then
  620.                 EXT.SetCullClockWise(false)
  621.             end
  622.            
  623.             EXT.PopMatrix()
  624.         end,
  625.     }
  626. end
  627.  
  628. -- internal
  629.  
  630. local C = chathud.config
  631.  
  632. local history = {}
  633. local variables = {}
  634. local time_speed = 1
  635. local time_offset = 0
  636.  
  637. local height_mult = EXT.CreateConVar("cl_chathud_height_mult", 0.76)
  638. local width_mult = EXT.CreateConVar("cl_chathud_width_mult", 0.3)
  639.  
  640.  
  641. local panic = false
  642.  
  643. do -- expression
  644.     -- used like <tag=[pi * rand()]>
  645.    
  646.     local lib =
  647.     {
  648.         PI = math.pi,
  649.         pi = math.pi,
  650.         rand = math.random,
  651.         random = math.random,
  652.         randx = function(a,b)
  653.             a = a or -1
  654.             b = b or 1
  655.             return EXT.Rand(a, b)
  656.         end,
  657.        
  658.         abs = math.abs,
  659.         sgn = function (x)
  660.             if x < 0 then return -1 end
  661.             if x > 0 then return  1 end
  662.             return 0
  663.         end,
  664.        
  665.         acos = math.acos,
  666.         asin = math.asin,
  667.         atan = math.atan,
  668.         atan2 = math.atan2,
  669.         ceil = math.ceil,
  670.         cos = math.cos,
  671.         cosh = math.cosh,
  672.         deg = math.deg,
  673.         exp = math.exp,
  674.         floor = math.floor,
  675.         frexp = math.frexp,
  676.         ldexp = math.ldexp,
  677.         log = math.log,
  678.         log10 = math.log10,
  679.         max = math.max,
  680.         min = math.min,
  681.         rad = math.rad,
  682.         sin = math.sin,
  683.         sinc = function (x)
  684.             if x == 0 then return 1 end
  685.             return math.sin(x) / x
  686.         end,
  687.         sinh = math.sinh,
  688.         sqrt = math.sqrt,
  689.         tanh = math.tanh,
  690.         tan = math.tan,
  691.        
  692.         clamp = math.Clamp,
  693.         pow = math.pow
  694.     }
  695.  
  696.     local blacklist = {"repeat", "until", "function", "end"}
  697.  
  698.     local expressions = {}
  699.  
  700.     function chathud.CompileExpression(str, extra_lib)
  701.         local source = str
  702.  
  703.         for _, word in pairs(blacklist) do
  704.             if str:find("[%p%s]" .. word) or str:find(word .. "[%p%s]") then
  705.                 return false, string.format("illegal characters used %q", word)
  706.             end
  707.         end
  708.        
  709.         local functions = {}
  710.        
  711.         for k,v in pairs(lib) do functions[k] = v end
  712.        
  713.         if extra_lib then
  714.             for k,v in pairs(extra_lib) do functions[k] = v end
  715.         end
  716.        
  717.         local t0 = EXT.GetTime()
  718.         functions.t    = function () return EXT.GetTime() - t0 end
  719.         functions.time = function () return EXT.GetTime() - t0 end
  720.         functions.select = select
  721.        
  722.         str = "local input = select(1, ...) return " .. str
  723.        
  724.         local func, err = EXT.LoadString(str)
  725.        
  726.         if func then
  727.             setfenv(func, functions)
  728.             expressions[func] = source
  729.             return true, func
  730.         else
  731.             return false, err
  732.         end
  733.     end
  734. end
  735.  
  736. local function split_text(str, maxwide)
  737.     local lines = {}
  738.     local pos = 0
  739.     local last_pos = 0
  740.     local wide = 0
  741.     local found = false
  742.    
  743.     local space_pos
  744.    
  745.     for char in str:gmatch("([%z\1-\127\194-\244][\128-\191]*)") do
  746.         pos = pos + #char
  747.        
  748.         local w, h = EXT.GetTextSize(char == "&" and "%" or char)
  749.        
  750.         w = w or 0
  751.         h = h or 0
  752.        
  753.         if char == " " then
  754.             space_pos = pos
  755.         end
  756.  
  757.         if wide + w >= maxwide then
  758.             if space_pos then
  759.                 table.insert(lines, str:sub(last_pos+1, space_pos))
  760.                 last_pos = space_pos
  761.             else
  762.                 table.insert(lines, str:sub(last_pos+1, pos))
  763.                 last_pos = pos
  764.             end
  765.            
  766.             wide = 0
  767.             found = true
  768.             space_pos = nil
  769.         else
  770.             wide = wide + w
  771.         end
  772.     end
  773.    
  774.     if found then
  775.         table.insert(lines, str:sub(last_pos+1, pos))
  776.     else
  777.         table.insert(lines, str)
  778.     end
  779.    
  780.     return lines
  781. end
  782.  
  783. local function run_tag(line, name, ...)
  784.     if not line.val.tag then return end
  785.    
  786.     if line.type == "custom" then
  787.        
  788.         if not chathud.CanRunAnnoyingTags() then
  789.             return
  790.         end
  791.    
  792.         local func = line.val.tag and line.val.tag[name]
  793.        
  794.         if func then       
  795.             local sigh = {line, ...}
  796.             for k,v in pairs(line.val.args) do
  797.                 if type(v) == "function" then
  798.                     local ok, val = pcall(v, line.exp_env)
  799.                     if ok and val then
  800.                         v = val
  801.                     else
  802.                         v = line.val.tag.arguments[k]
  803.                         if type(v) == "table" then
  804.                             v = v.default
  805.                         end
  806.                     end
  807.                 end
  808.                 table.insert(sigh, v)
  809.             end
  810.            
  811.             local args = {pcall(func, unpack(sigh))}
  812.            
  813.             if not args[1] then
  814.                 history = {}
  815.                 EXT.FormatPrint("tag error %s", args[2])
  816.             else
  817.                 return select(2, unpack(args))
  818.             end
  819.         end
  820.     end
  821. end
  822.  
  823. local function parse_tag_arguments(str)
  824.     str = str .. ","
  825.     local out =  {}
  826.     local expressions = {}
  827.    
  828.     str = str:gsub("(%[.-%]),", function(expression)
  829.         local id =  "__" .. expression .. "__"
  830.         expressions[id] = expression:sub(2, -2)
  831.         return id .. ","
  832.     end)
  833.    
  834.     for arg in str:gmatch("(.-),") do
  835.         if expressions[arg]  then
  836.             local ok, func = chathud.CompileExpression(expressions[arg])
  837.             if func then
  838.                 table.insert(out, func)
  839.             else
  840.                 EXT.FormatPrint("chathud expression error: %s", func)
  841.                 table.insert(out, 0)
  842.             end
  843.         else
  844.             table.insert(out, arg)
  845.         end
  846.     end
  847.    
  848.     return out
  849. end
  850.  
  851. local function to_markup(str)
  852.     local data = {}
  853.     local found = false
  854.    
  855.     local in_tag = false
  856.     local current_string = {}
  857.     local current_tag = {}
  858.    
  859.     -- just used for <r>
  860.     local tags = {}
  861.    
  862.     for i = 0, #str do
  863.         local char = string.sub(str, i, i)
  864.        
  865.         if char == "<" then
  866.             if current_string then
  867.                 table.insert(data, table.concat(current_string, ""))
  868.             end
  869.            
  870.             current_tag = {}
  871.             in_tag = true
  872.         elseif char == ">" and in_tag then
  873.             if current_tag then
  874.                 local input = table.concat(current_tag, "") .. ">"
  875.                 local tag, args = input:match("<(.-)[=?](.+)>")
  876.                                
  877.                 local info = chathud.tags[tag]
  878.                
  879.                 if info then               
  880.                     local args = parse_tag_arguments(args or "")
  881.                    
  882.                     for i = 1, #info.arguments do
  883.                         local arg = args[i]
  884.                         local default = info.arguments[i]
  885.                         local t = type(default)
  886.                        
  887.                         if t == "number" then
  888.                             local num = tonumber(arg)
  889.                            
  890.                             if not num and type(arg) == "function" then
  891.                                 num = arg
  892.                             end
  893.                            
  894.                             args[i] = num or default
  895.                         elseif t == "string" then
  896.                             if not arg or arg == "" then
  897.                                 arg = default
  898.                             end
  899.                            
  900.                             args[i] = arg
  901.                         elseif t == "table" then
  902.                             if default.min or default.max or default.default then
  903.                                 local num = tonumber(arg)
  904.                                
  905.                                 if num then
  906.                                     if default.min and default.max then
  907.                                         args[i] = math.min(math.max(num, default.min), default.max)
  908.                                     elseif default.min then
  909.                                         args[i] = math.min(num, default.min)
  910.                                     elseif default.max then
  911.                                         args[i] = math.max(num, default.max)
  912.                                     end
  913.                                 else
  914.                                     if type(arg) == "function" then
  915.                                         if default.min and default.max then
  916.                                             args[i] = function(...) return math.min(math.max(arg(...) or default.default, default.min), default.max) end
  917.                                         elseif default.min then
  918.                                             args[i] = function(...) return math.min(arg(...) or default.default, default.min) end
  919.                                         elseif default.max then
  920.                                             args[i] = function(...) return math.max(arg(...) or default.default, default.max) end
  921.                                         end
  922.                                     else
  923.                                         args[i] = default.default
  924.                                     end
  925.                                 end
  926.                             end
  927.                         end
  928.                     end
  929.                    
  930.                     found = true
  931.                    
  932.                     local tag = {tag = info, type = tag, args = args}
  933.                     table.insert(data, tag)
  934.                    
  935.                     -- for special tags
  936.                     table.insert(tags, tag)
  937.                 else
  938.                     if tag == "repeat" or tag == "r" then
  939.                         local args = parse_tag_arguments(args or "")
  940.                         local count = tonumber(args[1]) or 1
  941.                        
  942.                         for i = 0, count - 1 do
  943.                             local last = tags[#tags - i]
  944.                             if last then
  945.                                 table.insert(data, last)
  946.                             else
  947.                                 break
  948.                             end
  949.                         end
  950.                        
  951.                         found = true
  952.                     elseif (tag == "variable" or tag == "var" or tag == "v") and args then
  953.                         local args = parse_tag_arguments(args)
  954.                         local set = variables[args[1]]
  955.                        
  956.                         if set then
  957.                             for k,v in pairs(set) do
  958.                                 table.insert(data, v)
  959.                             end
  960.                             found = true
  961.                         end
  962.                     end
  963.                 end
  964.             end
  965.            
  966.             current_string = {}
  967.             in_tag = false
  968.         end
  969.        
  970.         if in_tag then
  971.             table.insert(current_tag, char)
  972.         elseif char ~= ">" then
  973.             table.insert(current_string, char)
  974.         end
  975.     end
  976.    
  977.     if found then
  978.         table.insert(data, table.concat(current_string, ""))
  979.     else
  980.         data = {str}
  981.     end
  982.    
  983.     return data
  984. end
  985.  
  986. local function add_markup(markup)  
  987.     C.max_width = EXT.GetScreenWidth() * EXT.GetConVarFloat(width_mult)
  988.     C.max_height = EXT.GetScreenHeight() * EXT.GetConVarFloat(height_mult)
  989.    
  990.     markup.life_time = EXT.GetTime() + C.history_life
  991.     table.insert(history, 1, markup)
  992. end
  993.  
  994. do
  995.     -- this converts chat.AddText to our markup language
  996.  
  997.     -- just for readability really
  998.  
  999.     local function is_color(var)
  1000.         return GMOD and var.r and var.g and var.b
  1001.     end
  1002.  
  1003.     local function is_font(var)
  1004.         return #var == 1 and type(var[1]) == "string"
  1005.     end
  1006.  
  1007.     function chathud.AddText(...)
  1008.        
  1009.         local args = {...}
  1010.        
  1011.         if panic then
  1012.             panic = false
  1013.         end
  1014.        
  1015.         local is_maybe_player_chat = false
  1016.        
  1017.         -- preprocess :something: to <texture=something>
  1018.         for k,v in pairs(args) do
  1019.             if type(v) == "string" then
  1020.                 for _k, _v in pairs(C.smiley_translate) do
  1021.                     v = v:gsub(":" .. _k .. ":", ":" .. _v .. ":")
  1022.                 end
  1023.                 args[k] = v:gsub("(:[%w_]-:)", function(str)
  1024.                     str = str:sub(2, -2)
  1025.                    
  1026.                     if variables[str] then
  1027.                         return "<v=" .. str .. ">"
  1028.                     end
  1029.                    
  1030.                     if C.shortcuts[str] then
  1031.                         return C.shortcuts[str]
  1032.                     end
  1033.                 end)
  1034.             end
  1035.         end
  1036.  
  1037.         -- normalize everything into a consistent markup table
  1038.         -- strings are also parsed
  1039.         local markup = {}
  1040.        
  1041.         for i, var in pairs(args) do
  1042.             local t = type(var)
  1043.            
  1044.             if not GMOD then
  1045.                 local t = typex(var)
  1046.                
  1047.                 if t == "color" then
  1048.                     table.insert(markup, {type = "color", val = var})
  1049.                 elseif t == "player" then
  1050.                     table.insert(markup, {type = "color", val = Color(0.25,0.75,1)})
  1051.                     table.insert(markup, {type = "string", val = var:GetNick()})
  1052.                     table.insert(markup, {type = "color", val = Color(1,1,1,1)})
  1053.                 end
  1054.             end
  1055.            
  1056.             if t == "Player" then
  1057.                 table.insert(markup, {type = "color", val = team.GetColor(var:Team())})
  1058.                 table.insert(markup, {type = "string", val = var:Name()})
  1059.                 table.insert(markup, {type = "color", val = color_white})
  1060.                
  1061.                 is_maybe_player_chat = true
  1062.             elseif t == "string" then
  1063.                 if var:sub(1, 2) == ": " then
  1064.                     is_maybe_player_chat = true
  1065.                 end
  1066.                
  1067.                 if is_maybe_player_chat and (var == ": sh" or var:find("%ssh%s")) then
  1068.                     panic = true
  1069.                 end
  1070.                
  1071.                 for i, var in pairs(to_markup(var)) do
  1072.                     if type(var) == "string"  then
  1073.                         table.insert(markup, {type = "string", val = var})
  1074.                     else
  1075.                         table.insert(markup, {type = "custom", val = var})
  1076.                     end
  1077.                 end
  1078.                
  1079.             elseif t == "table" then
  1080.                 if is_color(var) then
  1081.                     table.insert(markup, {type = "color", val = var})
  1082.                 elseif is_font(var) then
  1083.                     table.insert(markup, {type = "font", val = var[1]})
  1084.                 end
  1085.             else
  1086.                 EXT.FormatPrint("tried to parse unknown type %q", t)
  1087.             end
  1088.  
  1089.         end
  1090.        
  1091.         -- concatenate all repeated strings to properly work with with splitting and better performance
  1092.         local concatenated = {}
  1093.         local last_data = {}
  1094.        
  1095.         for i, data in pairs(markup) do
  1096.            
  1097.             if not (data.type == "color" and markup[i+1] and markup[i+1].type == "color")  then
  1098.                 if last_data.type == "string" and data.type == "string" then
  1099.                     last_data.val = last_data.val .. data.val
  1100.                 else
  1101.                     table.insert(concatenated, data)
  1102.                     last_data = data
  1103.                 end
  1104.             end
  1105.         end
  1106.        
  1107.         for find, add in pairs(C.extras) do
  1108.             for i, data in pairs(concatenated) do
  1109.                 if data.type == "string" and data.val:find(find, nil, true) then
  1110.                    
  1111.                     table.insert(concatenated, 1, add)
  1112.                     return
  1113.                 end
  1114.             end
  1115.         end
  1116.        
  1117.         EXT.SetFont(chathud.fonts.default.name)
  1118.        
  1119.         -- get the size of each object
  1120.         local temp = {}
  1121.        
  1122.         for i, data in pairs(concatenated) do
  1123.             if data.type == "font" then
  1124.                 EXT.SetFont(data.val)
  1125.             elseif data.type == "string" then
  1126.                 -- this really should be done in the previous loop..
  1127.                 for _, str in pairs(split_text(data.val, C.max_width)) do
  1128.                     local w, h = EXT.GetTextSize(str)
  1129.                     table.insert(temp, {type = "string", val = str, w = w, h = h, x = 0, y = 0})
  1130.                 end
  1131.                
  1132.                 goto NEXT
  1133.             elseif data.type == "custom" then
  1134.                 local info = data.val.tag
  1135.                
  1136.                 local w, h = run_tag(data, "get_size")
  1137.                 data.w = w
  1138.                 data.h = h
  1139.                
  1140.                 run_tag(data, "pre")
  1141.             end
  1142.            
  1143.             -- for consistency sake everything should have x y w h
  1144.             data.x = data.x or 0
  1145.             data.y = data.y or 0
  1146.             data.w = data.w or 0
  1147.             data.h = data.h or 0
  1148.            
  1149.             table.insert(temp, data)
  1150.            
  1151.             ::NEXT::
  1152.         end
  1153.        
  1154.         -- split it up if needed
  1155.        
  1156.         local markup = {w = 0, h = 0, data = {}}
  1157.        
  1158.         local y = 0
  1159.        
  1160.         local width = 0
  1161.        
  1162.         local split = false
  1163.         local line_height = 0
  1164.        
  1165.         for i, data in pairs(temp) do
  1166.             data.x = width
  1167.             data.y = y
  1168.            
  1169.             width = width + data.w
  1170.  
  1171.             -- figure out how tall this line is
  1172.             if data.h > line_height then
  1173.                 line_height = data.h
  1174.             end
  1175.            
  1176.             if width + data.w >= C.max_width and i ~= #temp then
  1177.                 y = y + line_height
  1178.                
  1179.                 if width > markup.w then
  1180.                     markup.w = width
  1181.                 end
  1182.                
  1183.                 width = 0
  1184.                 split = true
  1185.                
  1186.                 markup.h = markup.h + line_height
  1187.             end
  1188.            
  1189.             table.insert(markup.data, data)
  1190.         end
  1191.                    
  1192.         if not split then
  1193.             markup.w = width
  1194.             markup.h = line_height
  1195.            
  1196.             for i, data in pairs(markup.data) do
  1197.                 data.y = line_height - data.h
  1198.             end
  1199.         else
  1200.             markup.h = markup.h + line_height
  1201.         end
  1202.        
  1203.         -- this is for expressions to be use d like line.i+time()
  1204.         for i, data in pairs(markup.data) do
  1205.             data.exp_env = { i = i, w = data.w, h = data.h, x = data.x, y = data.y, rand = math.random() }
  1206.         end
  1207.        
  1208.         -- build linked list
  1209.         local prev = nil
  1210.         for _, data in ipairs(markup.data) do
  1211.             if prev then
  1212.                 prev.next = data
  1213.             end
  1214.             prev = data
  1215.         end
  1216.        
  1217.         for i, data in pairs(markup.data) do
  1218.             local w = 0
  1219.             local h = 0
  1220.             local node = data.next
  1221.             while node do
  1222.                 w = w + node.w
  1223.                 h = math.max (h, node.h)
  1224.                 node = node.next
  1225.             end
  1226.            
  1227.             data.message_width = w
  1228.             data.message_height = h            
  1229.         end
  1230.        
  1231.         markup.h = markup.h + C.height_spacing
  1232.            
  1233.         add_markup(markup)
  1234.     end
  1235. end
  1236.  
  1237. function chathud.Draw()
  1238.     local history_x = 45
  1239.     local history_y = C.max_height
  1240.    
  1241.     for i, markup in pairs(history) do
  1242.         history_y = history_y - markup.h
  1243.         local alpha = math.min(math.max(markup.life_time - EXT.GetTime(), 0), 1) ^ 5
  1244.                
  1245.         -- reset font and color for every line
  1246.         EXT.SetAlphaMultiplier(alpha)
  1247.         EXT.SetFont(chathud.fonts.default.name)
  1248.         EXT.SetColor(255, 255, 255, 255)
  1249.         EXT.SetColor(255, 255, 255, 255)
  1250.                
  1251.         for _, data in pairs(markup.data) do
  1252.             local x = history_x + data.x
  1253.             local y = history_y + data.y
  1254.            
  1255.             if y > 0 and x > 0 then                        
  1256.                 if data.type == "font" then
  1257.                     EXT.SetFont(data.val)
  1258.                 elseif data.type == "string" then
  1259.                     EXT.SetTextPos(x, y)
  1260.                     EXT.DrawText(data.val)
  1261.                 elseif data.type == "color" then
  1262.                     local c = data.val
  1263.                    
  1264.                     EXT.SetColor(c.r, c.g, c.b, c.a * alpha)
  1265.                 elseif data.type == "custom" and not data.stop then
  1266.                     data.started = true
  1267.                     run_tag(data, "draw", x, y, alpha)
  1268.                 end
  1269.             end
  1270.         end
  1271.        
  1272.         for _, data in pairs(markup.data) do
  1273.             if data.type == "custom" then
  1274.                 if not data.stop and data.started and data.val.tag and data.val.tag.post then
  1275.                     data.started = false
  1276.                     run_tag(data, "post")
  1277.                 end
  1278.                
  1279.                 if panic then
  1280.                     data.stop = true
  1281.                 end
  1282.             end
  1283.         end
  1284.        
  1285.         if alpha == 0 then
  1286.             table.remove(history, i)
  1287.         end
  1288.     end
  1289.    
  1290.     EXT.SetAlphaMultiplier(1)  
  1291. end
  1292.  
  1293. function chathud.GetPlayer()
  1294.     return chathud.current_player or NULL
  1295. end
  1296.  
  1297. if GMOD then
  1298.  
  1299.     for name, data in pairs(chathud.fonts) do
  1300.         surface.CreateFont(data.name, data.data)
  1301.     end
  1302.    
  1303.     if surface.DrawFlag then
  1304.         chathud.tags.flag =
  1305.         {      
  1306.             arguments = {"gb"},
  1307.            
  1308.             draw = function(self, x,y,a, flag)
  1309.                 surface.DrawFlag(flag, x, y-12)
  1310.             end,
  1311.         }
  1312.     end
  1313.  
  1314.     for _, v in pairs(file.Find("materials/icon16/*.png", "GAME")) do
  1315.         C.shortcuts[v:gsub("(%.png)$","")] = "<texture=materials/icon16/" .. v .. ">"
  1316.     end
  1317.    
  1318.     function chathud.CanRunAnnoyingTags()
  1319.         local you = LocalPlayer()
  1320.         local him = chathud.GetPlayer()
  1321.        
  1322.         return
  1323.             not (
  1324.                 him:IsValid() and
  1325.                 him.IsFriend and
  1326.                 you ~= chathud.GetPlayer() and
  1327.                 not you:IsFriend(him)
  1328.             )
  1329.     end
  1330.    
  1331.     do
  1332.         -- kinda hacky but it should work
  1333.         hook.Add("PlayerSay", "chathud", function(ply)
  1334.             chathud.current_player = ply
  1335.             timer.Simple(0, function() chathud.current_player = NULL end)
  1336.         end)
  1337.         hook.Add("OnPlayerChat", "chathud", function(ply)
  1338.             chathud.current_player = ply
  1339.             timer.Simple(0, function() chathud.current_player = NULL end)
  1340.         end)
  1341.     end
  1342.    
  1343.     hook.Add("ChatText", "chathud", function(_, _, msg)
  1344.         chathud.AddText(
  1345.             {chathud.fonts.chatprint.name},
  1346.             chathud.fonts.chatprint.color,
  1347.             tostring(msg)
  1348.         )
  1349.     end)
  1350.  
  1351.     local chathud_show = EXT.CreateConVar("cl_chathud_show", 1)
  1352.  
  1353.     hook.Add("HUDShouldDraw", "chathud", function(name)
  1354.         if name == "CHudChat" and chathud_show:GetBool() then
  1355.             return false
  1356.         end
  1357.     end)
  1358.    
  1359.     hook.Add("HUDPaint", "chathud", function()
  1360.         if chathud_show:GetBool() then
  1361.             chathud.Draw()
  1362.         end
  1363.     end)
  1364.     hook.Add("HUDShouldDraw", "chathud", function(name)
  1365.         if name == "CHudChat" and chathud_show:GetBool() then
  1366.             return false
  1367.         end
  1368.     end)
  1369.    
  1370.     hook.Add("HUDPaint", "chathud", function()
  1371.         if chathud_show:GetBool() then
  1372.             chathud.Draw()
  1373.         end
  1374.     end)
  1375.    
  1376.     -- NEED: lua/includes/extensions/chat_addtext_hack.lua
  1377.     _G.PrimaryChatAddText = chathud.AddText
  1378.     chat.AddTextX = chathud.AddText
  1379. else
  1380.     function chathud.CanRunAnnoyingTags()
  1381.         return true
  1382.     end
  1383.    
  1384.     event.AddListener("OnDraw2D", "chathud", function()
  1385.         chathud.Draw()
  1386.     end)
  1387. end
Advertisement
Add Comment
Please, Sign In to add comment