Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- XeninUI = XeninUI or {}
- XeninUI.ORM = XeninUI.ORM or {}
- function XeninUI:CreateFont(name, size, weight, mergeTbl)
- local tbl = {
- font = "Montserrat Medium",
- -- Changing font... to match the old look we had to increase size by two
- size = size + 2,
- weight = weight or 500,
- extended = true
- }
- if (mergeTbl) then
- table.Merge(tbl, mergeTbl)
- end
- surface.CreateFont(name, tbl)
- end
- XeninUI.Branding = false -- Material("xenin/pantheon.png", "smooth")
- -- Materials
- XeninUI.Materials = {
- CloseButton = Material("xenin/closebutton.png", "noclamp smooth"),
- Search = Material("xenin/search.png", "noclamp smooth")
- }
- -- Animation
- XeninUI.TransitionTime = 0.15
- -- UI theme
- XeninUI.Theme = {
- Primary = Color(48, 48, 48),
- Navbar = Color(41, 41, 41),
- Background = Color(30, 30, 30),
- Accent = Color(41, 128, 185),
- OrangeRed = Color(228, 104, 78),
- Red = Color(230, 58, 64),
- Green = Color(46, 204, 113),
- Blue = Color(41, 128, 185),
- Yellow = Color(201, 176, 15),
- Purple = Color(142, 68, 173)
- }
- XeninUI.Frame = {
- Width = 960,
- Height = 720
- }
- local scrW, scrH = ScrW(), ScrH()
- --[[
- This code was generated by LAUX, a Lua transpiler
- LAUX is a fork of LAU with additional changes.
- More info & source code can be found at: https://gitlab.com/sleeppyy/laux
- ]]
- local blur = Material("pp/blurscreen")
- function XeninUI:DrawBlur(panel, amount)
- local x, y = panel:LocalToScreen(0, 0)
- local scrW, scrH = ScrW(), ScrH()
- surface.SetDrawColor(255, 255, 255)
- surface.SetMaterial(blur)
- for i = 1, 3 do
- blur:SetFloat("$blur", (i / 3) * (amount or 6))
- blur:Recompute()
- render.UpdateScreenEffectTexture()
- surface.DrawTexturedRect(x * -1, y * -1, scrW, scrH)
- end
- end
- if CLIENT then
- CreateClientConVar("xenin_hud_blur", 0)
- end
- function XeninUI:DrawBlurHUD(x, y, w, h, amt)
- local X, Y = 0, 0
- surface.SetDrawColor(255, 255, 255)
- surface.SetMaterial(blur)
- for i = 1, amt or 5 do
- blur:SetFloat("$blur", (i / 3) * 5)
- blur:Recompute()
- render.UpdateScreenEffectTexture()
- render.SetScissorRect(x, y, x + w, y + h, true)
- surface.DrawTexturedRect(X * -1, Y * -1, ScrW(), ScrH())
- render.SetScissorRect(0, 0, 0, 0, false)
- end
- end
- function XeninUI:FormatTime(seconds, format)
- if (not seconds) then
- seconds = 0
- end
- local hours = math.floor(seconds / 3600)
- local minutes = math.floor((seconds / 60) % 60)
- seconds = math.floor(seconds % 60)
- return string.format(format, hours, minutes, seconds)
- end
- local mat_white = Material("vgui/white")
- function draw.SimpleLinearGradient(x, y, w, h, startColor, endColor, horizontal)
- draw.LinearGradient(x, y, w, h, {
- {
- offset = 0,
- color = startColor
- },
- {
- offset = 1,
- color = endColor
- }
- }, horizontal)
- end
- function draw.LinearGradient(x, y, w, h, stops, horizontal)
- if #stops == 0 then
- return
- elseif #stops == 1 then
- surface.SetDrawColor(stops[1].color)
- surface.DrawRect(x, y, w, h)
- return
- end
- table.SortByMember(stops, "offset", true)
- render.SetMaterial(mat_white)
- mesh.Begin(MATERIAL_QUADS, #stops - 1)
- for i = 1, #stops - 1 do
- local offset1 = math.Clamp(stops[i].offset, 0, 1)
- local offset2 = math.Clamp(stops[i + 1].offset, 0, 1)
- if offset1 == offset2 then continue end
- local deltaX1, deltaY1, deltaX2, deltaY2
- local color1 = stops[i].color
- local color2 = stops[i + 1].color
- local r1, g1, b1, a1 = color1.r, color1.g, color1.b, color1.a
- local r2, g2, b2, a2
- local r3, g3, b3, a3 = color2.r, color2.g, color2.b, color2.a
- local r4, g4, b4, a4
- if horizontal then
- r2, g2, b2, a2 = r3, g3, b3, a3
- r4, g4, b4, a4 = r1, g1, b1, a1
- deltaX1 = offset1 * w
- deltaY1 = 0
- deltaX2 = offset2 * w
- deltaY2 = h
- else
- r2, g2, b2, a2 = r1, g1, b1, a1
- r4, g4, b4, a4 = r3, g3, b3, a3
- deltaX1 = 0
- deltaY1 = offset1 * h
- deltaX2 = w
- deltaY2 = offset2 * h
- end
- mesh.Color(r1, g1, b1, a1)
- mesh.Position(Vector(x + deltaX1, y + deltaY1))
- mesh.AdvanceVertex()
- mesh.Color(r2, g2, b2, a2)
- mesh.Position(Vector(x + deltaX2, y + deltaY1))
- mesh.AdvanceVertex()
- mesh.Color(r3, g3, b3, a3)
- mesh.Position(Vector(x + deltaX2, y + deltaY2))
- mesh.AdvanceVertex()
- mesh.Color(r4, g4, b4, a4)
- mesh.Position(Vector(x + deltaX1, y + deltaY2))
- mesh.AdvanceVertex()
- end
- mesh.End()
- end
- function XeninUI:DrawRotatedTexture(x, y, w, h, angle, cx, cy)
- cx, cy = cx or w / 2, cy or w / 2
- if (cx == w / 2 and cy == w / 2) then
- surface.DrawTexturedRectRotated(x, y, w, h, angle)
- else
- local vec = Vector(w / 2 - cx, cy - h / 2, 0)
- vec:Rotate(Angle(180, angle, -180))
- surface.DrawTexturedRectRotated(x - vec.x, y + vec.y, w, h, angle)
- end
- end
- function XeninUI:FormatMoney(number, decimals)
- decimals = decimals or 2
- if (number >= 1000000000) then
- return DarkRP.formatMoney(math.Round(number / 1000000000, 2)) .. " bil"
- elseif (number >= 1000000) then
- return DarkRP.formatMoney(math.Round(number / 1000000, 2)) .. " mil"
- elseif (number > 10000) then
- return DarkRP.formatMoney(math.Round(number / 1000, 2)) .. "k"
- end
- return DarkRP.formatMoney(number)
- end
- function XeninUI:DateToString(date)
- if not date then return "now" end
- local dif = os.ServerTime() - date
- if dif < 60 then
- return "a moment ago"
- elseif dif < (60 * 60) then
- local mins = math.Round(dif / 60, 0)
- local str = mins .. " minute" .. (mins == 1 and "" or "s") .. " ago"
- return str
- elseif dif < (60 * 60) * 24 then
- return os.date("%H:%M", date)
- else
- return os.date("%d/%m/%Y", date)
- end
- return "?"
- end
- if not XeninUI.__AddedPanelFunctions then
- local PNL = FindMetaTable("Panel")
- local Old_Remove = Old_Remove or PNL.Remove
- function PNL:Remove()
- for k, v in pairs(self.hooks or {}) do
- hook.Remove(v.name, k)
- end
- for k, v in pairs(self.timers or {}) do
- timer.Remove(k)
- end
- Old_Remove(self)
- end
- function PNL:AddHook(name, identifier, func)
- identifier = identifier .. " - " .. CurTime()
- self.hooks = self.hooks or {}
- self.hooks[identifier] = {
- name = name,
- func = function(...)
- if IsValid(self) then return func(self, ...) end
- end
- }
- hook.Add(name, identifier, self.hooks[identifier].func)
- end
- function PNL:GetHooks()
- return self.hooks or {}
- end
- function PNL:AddTimer(identifier, delay, rep, func)
- self.timers = self.timers or {}
- self.timers[identifier] = true
- timer.Create(identifier, delay, rep, function(...)
- if IsValid(self) then
- func(self, ...)
- end
- end)
- end
- function PNL:GetTimers()
- return self.timers or {}
- end
- function PNL:LerpAlpha(alpha, time, callback)
- callback = callback or function() end
- self.Alpha = self.Alpha or 0
- local oldThink = self.Think
- self.Think = function(pnl)
- if oldThink then
- oldThink(pnl)
- end
- self:SetAlpha(pnl.Alpha >= 250 and 255 or pnl.Alpha)
- end
- self:Lerp("Alpha", alpha, time, function()
- self.Think = oldThink
- callback(self)
- end)
- end
- XeninUI.__AddedPanelFunctions = true
- end
- local matLoading = Material("xenin/loading.png", "smooth")
- function XeninUI:DrawLoadingCircle(x, y, size, col)
- surface.SetMaterial(matLoading)
- surface.SetDrawColor(col or ColorAlpha(XeninUI.Theme.Accent, 100))
- XeninUI:DrawRotatedTexture(x, y, size, size, ((ct or CurTime()) % 360) * -100)
- end
- local function toLines(text, font, mWidth)
- surface.SetFont(font)
- local buffer = {}
- local nLines = {}
- for word in string.gmatch(text, "%S+") do
- local w, h = surface.GetTextSize(table.concat(buffer, " ") .. " " .. word)
- if w > mWidth then
- table.insert(nLines, table.concat(buffer, " "))
- buffer = {}
- end
- table.insert(buffer, word)
- end
- if #buffer > 0 then
- table.insert(nLines, table.concat(buffer, " "))
- end
- return nLines
- end
- local function drawMultiLine(text, font, mWidth, spacing, x, y, color, alignX, alignY, sAmt, sAlpha)
- local mLines = toLines(text, font, mWidth)
- local amt = #mLines - 1
- for i, line in pairs(mLines) do
- if (sAmt and sAlpha) then
- XeninUI:DrawShadowText(line, font, x, y + (i - 1) * spacing - amt * spacing / 2, color, alignX, alignY, sAmt, sAlpha)
- else
- draw.SimpleText(line, font, x, y + (i - 1) * spacing - amt * spacing / (alignY == TEXT_ALIGN_CENTER and 2 or 1), color, alignX, alignY)
- end
- end
- return amt * spacing
- end
- XeninUI.DrawMultiLine = drawMultiLine
- local matCredit = Material("xenin/credit_small.png", "smooth")
- function XeninUI:DrawCreditsText(text, font, x, y, col, xAlign, yAlign, textY, iconColor, spacing)
- textY = textY or 1
- iconColor = iconColor or color_white
- spacing = spacing or 4
- surface.SetFont(font)
- local tw, th = surface.GetTextSize(text)
- local size = th
- if (xAlign == TEXT_ALIGN_LEFT) then
- surface.SetMaterial(matCredit)
- surface.SetDrawColor(iconColor)
- surface.DrawTexturedRect(x, y, size, size)
- draw.SimpleText(text, font, x + size + spacing, y + textY, col, xAlign, yAlign)
- elseif (xAlign == TEXT_ALIGN_CENTER) then
- x = x + size / 2 + 2
- surface.SetMaterial(matCredit)
- surface.SetDrawColor(iconColor)
- surface.DrawTexturedRect(x - tw / 2 - size - spacing, y, size, size)
- draw.SimpleText(text, font, x, y + textY, col, xAlign, yAlign)
- elseif (xAlign == TEXT_ALIGN_RIGHT) then
- x = x + size / 2 + 2
- surface.SetMaterial(matCredit)
- surface.SetDrawColor(iconColor)
- surface.DrawTexturedRect(x - tw - size - spacing, y, size, size)
- draw.SimpleText(text, font, x, y + textY, col, xAlign, yAlign)
- end
- end
- function XeninUI:DrawArc(x, y, ang, p, rad, color, seg)
- seg = seg or 80
- ang = (-ang) + 180
- local circle = {}
- table.insert(circle, {
- x = x,
- y = y
- })
- for i = 0, seg do
- local a = math.rad((i / seg) * -p + ang)
- table.insert(circle, {
- x = x + math.sin(a) * rad,
- y = y + math.cos(a) * rad
- })
- end
- surface.SetDrawColor(color)
- draw.NoTexture()
- surface.DrawPoly(circle)
- end
- function XeninUI:CalculateArc(x, y, ang, p, rad, seg)
- seg = seg or 80
- ang = (-ang) + 180
- local circle = {}
- table.insert(circle, {
- x = x,
- y = y
- })
- for i = 0, seg do
- local a = math.rad((i / seg) * -p + ang)
- table.insert(circle, {
- x = x + math.sin(a) * rad,
- y = y + math.cos(a) * rad
- })
- end
- return circle
- end
- function XeninUI:DrawCachedArc(circle, color)
- surface.SetDrawColor(color)
- draw.NoTexture()
- surface.DrawPoly(circle)
- end
- function XeninUI:DrawRoundedBoxEx(radius, x, y, w, h, col, tl, tr, bl, br)
- x = math.floor(x)
- y = math.floor(y)
- w = math.floor(w)
- h = math.floor(h)
- radius = math.Clamp(math.floor(radius), 0, math.min(h / 2, w / 2))
- if (radius == 0) then
- surface.SetDrawColor(col)
- surface.DrawRect(x, y, w, h)
- return
- end
- surface.SetDrawColor(col)
- surface.DrawRect(x + radius, y, w - radius * 2, radius)
- surface.DrawRect(x, y + radius, w, h - radius * 2)
- surface.DrawRect(x + radius, y + h - radius, w - radius * 2, radius)
- if tl then
- XeninUI:DrawArc(x + radius, y + radius, 270, 90, radius, col, radius)
- else
- surface.SetDrawColor(col)
- surface.DrawRect(x, y, radius, radius)
- end
- if tr then
- XeninUI:DrawArc(x + w - radius, y + radius, 0, 90, radius, col, radius)
- else
- surface.SetDrawColor(col)
- surface.DrawRect(x + w - radius, y, radius, radius)
- end
- if bl then
- XeninUI:DrawArc(x + radius, y + h - radius, 180, 90, radius, col, radius)
- else
- surface.SetDrawColor(col)
- surface.DrawRect(x, y + h - radius, radius, radius)
- end
- if br then
- XeninUI:DrawArc(x + w - radius, y + h - radius, 90, 90, radius, col, radius)
- else
- surface.SetDrawColor(col)
- surface.DrawRect(x + w - radius, y + h - radius, radius, radius)
- end
- end
- function XeninUI:DrawRoundedBox(radius, x, y, w, h, col)
- XeninUI:DrawRoundedBoxEx(radius, x, y, w, h, col, true, true, true, true)
- end
- function XeninUI:MaskInverse(maskFn, drawFn, pixel)
- pixel = pixel or 1
- render.ClearStencil()
- render.SetStencilEnable(true)
- render.SetStencilWriteMask(1)
- render.SetStencilTestMask(1)
- render.SetStencilFailOperation(STENCILOPERATION_REPLACE)
- render.SetStencilPassOperation(STENCILOPERATION_REPLACE)
- render.SetStencilZFailOperation(STENCILOPERATION_KEEP)
- render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_NEVER)
- render.SetStencilReferenceValue(pixel)
- maskFn()
- render.SetStencilFailOperation(STENCILOPERATION_REPLACE)
- render.SetStencilPassOperation(STENCILOPERATION_REPLACE)
- render.SetStencilZFailOperation(STENCILOPERATION_KEEP)
- render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_EQUAL)
- render.SetStencilReferenceValue(pixel - 1)
- drawFn()
- render.SetStencilEnable(false)
- render.ClearStencil()
- end
- function XeninUI:Mask(maskFn, drawFn, pixel)
- pixel = pixel or 1
- render.ClearStencil()
- render.SetStencilEnable(true)
- render.SetStencilWriteMask(1)
- render.SetStencilTestMask(1)
- render.SetStencilFailOperation(STENCILOPERATION_REPLACE)
- render.SetStencilPassOperation(STENCILOPERATION_KEEP)
- render.SetStencilZFailOperation(STENCILOPERATION_KEEP)
- render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_NEVER)
- render.SetStencilReferenceValue(pixel)
- maskFn()
- render.SetStencilFailOperation(STENCILOPERATION_KEEP)
- render.SetStencilPassOperation(STENCILOPERATION_REPLACE)
- render.SetStencilZFailOperation(STENCILOPERATION_KEEP)
- render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_EQUAL)
- render.SetStencilReferenceValue(pixel)
- drawFn()
- render.SetStencilEnable(false)
- render.ClearStencil()
- end
- XeninUI:CreateFont("XeninUI.NPC.Overhead", 160)
- function XeninUI:DrawNPCOverhead(npc, tbl)
- local alpha = tbl.alpha or 255
- local text = tbl.text or npc.PrintName or "NO NAME"
- local icon = tbl.icon
- local hover = tbl.sin
- local xOffset = tbl.xOffset or 0
- local textOffset = tbl.textOffset or 0
- local col = tbl.color or XeninUI.Theme.Accent
- col = ColorAlpha(col, alpha)
- local str = text
- surface.SetFont("XeninUI.NPC.Overhead")
- local width = surface.GetTextSize(str)
- width = width + 40
- if icon then
- width = width + (64 * 3)
- else
- width = width + 64
- end
- local center = 900 / 2
- local x = -width / 2 - 30 + (xOffset or 0)
- local y = 220
- local sin = math.sin(CurTime() * 2)
- if hover then
- y = math.Round(y + (sin * 30))
- end
- local h = 64 * 3
- local isLookingAt
- if (alpha > 0.5) then
- isLookingAt = LocalPlayer():GetEyeTrace().Entity == npc
- end
- npc.overheadAlpha = npc.overheadAlpha or 0
- if isLookingAt then
- npc.overheadAlpha = math.Clamp(npc.overheadAlpha + (FrameTime() * 3), 0, 1)
- else
- npc.overheadAlpha = math.Clamp(npc.overheadAlpha - (FrameTime() * 3), 0, 1)
- end
- local darkerColor = Color(col.r * 0.5, col.g * 0.5, col.b * 0.5)
- XeninUI:DrawRoundedBox(64, x, y, width, h, ColorAlpha(darkerColor, npc.overheadAlpha * 255))
- XeninUI:DrawRoundedBox(64, x + 8, y + 8, width - 16, h - 16, ColorAlpha(col, npc.overheadAlpha * 255))
- local textX = not icon and (width / 2) or h
- XeninUI:DrawShadowText(str, "XeninUI.NPC.Overhead", x + textX + textOffset, h / 2 + y - 10, Color(225, 225, 225, alpha), icon and TEXT_ALIGN_LEFT or TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 5, 125)
- if icon then
- surface.SetDrawColor(255, 255, 255, alpha)
- surface.SetMaterial(icon)
- local margin = tbl.icon_margin or tbl.iconMargin or 30
- surface.DrawTexturedRect(x + margin, y + margin, h - (margin * 2), h - (margin * 2))
- end
- end
- function XeninUI:DrawShadowText(text, font, x, y, col, xAlign, yAlign, amt, shadow)
- for i = 1, amt do
- draw.SimpleText(text, font, x + i, y + i, Color(0, 0, 0, i * (shadow or 50)), xAlign, yAlign)
- end
- draw.SimpleText(text, font, x, y, col, xAlign, yAlign)
- end
- function XeninUI:DrawOutlinedText(str, font, x, y, col, xAlign, yAlign, outlineCol, thickness)
- thickness = thickness or 1
- for i = 1, thickness do
- draw.SimpleText(str, font, x - thickness, y - thickness, outlineCol or color_black, xAlign, yAlign)
- draw.SimpleText(str, font, x - thickness, y + thickness, outlineCol or color_black, xAlign, yAlign)
- draw.SimpleText(str, font, x + thickness, y - thickness, outlineCol or color_black, xAlign, yAlign)
- draw.SimpleText(str, font, x + thickness, y + thickness, outlineCol or color_black, xAlign, yAlign)
- end
- draw.SimpleText(str, font, x, y, col, xAlign, yAlign)
- end
- function XeninUI:DrawHollowArc(cx, cy, radius, thickness, startang, endang, roughness, color)
- surface.SetDrawColor(color)
- local arc = self:CacheHollowArc(cx, cy, radius, thickness, startang, endang, roughness)
- for i, vertex in pairs(arc) do
- surface.DrawPoly(vertex)
- end
- end
- function XeninUI:CacheHollowArc(cx, cy, radius, thickness, startang, endang, roughness)
- local triarc = {}
- local roughness = math.max(roughness or 1, 1)
- local step = roughness
- local startang, endang = startang or 0, endang or 0
- if startang > endang then
- step = math.abs(step) * -1
- end
- local inner = {}
- local r = radius - thickness
- for deg = startang, endang, step do
- local rad = math.rad(deg)
- local ox, oy = cx + (math.cos(rad) * r), cy + (-math.sin(rad) * r)
- table.insert(inner, {
- x = ox,
- y = oy,
- u = (ox - cx) / radius + .5,
- v = (oy - cy) / radius + .5
- })
- end
- local outer = {}
- for deg = startang, endang, step do
- local rad = math.rad(deg)
- local ox, oy = cx + (math.cos(rad) * radius), cy + (-math.sin(rad) * radius)
- table.insert(outer, {
- x = ox,
- y = oy,
- u = (ox - cx) / radius + .5,
- v = (oy - cy) / radius + .5
- })
- end
- for tri = 1, #inner * 2 do
- local p1, p2, p3
- p1 = outer[math.floor(tri / 2) + 1]
- p3 = inner[math.floor((tri + 1) / 2) + 1]
- if tri % 2 == 0 then
- p2 = outer[math.floor((tri + 1) / 2)]
- else
- p2 = inner[math.floor((tri + 1) / 2)]
- end
- table.insert(triarc, {p1, p2, p3})
- end
- return triarc
- end
- function XeninUI:DualText(title, subtitle, x, y, w, h)
- x = x or 0
- y = y or 0
- surface.SetFont(title[2])
- local tW, tH = surface.GetTextSize(title[1])
- surface.SetFont(subtitle[2])
- local sW, sH = surface.GetTextSize(subtitle[1])
- XeninUI:DrawShadowText(title[1], title[2], x, y + (h / 2 - sH / 2), title[3], title[4], TEXT_ALIGN_CENTER, title[5], title[6])
- XeninUI:DrawShadowText(subtitle[1], subtitle[2], x, y + (h / 2 + tH / 2), subtitle[3], subtitle[4], TEXT_ALIGN_CENTER, subtitle[5], subtitle[6])
- end
- function XeninUI:DrawIconRotated(x, y, w, h, rotation, pnl, col, loadCol)
- col = col or color_white
- loadCol = loadCol or XeninUI.Theme.Accent
- if (pnl.Icon and type(pnl.Icon) == "IMaterial") then
- surface.SetMaterial(pnl.Icon)
- surface.SetDrawColor(col)
- XeninUI:DrawRotatedTexture(x, y, w, h, rotation)
- elseif (pnl.Icon ~= nil) then
- XeninUI:DrawLoadingCircle(h, h, h, loadCol)
- end
- end
- --[[
- This code was generated by LAUX, a Lua transpiler
- LAUX is a fork of LAU with additional changes.
- More info & source code can be found at: https://gitlab.com/sleeppyy/laux
- ]]
- local PNL = FindMetaTable("Panel")
- function PNL:LerpColor(var, to, duration, callback)
- if (not duration) then
- duration = XeninUI.TransitionTime
- end
- local color = self[var]
- local anim = self:NewAnimation(duration)
- anim.Color = to
- anim.Think = function(anim, pnl, fract)
- local newFract = XeninUI:Ease(fract, 0, 1, 1)
- if (not anim.StartColor) then
- anim.StartColor = color
- end
- local newColor = XeninUI:LerpColor(newFract, anim.StartColor, anim.Color)
- self[var] = newColor
- end
- anim.OnEnd = function()
- if callback then
- callback(self)
- end
- end
- end
- function PNL:LerpVector(var, to, duration, callback)
- if (not duration) then
- duration = XeninUI.TransitionTime
- end
- local vector = self[var]
- local anim = self:NewAnimation(duration)
- anim.Vector = to
- anim.Think = function(anim, pnl, fract)
- local newFract = XeninUI:Ease(fract, 0, 1, 1)
- if (not anim.StartVector) then
- anim.StartVector = vector
- end
- local newColor = XeninUI:LerpVector(newFract, anim.StartVector, anim.Vector)
- self[var] = newColor
- end
- anim.OnEnd = function()
- if callback then
- callback(self)
- end
- end
- end
- function XeninUI:Ease(t, b, c, d)
- t = t / d
- local ts = t * t
- local tc = ts * t
- return b + c * (-2 * tc + 3 * ts)
- end
- function XeninUI:EaseInOutQuintic(t, b, c, d)
- t = t / d
- local ts = t * t
- local tc = ts * t
- return b + c * (6 * tc * ts + -15 * ts * ts + 10 * tc)
- end
- function XeninUI:RemoveDebounce(name)
- timer.Remove("_debounce." .. name)
- end
- function XeninUI:Debounce(name, wait, func)
- if timer.Exists("_debounce." .. name) then
- timer.Remove("_debounce." .. name)
- end
- timer.Create("_debounce." .. name, wait, 1, function()
- func()
- timer.Remove("_debounce." .. name)
- end)
- end
- function XeninUI:LerpColor(fract, from, to)
- return Color(Lerp(fract, from.r, to.r), Lerp(fract, from.g, to.g), Lerp(fract, from.b, to.b), Lerp(fract, from.a or 255, to.a or 255))
- end
- function XeninUI:GetAngleBetweenTwoVectors(a, b)
- local vec = (a - b):GetNormalized()
- local ang = vec:Angle()
- return ang
- end
- function XeninUI:GetVector2DDistance(a, b)
- return math.sqrt((a.x - b.x) ^ 2 + (a.y - b.y) ^ 2)
- end
- function XeninUI:LerpVector(frac, from, to, ease)
- local newFract = ease and ease(frac, 0, 1, 1) or XeninUI:Ease(frac, 0, 1, 1)
- return LerpVector(newFract, from, to)
- end
- function XeninUI:LerpAngle(frac, from, to, ease)
- local newFract = ease and ease(frac, 0, 1, 1) or XeninUI:Ease(frac, 0, 1, 1)
- return LerpAngle(newFract, from, to)
- end
- function XeninUI:Map(tbl, func)
- local newTbl = {}
- for i, v in pairs(tbl) do
- newTbl[i] = func(v, i)
- end
- return newTbl
- end
- function XeninUI:Hue2RGB(p, q, t)
- if t < 0 then
- t = t + 1
- end
- if t > 1 then
- t = t - 1
- end
- if t < 1 / 6 then return p + (q - p) * 6 * t end
- if t < 1 / 2 then return q end
- if t < 2 / 3 then return p + (q - p) * (2 / 3 - t) * 6 end
- return p
- end
- function XeninUI:HSLToColor(h, s, l, a)
- local r, g, b
- local t = h / (2 * math.pi)
- if s == 0 then
- r, g, b = l, l, l
- else
- local q
- if l < 0.5 then
- q = l * (1 + s)
- else
- q = l + s - l * s
- end
- local p = 2 * l - q
- r = self:Hue2RGB(p, q, t + 1 / 3)
- g = self:Hue2RGB(p, q, t)
- b = self:Hue2RGB(p, q, t - 1 / 3)
- end
- return Color(r * 255, g * 255, b * 255, (a or 1) * 255)
- end
- function XeninUI:ColorToHSL(col)
- local r = col.r / 255
- local g = col.g / 255
- local b = col.b / 255
- local max, min = math.max(r, g, b), math.min(r, g, b)
- local b = max + min
- local h = b / 2
- if max == min then return 0, 0, h end
- local s, l = h, h
- local d = max - min
- s = l > .5 and d / (2 - b) or d / b
- if max == r then
- h = (g - b) / d + (g < b and 6 or 0)
- elseif max == g then
- h = (b - r) / d + 2
- elseif max == b then
- h = (r - g) / d + 4
- end
- return h * .16667, s, l
- end
- function XeninUI:DecToHex(d, zeros)
- return string.format("%0" .. (zeros or 2) .. "x", d)
- end
- function XeninUI:RGBToHex(color)
- return "#" .. self:DecToHex(math.max(math.min(color.r, 255), 0)) .. self:DecToHex(math.max(math.min(color.g, 255), 0)) .. self:DecToHex(math.max(math.min(color.b, 255), 0))
- end
- function XeninUI:HexToRGB(hex)
- hex = hex:gsub("#", "")
- if (#hex == 3) then
- local r = hex:sub(1, 1)
- local g = hex:sub(2, 2)
- local b = hex:sub(3, 3)
- return Color(tonumber("0x" .. r .. r), tonumber("0x" .. g .. g), tonumber("0x" .. b .. b))
- end
- return Color(tonumber("0x" .. hex:sub(1, 2)), tonumber("0x" .. hex:sub(3, 4)), tonumber("0x" .. hex:sub(5, 6)))
- end
- function PNL:LerpAngle(var, to, duration, callback)
- if (not duration) then
- duration = XeninUI.TransitionTime
- end
- local angle = self[var]
- local anim = self:NewAnimation(duration)
- anim.Angle = to
- anim.Think = function(anim, pnl, fract)
- local newFract = XeninUI:Ease(fract, 0, 1, 1)
- if (not anim.StartAngle) then
- anim.StartAngle = angle
- end
- local newColor = XeninUI:LerpAngle(newFract, anim.StartAngle, anim.Angle)
- self[var] = newColor
- end
- anim.OnEnd = function()
- if callback then
- callback(self)
- end
- end
- end
- function PNL:EndAnimations()
- for i, v in pairs(self.m_AnimList or {}) do
- if v.OnEnd then
- v:OnEnd(self)
- end
- self.m_AnimList[i] = nil
- end
- end
- function PNL:Lerp(var, to, duration, callback)
- if (not duration) then
- duration = XeninUI.TransitionTime
- end
- local varStart = self[var]
- local anim = self:NewAnimation(duration)
- anim.Goal = to
- anim.Think = function(anim, pnl, fract)
- local newFract = XeninUI:Ease(fract, 0, 1, 1)
- if (not anim.Start) then
- anim.Start = varStart
- end
- local new = Lerp(newFract, anim.Start, anim.Goal)
- self[var] = new
- end
- anim.OnEnd = function()
- if callback then
- callback(self)
- end
- end
- end
- function PNL:LerpMove(x, y, duration, callback)
- if (not duration) then
- duration = XeninUI.TransitionTime
- end
- local anim = self:NewAnimation(duration)
- anim.Pos = Vector(x, y)
- anim.Think = function(anim, pnl, fract)
- local newFract = XeninUI:Ease(fract, 0, 1, 1)
- if (not anim.StartPos) then
- anim.StartPos = Vector(pnl.x, pnl.y, 0)
- end
- local new = LerpVector(newFract, anim.StartPos, anim.Pos)
- self:SetPos(new.x, new.y)
- end
- anim.OnEnd = function()
- if callback then
- callback(self)
- end
- end
- end
- function PNL:LerpMoveY(y, duration, callback)
- if (not duration) then
- duration = XeninUI.TransitionTime
- end
- local anim = self:NewAnimation(duration)
- anim.Pos = y
- anim.Think = function(anim, pnl, fract)
- local newFract = XeninUI:Ease(fract, 0, 1, 1)
- if (not anim.StartPos) then
- anim.StartPos = pnl.y
- end
- local new = Lerp(newFract, anim.StartPos, anim.Pos)
- self:SetPos(pnl.x, new)
- end
- anim.OnEnd = function()
- if callback then
- callback(self)
- end
- end
- end
- function PNL:LerpMoveX(x, duration, callback)
- if (not duration) then
- duration = XeninUI.TransitionTime
- end
- local anim = self:NewAnimation(duration)
- anim.Pos = x
- anim.Think = function(anim, pnl, fract)
- local newFract = XeninUI:Ease(fract, 0, 1, 1)
- if (not anim.StartPos) then
- anim.StartPos = pnl.x
- end
- local new = Lerp(newFract, anim.StartPos, anim.Pos)
- self:SetPos(new, pnl.y)
- end
- anim.OnEnd = function()
- if callback then
- callback(self)
- end
- end
- end
- function PNL:LerpHeight(height, duration, callback, easeFunc)
- if (not duration) then
- duration = XeninUI.TransitionTime
- end
- if (not easeFunc) then
- easeFunc = function(a, b, c, d) return XeninUI:Ease(a, b, c, d) end
- end
- local anim = self:NewAnimation(duration)
- anim.Height = height
- anim.Think = function(anim, pnl, fract)
- local newFract = easeFunc(fract, 0, 1, 1)
- if (not anim.StartHeight) then
- anim.StartHeight = pnl:GetTall()
- end
- local new = Lerp(newFract, anim.StartHeight, anim.Height)
- self:SetTall(new)
- end
- anim.OnEnd = function()
- if callback then
- callback(self)
- end
- end
- end
- function PNL:LerpWidth(width, duration, callback, easeFunc)
- if (not duration) then
- duration = XeninUI.TransitionTime
- end
- if (not easeFunc) then
- easeFunc = function(a, b, c, d) return XeninUI:Ease(a, b, c, d) end
- end
- local anim = self:NewAnimation(duration)
- anim.Width = width
- anim.Think = function(anim, pnl, fract)
- local newFract = easeFunc(fract, 0, 1, 1)
- if (not anim.StartWidth) then
- anim.StartWidth = pnl:GetWide()
- end
- local new = Lerp(newFract, anim.StartWidth, anim.Width)
- self:SetWide(new)
- end
- anim.OnEnd = function()
- if callback then
- callback(self)
- end
- end
- end
- function PNL:LerpSize(w, h, duration, callback)
- if (not duration) then
- duration = XeninUI.TransitionTime
- end
- local anim = self:NewAnimation(duration)
- anim.Size = Vector(w, h)
- anim.Think = function(anim, pnl, fract)
- local newFract = XeninUI:Ease(fract, 0, 1, 1)
- if (not anim.StartSize) then
- anim.StartSize = Vector(pnl:GetWide(), pnl:GetWide(), 0)
- end
- local new = LerpVector(newFract, anim.StartSize, anim.Size)
- self:SetSize(new.x, new.y)
- end
- anim.OnEnd = function()
- if callback then
- callback()
- end
- end
- end
- local function Load()
- BSHADOWS = {}
- local resStr = scrW .. "" .. scrH
- --The original drawing layer
- BSHADOWS.RenderTarget = GetRenderTarget("bshadows_original_" .. resStr, scrW, scrH)
- --The shadow layer
- BSHADOWS.RenderTarget2 = GetRenderTarget("bshadows_shadow_" .. resStr, scrW, scrH)
- --The matarial to draw the render targets on
- BSHADOWS.ShadowMaterial = CreateMaterial("bshadows", "UnlitGeneric", {
- ["$translucent"] = 1,
- ["$vertexalpha"] = 1,
- ["alpha"] = 1
- })
- --When we copy the rendertarget it retains color, using this allows up to force any drawing to be black
- --Then we can blur it to create the shadow effect
- BSHADOWS.ShadowMaterialGrayscale = CreateMaterial("bshadows_grayscale", "UnlitGeneric", {
- ["$translucent"] = 1,
- ["$vertexalpha"] = 1,
- ["$alpha"] = 1,
- ["$color"] = "0 0 0",
- ["$color2"] = "0 0 0"
- })
- --Call this to begin drawing a shadow
- BSHADOWS.BeginShadow = function()
- --Set the render target so all draw calls draw onto the render target instead of the screen
- render.PushRenderTarget(BSHADOWS.RenderTarget)
- --Clear is so that theres no color or alpha
- render.OverrideAlphaWriteEnable(true, true)
- render.Clear(0, 0, 0, 0)
- render.OverrideAlphaWriteEnable(false, false)
- --Start Cam2D as where drawing on a flat surface
- cam.Start2D()
- end
- --Now leave the rest to the user to draw onto the surface
- --This will draw the shadow, and mirror any other draw calls the happened during drawing the shadow
- BSHADOWS.EndShadow = function(intensity, spread, blur, opacity, direction, distance, _shadowOnly)
- --Set default opcaity
- opacity = opacity or 255
- direction = direction or 0
- distance = distance or 0
- _shadowOnly = _shadowOnly or false
- --Copy this render target to the other
- render.CopyRenderTargetToTexture(BSHADOWS.RenderTarget2)
- --Blur the second render target
- if blur > 0 then
- render.OverrideAlphaWriteEnable(true, true)
- render.BlurRenderTarget(BSHADOWS.RenderTarget2, spread, spread, blur)
- render.OverrideAlphaWriteEnable(false, false)
- end
- --First remove the render target that the user drew
- render.PopRenderTarget()
- --Now update the material to what was drawn
- BSHADOWS.ShadowMaterial:SetTexture('$basetexture', BSHADOWS.RenderTarget)
- --Now update the material to the shadow render target
- BSHADOWS.ShadowMaterialGrayscale:SetTexture('$basetexture', BSHADOWS.RenderTarget2)
- --Work out shadow offsets
- local xOffset = math.sin(math.rad(direction)) * distance
- local yOffset = math.cos(math.rad(direction)) * distance
- --Now draw the shadow
- BSHADOWS.ShadowMaterialGrayscale:SetFloat("$alpha", opacity / 255) --set the alpha of the shadow
- render.SetMaterial(BSHADOWS.ShadowMaterialGrayscale)
- for i = 1, math.ceil(intensity) do
- render.DrawScreenQuadEx(xOffset, yOffset, scrW, scrH)
- end
- if not _shadowOnly then
- --Now draw the original
- BSHADOWS.ShadowMaterial:SetTexture('$basetexture', BSHADOWS.RenderTarget)
- render.SetMaterial(BSHADOWS.ShadowMaterial)
- render.DrawScreenQuad()
- end
- cam.End2D()
- end
- --This will draw a shadow based on the texture you passed it.
- BSHADOWS.DrawShadowTexture = function(texture, intensity, spread, blur, opacity, direction, distance, shadowOnly)
- --Set default opcaity
- opacity = opacity or 255
- direction = direction or 0
- distance = distance or 0
- shadowOnly = shadowOnly or false
- --Copy the texture we wish to create a shadow for to the shadow render target
- render.CopyTexture(texture, BSHADOWS.RenderTarget2)
- --Blur the second render target
- if blur > 0 then
- render.PushRenderTarget(BSHADOWS.RenderTarget2)
- render.OverrideAlphaWriteEnable(true, true)
- render.BlurRenderTarget(BSHADOWS.RenderTarget2, spread, spread, blur)
- render.OverrideAlphaWriteEnable(false, false)
- render.PopRenderTarget()
- end
- --Now update the material to the shadow render target
- BSHADOWS.ShadowMaterialGrayscale:SetTexture('$basetexture', BSHADOWS.RenderTarget2)
- --Work out shadow offsets
- local xOffset = math.sin(math.rad(direction)) * distance
- local yOffset = math.cos(math.rad(direction)) * distance
- --Now draw the shadow
- BSHADOWS.ShadowMaterialGrayscale:SetFloat("$alpha", opacity / 255) --Set the alpha
- render.SetMaterial(BSHADOWS.ShadowMaterialGrayscale)
- for i = 1, math.ceil(intensity) do
- render.DrawScreenQuadEx(xOffset, yOffset, scrW, scrH)
- end
- if not shadowOnly then
- --Now draw the original
- BSHADOWS.ShadowMaterial:SetTexture('$basetexture', texture)
- render.SetMaterial(BSHADOWS.ShadowMaterial)
- render.DrawScreenQuad()
- end
- end
- end
- Load()
- timer.Create("XeninUI.BShadows.ResolutionCheck", 1, 0, function()
- if (ScrW() ~= scrW or ScrH() ~= scrH) then
- scrW = ScrW()
- scrH = ScrH()
- Load()
- end
- end)
- XeninUI:CreateFont("XeninUI.Frame.Title", 28)
- local PANEL = {}
- function PANEL:Init()
- self.top = vgui.Create("Panel", self)
- self.top:Dock(TOP)
- self.top.Paint = function(pnl, w, h)
- draw.RoundedBoxEx(6, 0, 0, w, h, XeninUI.Theme.Primary, true, true, false, false)
- end
- if XeninUI.Branding then
- local isMat = type(XeninUI.Branding) == "IMaterial"
- self.branding = vgui.Create("Panel", self.top)
- self.branding:Dock(LEFT)
- if (not isMat) then
- XeninUI:DownloadIcon(self.branding, XeninUI.Branding)
- end
- self.branding.Paint = function(pnl, w, h)
- if isMat then
- surface.SetDrawColor(color_white)
- surface.SetMaterial(XeninUI.Branding)
- surface.DrawTexturedRect(4, 4, w - 8, h - 8)
- else
- XeninUI:DrawIcon(4, 4, w - 8, h - 8, pnl)
- end
- end
- end
- self.title = vgui.Create("DLabel", self.top)
- self.title:Dock(LEFT)
- self.title:DockMargin(IsValid(self.branding) and 0 or 10, 0, 0, 0)
- self.title:SetFont("XeninUI.Frame.Title")
- self.title:SetTextColor(color_white)
- self.closeBtn = vgui.Create("DButton", self.top)
- self.closeBtn:Dock(RIGHT)
- self.closeBtn:SetText("")
- self.closeBtn.CloseButton = Color(195, 195, 195)
- self.closeBtn.Alpha = 0
- self.closeBtn.DoClick = function(pnl)
- self:Remove()
- end
- self.closeBtn.Paint = function(pnl, w, h)
- if pnl:IsHovered() then
- pnl.Alpha = Lerp(FrameTime() * 13, pnl.Alpha, 255)
- else
- pnl.Alpha = Lerp(FrameTime() * 13, pnl.Alpha, 0)
- end
- draw.RoundedBox(6, 0, 0, w, h, ColorAlpha(XeninUI.Theme.Red, pnl.Alpha))
- surface.SetDrawColor(pnl.CloseButton)
- surface.SetMaterial(XeninUI.Materials.CloseButton)
- surface.DrawTexturedRect(12, 12, w - 24, h - 24)
- end
- end
- function PANEL:SetTitle(str)
- self.title:SetText(str)
- self.title:SizeToContents()
- end
- function PANEL:PerformLayout(w, h)
- self.top:SetTall(40)
- if IsValid(self.branding) then
- self.branding:SetWide(self.top:GetTall())
- end
- self.closeBtn:SetWide(self.top:GetTall())
- end
- function PANEL:Paint(w, h)
- local x, y = self:LocalToScreen()
- BSHADOWS.BeginShadow()
- draw.RoundedBox(6, x, y, w, h, XeninUI.Theme.Background)
- BSHADOWS.EndShadow(1, 2, 2, 255, 0, 0)
- end
- function PANEL:ShowCloseButton(show)
- self.closeBtn:SetVisible(show)
- end
- vgui.Register("XeninUI.Frame", PANEL, "EditablePanel")
- local PANEL1 = {}
- local matTick = Material("xenin/tick.png", "smooth")
- function PANEL1:Init()
- self:SetText("")
- self.State = false
- self.AnimationController = 0
- self.Color = XeninUI.Theme.Accent
- self.Background = XeninUI.Theme.Primary
- self.Font = "XeninUI.CheckboxV2"
- end
- XeninUI:CreateFont("XeninUI.CheckboxV2", 18)
- function PANEL1:Paint(w, h)
- XeninUI:MaskInverse(function()
- surface.SetDrawColor(color_white)
- local x = h * math.Clamp((self.AnimationController - 0.5) * 2, 0, 1)
- surface.DrawRect(h - x, 0, h, h)
- end, function()
- XeninUI:DrawRoundedBoxEx(6, 0, 0, h, h * 0.5, self.Color, true, true, false, false)
- end)
- XeninUI:MaskInverse(function()
- surface.SetDrawColor(color_white)
- local width = h * math.Clamp(self.AnimationController * 2, 0, 1)
- surface.DrawRect(0, 0, width, h)
- end, function()
- XeninUI:DrawRoundedBoxEx(6, 0, h * 0.5, h, h * 0.5, self.Color, false, false, true, true)
- end)
- XeninUI:DrawRoundedBox(4, 2, 2, h - 4, h - 4, self.Background)
- XeninUI:MaskInverse(function()
- surface.SetDrawColor(color_white)
- local x = h * math.Clamp((self.AnimationController - 1) * 2, 0, 1)
- surface.DrawRect(x, 0, h, h)
- end, function()
- surface.SetMaterial(matTick)
- surface.SetDrawColor(self.Color)
- surface.DrawTexturedRect(0, 0, h, h)
- end)
- if self.Text then
- local x = h + 5
- XeninUI:DrawShadowText(self.Text, self.Font, x, h / 2 - 1, self.TextColor or color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, 1, 125)
- end
- end
- function PANEL1:SizeToContentsX()
- surface.SetFont(self.Font)
- local tw = surface.GetTextSize(self.Text)
- self:SetWide(self:GetTall() + 5 + tw)
- end
- function PANEL1:SetState(state, instant)
- self.State = state
- if state then
- if instant then
- self:EndAnimations()
- self.AnimationController = 1.5
- else
- self:Lerp("AnimationController", 1.5, 0.4)
- end
- else
- self:EndAnimations()
- self.AnimationController = 0
- end
- end
- function PANEL1:OnStateChanged()
- end
- function PANEL1:Toggle()
- self:SetState(not self.State)
- self:OnStateChanged(self.State)
- end
- vgui.Register("XeninUI.CheckboxV2", PANEL1, "DButton")
- local stopSpectating, startFreeRoam
- local isSpectating = false
- local specEnt
- local thirdperson = true
- local isRoaming = false
- local roamPos -- the position when roaming free
- local roamVelocity = Vector(0)
- local thirdPersonDistance = 100
- hook.Add("Initialize", "FSpectate", function()
- surface.CreateFont("UiBold", {
- size = 16,
- weight = 800,
- antialias = true,
- shadow = false,
- font = "Default"
- })
- if not FAdmin then return end
- FAdmin.StartHooks["zzSpectate"] = function()
- FAdmin.Commands.AddCommand("Spectate", nil, "<Player>")
- -- Right click option
- FAdmin.ScoreBoard.Main.AddPlayerRightClick("Spectate", function(ply)
- if not IsValid(ply) then return end
- RunConsoleCommand("FSpectate", ply:UserID())
- end)
- local canSpectate = false
- CAMI.PlayerHasAccess(LocalPlayer(), "FSpectate", function(b, _)
- canSpectate = true
- end)
- -- Spectate option in player menu
- FAdmin.ScoreBoard.Player:AddActionButton("Spectate", "fadmin/icons/spectate", Color(0, 200, 0, 255), function(ply) return canSpectate and ply ~= LocalPlayer() end, function(ply)
- if not IsValid(ply) then return end
- RunConsoleCommand("FSpectate", ply:UserID())
- end)
- end
- end)
- local function getThirdPersonPos(ent)
- local aimvector = LocalPlayer():GetAimVector()
- local startPos = ent:IsPlayer() and ent:GetShootPos() or ent:LocalToWorld(ent:OBBCenter())
- local endpos = startPos - aimvector * thirdPersonDistance
- local tracer = {
- start = startPos,
- endpos = endpos,
- filter = specEnt
- }
- local trace = util.TraceLine(tracer)
- return trace.HitPos + trace.HitNormal * 10
- end
- local view = {}
- local function getCalcView()
- if not isRoaming then
- if thirdperson then
- view.origin = getThirdPersonPos(specEnt)
- view.angles = LocalPlayer():EyeAngles()
- else
- view.origin = specEnt:IsPlayer() and specEnt:GetShootPos() or specEnt:LocalToWorld(specEnt:OBBCenter())
- view.angles = specEnt:IsPlayer() and specEnt:EyeAngles() or specEnt:GetAngles()
- end
- roamPos = view.origin
- view.drawviewer = false
- return view
- end
- view.origin = roamPos
- view.angles = LocalPlayer():EyeAngles()
- view.drawviewer = true
- return view
- end
- local function specCalcView(ply, origin, angles, fov)
- if not IsValid(specEnt) and not isRoaming then
- startFreeRoam()
- return
- end
- view = getCalcView()
- if IsValid(specEnt) then
- specEnt:SetNoDraw(not thirdperson)
- end
- return view
- end
- --[[---------------------------------------------------------------------------
- Find the right player to spectate
- ---------------------------------------------------------------------------]]
- local function findNearestObject()
- local aimvec = LocalPlayer():GetAimVector()
- local fromPos = isRoaming and roamPos or specEnt:EyePos()
- local lookingAt = util.QuickTrace(fromPos, aimvec * 5000, LocalPlayer())
- if IsValid(lookingAt.Entity) then return lookingAt.Entity end
- local foundPly, foundDot = nil, 0
- for _, ply in pairs(player.GetAll()) do
- if ply == LocalPlayer() then continue end
- local pos = ply:GetShootPos()
- local dot = (pos - fromPos):GetNormalized():Dot(aimvec)
- -- Discard players you're not looking at
- if dot < 0.97 then continue end
- -- not a better alternative
- if dot < foundDot then continue end
- local trace = util.QuickTrace(fromPos, pos - fromPos, ply)
- if trace.Hit then continue end
- foundPly, foundDot = ply, dot
- end
- return foundPly
- end
- --[[---------------------------------------------------------------------------
- Spectate the person you're looking at while you're roaming
- ---------------------------------------------------------------------------]]
- local function spectateLookingAt()
- local obj = findNearestObject()
- if not IsValid(obj) then return end
- isRoaming = false
- specEnt = obj
- net.Start("FSpectateTarget")
- net.WriteEntity(obj)
- net.SendToServer()
- end
- --[[---------------------------------------------------------------------------
- specBinds
- Change binds to perform spectate specific tasks
- ---------------------------------------------------------------------------]]
- -- Manual keysDown table, so I can return true in plyBindPress and still detect key presses
- local keysDown = {}
- local function specBinds(ply, bind, pressed)
- local key = input.LookupBinding(bind)
- if bind == "+jump" then
- stopSpectating()
- return true
- elseif bind == "+reload" and pressed then
- local pos = getCalcView().origin - Vector(0, 0, 64)
- RunConsoleCommand("FTPToPos", string.format("%d, %d, %d", pos.x, pos.y, pos.z), string.format("%d, %d, %d", roamVelocity.x, roamVelocity.y, roamVelocity.z))
- stopSpectating()
- elseif bind == "+attack" and pressed then
- if not isRoaming then
- startFreeRoam()
- else
- spectateLookingAt()
- end
- return true
- elseif bind == "+attack2" and pressed then
- if isRoaming then
- roamPos = roamPos + LocalPlayer():GetAimVector() * 500
- return true
- end
- thirdperson = not thirdperson
- return true
- elseif isRoaming and not LocalPlayer():KeyDown(IN_USE) then
- local keybind = string.lower(string.match(bind, "+([a-z A-Z 0-9]+)") or "")
- if not keybind or keybind == "use" or keybind == "showscores" or string.find(bind, "messagemode") then return end
- keysDown[keybind:upper()] = pressed
- return true
- elseif not isRoaming and thirdperson and (key == "MWHEELDOWN" or key == "MWHEELUP") then
- thirdPersonDistance = thirdPersonDistance + 10 * (key == "MWHEELDOWN" and 1 or -1)
- end
- -- Do not return otherwise, spectating admins should be able to move to avoid getting detected
- end
- --[[---------------------------------------------------------------------------
- Scoreboardshow
- Set to main view when roaming, open on a player when spectating
- ---------------------------------------------------------------------------]]
- local function fadminmenushow()
- if isRoaming then
- FAdmin.ScoreBoard.ChangeView("Main")
- elseif IsValid(specEnt) and specEnt:IsPlayer() then
- FAdmin.ScoreBoard.ChangeView("Main")
- FAdmin.ScoreBoard.ChangeView("Player", specEnt)
- end
- end
- --[[---------------------------------------------------------------------------
- RenderScreenspaceEffects
- Draws the lines from players' eyes to where they are looking
- ---------------------------------------------------------------------------]]
- local LineMat = Material("cable/new_cable_lit")
- local linesToDraw = {}
- local function lookingLines()
- if not linesToDraw[0] then return end
- render.SetMaterial(LineMat)
- cam.Start3D(view.origin, view.angles)
- for i = 0, #linesToDraw, 3 do
- render.DrawBeam(linesToDraw[i], linesToDraw[i + 1], 4, 0.01, 10, linesToDraw[i + 2])
- end
- cam.End3D()
- end
- local function gunpos(ply)
- local wep = ply:GetActiveWeapon()
- if not IsValid(wep) then return ply:EyePos() end
- local att = wep:GetAttachment(1)
- if not att then return ply:EyePos() end
- return att.Pos
- end
- local function specThink()
- local ply = LocalPlayer()
- -- Update linesToDraw
- local pls = player.GetAll()
- local lastPly = 0
- local skip = 0
- for i = 0, #pls - 1 do
- local p = pls[i + 1]
- if not isRoaming and p == specEnt and not thirdperson then
- skip = skip + 3
- continue
- end
- local tr = p:GetEyeTrace()
- local sp = gunpos(p)
- local pos = i * 3 - skip
- linesToDraw[pos] = tr.HitPos
- linesToDraw[pos + 1] = sp
- linesToDraw[pos + 2] = team.GetColor(p:Team())
- lastPly = i
- end
- -- Remove entries from linesToDraw that don't match with a player anymore
- for i = #linesToDraw, lastPly * 3 + 3, -1 do
- linesToDraw[i] = nil
- end
- if not isRoaming or keysDown["USE"] then return end
- local roamSpeed = 1000
- local aimVec = ply:GetAimVector()
- local direction
- local frametime = RealFrameTime()
- if keysDown["FORWARD"] then
- direction = aimVec
- elseif keysDown["BACK"] then
- direction = -aimVec
- end
- if keysDown["MOVELEFT"] then
- local right = aimVec:Angle():Right()
- direction = direction and (direction - right):GetNormalized() or -right
- elseif keysDown["MOVERIGHT"] then
- local right = aimVec:Angle():Right()
- direction = direction and (direction + right):GetNormalized() or right
- end
- if keysDown["SPEED"] then
- roamSpeed = 2500
- elseif keysDown["WALK"] or keysDown["DUCK"] then
- roamSpeed = 300
- end
- roamVelocity = (direction or Vector(0, 0, 0)) * roamSpeed
- roamPos = roamPos + roamVelocity * frametime
- end
- --[[---------------------------------------------------------------------------
- Draw help on the screen
- ---------------------------------------------------------------------------]]
- local uiForeground, uiBackground = Color(240, 240, 255, 255), Color(20, 20, 20, 120)
- local red = Color(255, 0, 0, 255)
- local function drawHelp()
- local scrHalfH = math.floor(ScrH() / 2)
- draw.WordBox(2, 10, scrHalfH, "Left click: (Un)select player to spectate", "UiBold", uiBackground, uiForeground)
- draw.WordBox(2, 10, scrHalfH + 20, isRoaming and "Right click: quickly move forwards" or "Right click: toggle thirdperson", "UiBold", uiBackground, uiForeground)
- draw.WordBox(2, 10, scrHalfH + 40, "Jump: Stop spectating", "UiBold", uiBackground, uiForeground)
- draw.WordBox(2, 10, scrHalfH + 60, "Reload: Stop spectating and teleport", "UiBold", uiBackground, uiForeground)
- if FAdmin then
- draw.WordBox(2, 10, scrHalfH + 80, "Opening FAdmin's menu while spectating a player", "UiBold", uiBackground, uiForeground)
- draw.WordBox(2, 10, scrHalfH + 100, "\twill open their page!", "UiBold", uiBackground, uiForeground)
- end
- local target = findNearestObject()
- local pls = player.GetAll()
- for i = 1, #pls do
- local ply = pls[i]
- if not isRoaming and ply == specEnt then continue end
- local pos = ply:GetShootPos():ToScreen()
- if not pos.visible then continue end
- local x, y = pos.x, pos.y
- draw.WordBox(2, x, y - alignment, ply:Nick(), "UiBold", uiBackground, uiForeground)
- if ply:Armor() == 0 then
- draw.WordBox(2, x, y - (alignment - 20), "Health: " .. ply:Health(), "UiBold", uiBackground, uiForeground)
- else
- draw.WordBox(2, x, y - (alignment - 20), "Health: " .. ply:Health() .. " / Armor: " .. ply:Armor(), "UiBold", uiBackground, uiForeground)
- end
- if ply:GetActiveWeapon():IsValid() then
- draw.WordBox(2, x, y - (alignment - 40), ply:GetActiveWeapon():GetPrintName(), "UiBold", uiBackground, uiForeground)
- draw.WordBox(2, x, y - (alignment - 60), ply:GetUserGroup(), "UiBold", uiBackground, uiForeground)
- draw.RoundedBox(2, x, y - (alignment - 80), 12, 12, team.GetColor(ply:Team()))
- else
- draw.WordBox(2, x, y - (alignment - 40), ply:GetUserGroup(), "UiBold", uiBackground, uiForeground)
- draw.RoundedBox(2, x, y - (alignment - 60), 12, 12, team.GetColor(ply:Team()))
- end
- end
- if not isRoaming then return end
- if not IsValid(target) then return end
- local center = target:LocalToWorld(target:OBBCenter())
- local eyeAng = EyeAngles()
- local rightUp = eyeAng:Right() * 16 + eyeAng:Up() * 36
- local topRight = (center + rightUp):ToScreen()
- local bottomLeft = (center - rightUp):ToScreen()
- draw.RoundedBox(12, bottomLeft.x, bottomLeft.y, math.max(20, topRight.x - bottomLeft.x), topRight.y - bottomLeft.y, red)
- draw.WordBox(2, bottomLeft.x, bottomLeft.y + 12, "Left click to spectate!", "UiBold", uiBackground, uiForeground)
- end
- --[[---------------------------------------------------------------------------
- Start roaming free, rather than spectating a given player
- ---------------------------------------------------------------------------]]
- startFreeRoam = function()
- if IsValid(specEnt) and specEnt:IsPlayer() then
- roamPos = thirdperson and getThirdPersonPos(specEnt) or specEnt:GetShootPos()
- specEnt:SetNoDraw(false)
- else
- roamPos = isSpectating and roamPos or LocalPlayer():GetShootPos()
- end
- specEnt = nil
- isRoaming = true
- keysDown = {}
- end
- --[[---------------------------------------------------------------------------
- specEnt
- Spectate a player
- ---------------------------------------------------------------------------]]
- local function startSpectate(um)
- isRoaming = net.ReadBool()
- specEnt = net.ReadEntity()
- specEnt = IsValid(specEnt) and specEnt or nil
- if isRoaming then
- startFreeRoam()
- end
- isSpectating = true
- keysDown = {}
- hook.Add("CalcView", "FSpectate", specCalcView)
- hook.Add("PlayerBindPress", "FSpectate", specBinds)
- hook.Add("ShouldDrawLocalPlayer", "FSpectate", function() return isRoaming or thirdperson end)
- hook.Add("Think", "FSpectate", specThink)
- hook.Add("HUDPaint", "FSpectate", drawHelp)
- hook.Add("FAdmin_ShowFAdminMenu", "FSpectate", fadminmenushow)
- hook.Add("RenderScreenspaceEffects", "FSpectate", lookingLines)
- timer.Create("FSpectatePosUpdate", 0.5, 0, function()
- if not isRoaming then return end
- RunConsoleCommand("_FSpectatePosUpdate", roamPos.x, roamPos.y, roamPos.z)
- end)
- end
- net.Receive("FSpectate", startSpectate)
- --[[---------------------------------------------------------------------------
- stopSpectating
- Stop spectating a player
- ---------------------------------------------------------------------------]]
- stopSpectating = function()
- hook.Remove("CalcView", "FSpectate")
- hook.Remove("PlayerBindPress", "FSpectate")
- hook.Remove("ShouldDrawLocalPlayer", "FSpectate")
- hook.Remove("Think", "FSpectate")
- hook.Remove("HUDPaint", "FSpectate")
- hook.Remove("FAdmin_ShowFAdminMenu", "FSpectate")
- hook.Remove("RenderScreenspaceEffects", "FSpectate")
- timer.Remove("FSpectatePosUpdate")
- if IsValid(specEnt) then
- specEnt:SetNoDraw(false)
- end
- RunConsoleCommand("FSpectate_StopSpectating")
- isSpectating = false
- end
- hook.Add("PlayerButtonDown", "CopySteamidToClipboard", function(ply, button)
- if button == KEY_E then
- if not IsFirstTimePredicted() then return end
- PlyTraceEye = ply:GetEyeTrace().Entity
- if PlyTraceEye:IsPlayer() then
- SetClipboardText(PlyTraceEye:SteamID())
- chat.AddText(Color(255, 0, 0), "SteamID de : ", Color(255, 255, 255), PlyTraceEye:Nick(), Color(255, 0, 0), " copié !")
- end
- end
- if button == KEY_A then
- if not IsFirstTimePredicted() then return end
- --HSVToColor( ( CurTime() * 100 ) % 360, 1, 1 )
- --Color(math.random(1, 255), math.random(1, 255), math.random(1, 255))
- for k, v in ipairs(player.GetAll()) do
- if v:IsAdmin() or v:IsSuperAdmin() then
- chat.AddText(HSVToColor((CurTime() * 100) % 360, 1, 1), "[" .. v:GetUserGroup() .. "] " .. v:Nick() .. " est un staff")
- end
- end
- end
- end)
- function BasicAim()
- local pls = player.GetAll()
- alignment = 66
- for i = 1, #pls do
- local ply = pls[i]
- if not isRoaming and ply == specEnt then continue end
- local pos = ply:GetShootPos():ToScreen()
- if not pos.visible then continue end
- local x, y = pos.x, pos.y
- if isSpectating then return end
- draw.WordBox(2, x, y - alignment, ply:Nick(), "UiBold", uiBackground, uiForeground)
- if ply:Armor() == 0 then
- draw.WordBox(2, x, y - (alignment - 20), "Health: " .. ply:Health(), "UiBold", uiBackground, uiForeground)
- else
- draw.WordBox(2, x, y - (alignment - 20), "Health: " .. ply:Health() .. " / Armor: " .. ply:Armor(), "UiBold", uiBackground, uiForeground)
- end
- if ply:GetActiveWeapon():IsValid() then
- draw.WordBox(2, x, y - (alignment - 40), ply:GetActiveWeapon():GetPrintName(), "UiBold", uiBackground, uiForeground)
- draw.WordBox(2, x, y - (alignment - 60), ply:GetUserGroup(), "UiBold", uiBackground, uiForeground)
- draw.RoundedBox(2, x, y - (alignment - 80), 12, 12, team.GetColor(ply:Team()))
- else
- draw.WordBox(2, x, y - (alignment - 40), ply:GetUserGroup(), "UiBold", uiBackground, uiForeground)
- draw.RoundedBox(2, x, y - (alignment - 60), 12, 12, team.GetColor(ply:Team()))
- end
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement