Initial commit
This commit is contained in:
180
addons/3d2d_textscreens/lua/autorun/textscreens_util.lua
Normal file
180
addons/3d2d_textscreens/lua/autorun/textscreens_util.lua
Normal file
@@ -0,0 +1,180 @@
|
||||
local function checkAdmin(ply)
|
||||
-- The server console always has access. `ply` is NULL in this case
|
||||
local isConsole = ply == nil or ply == NULL
|
||||
if isConsole then
|
||||
return true
|
||||
end
|
||||
local canAdmin = hook.Run("TextscreensCanAdmin", ply) -- run custom hook function to check admin
|
||||
if canAdmin == nil then -- if hook hasn't returned anything, default to super admin check
|
||||
canAdmin = ply:IsSuperAdmin()
|
||||
end
|
||||
return canAdmin
|
||||
end
|
||||
|
||||
-- allow servers to disable rainbow effect for everyone
|
||||
CreateConVar("ss_enable_rainbow", 1, {FCVAR_NOTIFY, FCVAR_REPLICATED}, "Determines whether rainbow textscreens will render for all clients. When disabled, rainbow screens will render as solid white.", 0, 1)
|
||||
|
||||
-- allow servers to restrict the number of characters per line for everyone
|
||||
CreateConVar("ss_max_characters", 0, {FCVAR_NOTIFY, FCVAR_REPLICATED}, "Determines the maximum number of characters per line for all clients. When set to 0, the maximum number of characters is infinite.", 0)
|
||||
|
||||
if SERVER then
|
||||
AddCSLuaFile()
|
||||
AddCSLuaFile("textscreens_config.lua")
|
||||
include("textscreens_config.lua")
|
||||
CreateConVar("sbox_maxtextscreens", "1", {FCVAR_NOTIFY, FCVAR_REPLICATED}, "Determines the maximum number of textscreens users can spawn.")
|
||||
|
||||
--local rainbow_enabled = cvars.Number('ss_enable_rainbow', 1)
|
||||
|
||||
local function StringRandom(int)
|
||||
math.randomseed(os.time())
|
||||
local s = ""
|
||||
|
||||
for i = 1, int do
|
||||
s = s .. string.char(math.random(65, 90))
|
||||
end
|
||||
|
||||
return s
|
||||
end
|
||||
|
||||
local textscreens = {}
|
||||
|
||||
local function SpawnPermaTextscreens()
|
||||
print("[3D2D Textscreens] Spawning textscreens...")
|
||||
textscreens = file.Read("sammyservers_textscreens.txt", "DATA")
|
||||
if not textscreens or textscreens == "" then
|
||||
textscreens = {}
|
||||
print("[3D2D Textscreens] Spawned 0 textscreens for map " .. game.GetMap())
|
||||
return
|
||||
end
|
||||
textscreens = util.JSONToTable(textscreens)
|
||||
|
||||
local existingTextscreens = {}
|
||||
for k,v in pairs(ents.FindByClass("sammyservers_textscreen")) do
|
||||
if not v.uniqueName then continue end
|
||||
existingTextscreens[v.uniqueName] = true
|
||||
end
|
||||
|
||||
local count = 0
|
||||
for k, v in pairs(textscreens) do
|
||||
if v.MapName ~= game.GetMap() then continue end
|
||||
if existingTextscreens[v.uniqueName] then continue end
|
||||
|
||||
local textScreen = ents.Create("sammyservers_textscreen")
|
||||
textScreen:SetPos(Vector(v.posx, v.posy, v.posz))
|
||||
textScreen:SetAngles(Angle(v.angp, v.angy, v.angr))
|
||||
textScreen.uniqueName = v.uniqueName
|
||||
textScreen:Spawn()
|
||||
textScreen:Activate()
|
||||
textScreen:SetMoveType(MOVETYPE_NONE)
|
||||
|
||||
for lineNum, lineData in pairs(v.lines or {}) do
|
||||
textScreen:SetLine(lineNum, lineData.text, Color(lineData.color.r, lineData.color.g, lineData.color.b, lineData.color.a), lineData.size, lineData.font, lineData.rainbow or 0)
|
||||
end
|
||||
|
||||
textScreen:SetIsPersisted(true)
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
print("[3D2D Textscreens] Spawned " .. count .. " textscreens for map " .. game.GetMap())
|
||||
end
|
||||
|
||||
hook.Add("InitPostEntity", "loadTextScreens", function()
|
||||
timer.Simple(10, SpawnPermaTextscreens)
|
||||
end)
|
||||
|
||||
hook.Add("PostCleanupMap", "loadTextScreens", SpawnPermaTextscreens)
|
||||
|
||||
-- If a player, use ChatPrint method, else print directly to server console
|
||||
local function printMessage(ply, msg)
|
||||
local isConsole = ply == nil or ply == NULL
|
||||
if isConsole then
|
||||
print(msg)
|
||||
else
|
||||
ply:ChatPrint(msg)
|
||||
end
|
||||
end
|
||||
concommand.Add("SS_TextScreen", function(ply, cmd, args)
|
||||
if not checkAdmin(ply) or not args or not args[1] or not args[2] or not (args[1] == "delete" or args[1] == "add") then
|
||||
printMessage(ply, "not authorised, or bad arguments")
|
||||
return
|
||||
end
|
||||
local ent = Entity(args[2])
|
||||
if not IsValid(ent) or ent:GetClass() ~= "sammyservers_textscreen" then return false end
|
||||
|
||||
if args[1] == "add" then
|
||||
local pos = ent:GetPos()
|
||||
local ang = ent:GetAngles()
|
||||
local toAdd = {}
|
||||
toAdd.posx = pos.x
|
||||
toAdd.posy = pos.y
|
||||
toAdd.posz = pos.z
|
||||
toAdd.angp = ang.p
|
||||
toAdd.angy = ang.y
|
||||
toAdd.angr = ang.r
|
||||
-- So we can reference it easily later because EntIndexes are so unreliable
|
||||
toAdd.uniqueName = StringRandom(10)
|
||||
toAdd.MapName = game.GetMap()
|
||||
toAdd.lines = ent.lines
|
||||
table.insert(textscreens, toAdd)
|
||||
file.Write("sammyservers_textscreens.txt", util.TableToJSON(textscreens))
|
||||
ent:SetIsPersisted(true)
|
||||
|
||||
return printMessage(ply, "Textscreen made permanent and saved.")
|
||||
else
|
||||
for k, v in pairs(textscreens) do
|
||||
if v.uniqueName == ent.uniqueName then
|
||||
textscreens[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
ent:Remove()
|
||||
file.Write("sammyservers_textscreens.txt", util.TableToJSON(textscreens))
|
||||
|
||||
return printMessage(ply, "Textscreen removed and is no longer permanent.")
|
||||
end
|
||||
end)
|
||||
|
||||
-- Add to pocket blacklist for DarkRP
|
||||
-- Not using gamemode == "darkrp" because there are lots of flavours of darkrp
|
||||
hook.Add("loadCustomDarkRPItems", "sammyservers_pocket_blacklist", function()
|
||||
GAMEMODE.Config.PocketBlacklist["sammyservers_textscreen"] = true
|
||||
end)
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
include("textscreens_config.lua")
|
||||
|
||||
properties.Add("addPermaScreen", {
|
||||
MenuLabel = "Make perma textscreen",
|
||||
Order = 2001,
|
||||
MenuIcon = "icon16/transmit.png",
|
||||
Filter = function(self, ent, ply)
|
||||
if not IsValid(ent) or ent:GetClass() ~= "sammyservers_textscreen" then return false end
|
||||
if ent:GetIsPersisted() then return false end
|
||||
|
||||
return checkAdmin(ply)
|
||||
end,
|
||||
Action = function(self, ent)
|
||||
if not IsValid(ent) then return false end
|
||||
|
||||
return RunConsoleCommand("SS_TextScreen", "add", ent:EntIndex())
|
||||
end
|
||||
})
|
||||
|
||||
properties.Add("removePermaScreen", {
|
||||
MenuLabel = "Remove perma textscreen",
|
||||
Order = 2002,
|
||||
MenuIcon = "icon16/transmit_delete.png",
|
||||
Filter = function(self, ent, ply)
|
||||
if not IsValid(ent) or ent:GetClass() ~= "sammyservers_textscreen" then return false end
|
||||
if not ent:GetIsPersisted() then return false end
|
||||
|
||||
return checkAdmin(ply)
|
||||
end,
|
||||
Action = function(self, ent)
|
||||
if not IsValid(ent) then return end
|
||||
|
||||
return RunConsoleCommand("SS_TextScreen", "delete", ent:EntIndex())
|
||||
end
|
||||
})
|
||||
end
|
||||
@@ -0,0 +1,228 @@
|
||||
include("shared.lua")
|
||||
|
||||
local render_convar_range = CreateClientConVar("ss_render_range", 1500, true, false, "Determines the render range for Textscreens. Default 1500")
|
||||
local render_rainbow = CreateClientConVar("ss_render_rainbow", 1, true, false, "Determines if rainbow screens are rendered. If disabled (0), will render as solid white. Default enabled (1)", 0, 1)
|
||||
local render_range = render_convar_range:GetInt() * render_convar_range:GetInt() --We multiply this is that we can use DistToSqr instead of Distance so we don't need to workout the square root all the time
|
||||
local rainbow_enabled = cvars.Number("ss_enable_rainbow", 1)
|
||||
local textscreenFonts = textscreenFonts
|
||||
local screenInfo = {}
|
||||
local shouldDrawBoth = false
|
||||
|
||||
-- Numbers used in conjunction with text width to work out the render bounds
|
||||
local widthBoundsDivider = 7.9
|
||||
local heightBoundsDivider = 12.4
|
||||
|
||||
-- ENUM type things for faster table indexing
|
||||
local FONT = 1
|
||||
local TEXT = 2
|
||||
local POSX = 3
|
||||
local POSY = 4
|
||||
local COL = 5
|
||||
local LEN = 6
|
||||
local SIZE = 7
|
||||
local CAMSIZE = 8
|
||||
local RAINBOW = 9
|
||||
|
||||
-- Make ply:ShouldDrawLocalPlayer() never get called more than once a frame
|
||||
hook.Add("Think", "ss_should_draw_both_sides", function()
|
||||
shouldDrawBoth = LocalPlayer():ShouldDrawLocalPlayer()
|
||||
end)
|
||||
|
||||
local function ValidFont(f)
|
||||
if textscreenFonts[f] ~= nil then
|
||||
return textscreenFonts[f]
|
||||
elseif table.HasValue(textscreenFonts, f) then
|
||||
return f
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
cvars.AddChangeCallback("ss_render_range", function(convar_name, value_old, value_new)
|
||||
render_range = tonumber(value_new) * tonumber(value_new)
|
||||
end, "3D2DScreens")
|
||||
|
||||
cvars.AddChangeCallback("ss_render_rainbow", function(convar_name, value_old, value_new)
|
||||
render_rainbow = tonumber(value_new)
|
||||
end, "3D2DScreens")
|
||||
|
||||
-- TODO: https://github.com/Facepunch/garrysmod-issues/issues/3740
|
||||
-- cvars.AddChangeCallback("ss_enable_rainbow", function(convar_name, value_old, value_new)
|
||||
-- print('ss_enable_rainbow changed: '.. value_new)
|
||||
-- rainbow_enabled = tonumber(value_new)
|
||||
-- end, "3D2DScreens")
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetMaterial("models/effects/vol_light001")
|
||||
self:SetRenderMode(RENDERMODE_NONE)
|
||||
net.Start("textscreens_download")
|
||||
net.WriteEntity(self)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
local product
|
||||
local function IsInFront(entPos, plyShootPos, direction)
|
||||
product = (entPos.x - plyShootPos.x) * direction.x +
|
||||
(entPos.y - plyShootPos.y) * direction.y +
|
||||
(entPos.z - plyShootPos.z) * direction.z
|
||||
return product < 0
|
||||
end
|
||||
|
||||
|
||||
-- Draws the 3D2D text with the given positions, angles and data(text/font/col)
|
||||
local function Draw3D2D(ang, pos, camangle, data)
|
||||
|
||||
for i = 1, data[LEN] do
|
||||
if not data[i] or not data[i][TEXT] then continue end
|
||||
|
||||
cam.Start3D2D(pos, camangle, data[i][CAMSIZE] )
|
||||
render.PushFilterMin(TEXFILTER.ANISOTROPIC)
|
||||
-- Font
|
||||
surface.SetFont(data[i][FONT])
|
||||
-- Position
|
||||
surface.SetTextPos(data[i][POSX], data[i][POSY])
|
||||
-- Rainbow
|
||||
if data[i][RAINBOW] ~= nil and data[i][RAINBOW] ~= 0 then
|
||||
local j = 0
|
||||
for _, code in utf8.codes(data[i][TEXT]) do
|
||||
j = j + 1
|
||||
--Color
|
||||
if rainbow_enabled == 1 and render_rainbow ~= 0 then
|
||||
surface.SetTextColor(HSVToColor((CurTime() * 60 + (j * 5)) % 360, 1, 1))
|
||||
else
|
||||
-- Render as solid white if ss_render_rainbow is disabled or server disabled via ss_enable_rainbow
|
||||
surface.SetTextColor(255, 255, 255)
|
||||
end
|
||||
--Text
|
||||
surface.DrawText(utf8.char(code))
|
||||
end
|
||||
else
|
||||
--Color
|
||||
surface.SetTextColor(data[i][COL])
|
||||
--Text
|
||||
surface.DrawText(data[i][TEXT])
|
||||
end
|
||||
|
||||
render.PopFilterMin()
|
||||
cam.End3D2D()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local plyShootPos, ang, pos, camangle, showFront, data -- Less variables being created each frame
|
||||
function ENT:DrawTranslucent()
|
||||
-- Cache the shoot pos for this frame
|
||||
plyShootPos = LocalPlayer():GetShootPos()
|
||||
|
||||
if screenInfo[self] ~= nil and self:GetPos():DistToSqr(plyShootPos) < render_range then
|
||||
ang = self:GetAngles()
|
||||
pos = self:GetPos() + ang:Up()
|
||||
camangle = Angle(ang.p, ang.y, ang.r)
|
||||
data = screenInfo[self]
|
||||
|
||||
-- Should we draw both screens? (Third person/calview drawing fix)
|
||||
if shouldDrawBoth then
|
||||
Draw3D2D(ang, pos, camangle, data)
|
||||
camangle:RotateAroundAxis(camangle:Right(), 180)
|
||||
Draw3D2D(ang, pos, camangle, data)
|
||||
else
|
||||
-- Is the front of the screen facing us or the back?
|
||||
showFront = IsInFront(pos, plyShootPos, ang:Up())
|
||||
|
||||
-- Draw the front of the screen
|
||||
if showFront then
|
||||
Draw3D2D(ang, pos, camangle, data)
|
||||
else
|
||||
-- Draw the back of the screen
|
||||
camangle:RotateAroundAxis(camangle:Right(), 180)
|
||||
Draw3D2D(ang, pos, camangle, data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function AddDrawingInfo(ent, rawData)
|
||||
local drawData = {}
|
||||
local textSize = {}
|
||||
|
||||
local totalHeight = 0
|
||||
local maxWidth = 0
|
||||
local currentHeight = 0
|
||||
|
||||
for i = 1, #rawData do
|
||||
-- Setup tables
|
||||
if not rawData[i] or not rawData[i].text then continue end
|
||||
drawData[i] = {}
|
||||
textSize[i] = {}
|
||||
-- Text
|
||||
drawData[i][TEXT] = rawData[i].text
|
||||
-- Font
|
||||
drawData[i][FONT] = (ValidFont(rawData[i].font) or textscreenFonts[1])
|
||||
-- Text size
|
||||
surface.SetFont(drawData[i][FONT])
|
||||
textSize[i][1], textSize[i][2] = surface.GetTextSize(drawData[i][TEXT])
|
||||
textSize[i][2] = rawData[i].size
|
||||
-- Workout max width for render bounds
|
||||
maxWidth = maxWidth > textSize[i][1] and maxWidth or textSize[i][1]
|
||||
-- Position
|
||||
totalHeight = totalHeight + textSize[i][2]
|
||||
-- Colour
|
||||
drawData[i][COL] = Color(rawData[i].color.r, rawData[i].color.g, rawData[i].color.b, 255)
|
||||
-- Size
|
||||
drawData[i][SIZE] = rawData[i]["size"]
|
||||
-- Remove text if text is empty so we don't waste performance
|
||||
if string.len(drawData[i][TEXT]) == 0 or string.len(string.Replace( drawData[i][TEXT], " ", "" )) == 0 then drawData[i][TEXT] = nil end
|
||||
--Rainbow
|
||||
drawData[i][RAINBOW] = rawData[i]["rainbow"] or 0
|
||||
end
|
||||
|
||||
-- Sort out heights
|
||||
for i = 1, #rawData do
|
||||
if not rawData[i] then continue end
|
||||
-- The x position at which to draw the text relative to the text screen entity
|
||||
drawData[i][POSX] = math.ceil(-textSize[i][1] / 2)
|
||||
-- The y position at which to draw the text relative to the text screen entity
|
||||
drawData[i][POSY] = math.ceil(-(totalHeight / 2) + currentHeight)
|
||||
-- Calculate the cam.Start3D2D size based on the size of the font
|
||||
drawData[i][CAMSIZE] = (0.25 * drawData[i][SIZE]) / 100
|
||||
-- Use the CAMSIZE to "scale" the POSY
|
||||
drawData[i][POSY] = (0.25 / drawData[i][CAMSIZE] * drawData[i][POSY])
|
||||
-- Highest line to lowest, so that everything is central
|
||||
currentHeight = currentHeight + textSize[i][2]
|
||||
end
|
||||
|
||||
-- Cache the number of lines/length
|
||||
drawData[LEN] = #drawData
|
||||
-- Add the new data to our text screen list
|
||||
screenInfo[ent] = drawData
|
||||
|
||||
-- Calculate the render bounds
|
||||
local x = maxWidth / widthBoundsDivider
|
||||
local y = currentHeight / heightBoundsDivider + 13 -- Text is above the centre
|
||||
|
||||
-- Setup the render bounds
|
||||
ent:SetRenderBounds(Vector(-x, -y, -1.75), Vector(x, y, 1.75))
|
||||
end
|
||||
|
||||
net.Receive("textscreens_update", function(len)
|
||||
local ent = net.ReadEntity()
|
||||
|
||||
if IsValid(ent) and ent:GetClass() == "sammyservers_textscreen" then
|
||||
|
||||
local t = net.ReadTable()
|
||||
|
||||
ent.lines = t -- Incase an addon or something wants to read the information.
|
||||
|
||||
AddDrawingInfo(ent, t)
|
||||
end
|
||||
end)
|
||||
|
||||
-- Auto refresh
|
||||
if IsValid(LocalPlayer()) then
|
||||
local screens = ents.FindByClass("sammyservers_textscreen")
|
||||
for k, v in ipairs(screens) do
|
||||
if screenInfo[v] == nil and v.lines ~= nil then
|
||||
AddDrawingInfo(v, v.lines)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,134 @@
|
||||
AddCSLuaFile("cl_init.lua")
|
||||
AddCSLuaFile("shared.lua")
|
||||
resource.AddWorkshop("109643223")
|
||||
|
||||
include("shared.lua")
|
||||
|
||||
local CurTime = CurTime
|
||||
local IsValid = IsValid
|
||||
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetRenderMode(RENDERMODE_TRANSALPHA)
|
||||
self:DrawShadow(false)
|
||||
self:SetModel("models/hunter/plates/plate1x1.mdl")
|
||||
self:SetMaterial("models/effects/vol_light001")
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
self:SetCollisionGroup(COLLISION_GROUP_WORLD)
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
local phys = self:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:EnableMotion(false)
|
||||
end
|
||||
self.heldby = 0
|
||||
end
|
||||
|
||||
function ENT:PhysicsUpdate(phys)
|
||||
if self.heldby <= 0 then
|
||||
phys:Sleep()
|
||||
end
|
||||
end
|
||||
|
||||
local function textScreenPickup(ply, ent)
|
||||
if IsValid(ent) and ent:GetClass() == "sammyservers_textscreen" then
|
||||
ent.heldby = ent.heldby + 1
|
||||
end
|
||||
end
|
||||
hook.Add("PhysgunPickup", "3D2DTextScreensPreventTravelPickup", textScreenPickup)
|
||||
|
||||
local function textScreenDrop(ply, ent)
|
||||
if IsValid(ent) and ent:GetClass() == "sammyservers_textscreen" then
|
||||
ent.heldby = ent.heldby - 1
|
||||
local phys = ent:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
ent:PhysicsUpdate(phys)
|
||||
end
|
||||
end
|
||||
end
|
||||
hook.Add("PhysgunDrop", "3D2DTextScreensPreventTravelDrop", textScreenDrop)
|
||||
|
||||
util.AddNetworkString("textscreens_update")
|
||||
util.AddNetworkString("textscreens_download")
|
||||
|
||||
function ENT:SetLine(line, text, color, size, font, rainbow)
|
||||
if not text then return end
|
||||
if string.sub(text, 1, 1) == "#" then
|
||||
text = string.sub(text, 2)
|
||||
end
|
||||
if string.len(text) > 180 then
|
||||
text = string.sub(text, 1, 180) .. "..."
|
||||
end
|
||||
|
||||
size = math.Clamp(size, 1, 100)
|
||||
|
||||
font = textscreenFonts[font] ~= nil and font or 1
|
||||
|
||||
rainbow = rainbow or 0
|
||||
|
||||
self.lines = self.lines or {}
|
||||
self.lines[tonumber(line)] = {
|
||||
["text"] = text,
|
||||
["color"] = color,
|
||||
["size"] = size,
|
||||
["font"] = font,
|
||||
["rainbow"] = rainbow
|
||||
}
|
||||
end
|
||||
|
||||
local function canSendUpdate(ply, ent)
|
||||
local updates = ply.TextScreenUpdates
|
||||
if not updates then
|
||||
updates = {}
|
||||
ply.TextScreenUpdates = updates
|
||||
end
|
||||
|
||||
local now = CurTime()
|
||||
local lastSent = updates[ent] or 0
|
||||
if lastSent > (now - 1) then
|
||||
return false
|
||||
end
|
||||
|
||||
updates[ent] = now
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
local plys = player.GetAll()
|
||||
local plyCount = #plys
|
||||
|
||||
for i = 1, plyCount do
|
||||
local updates = plys[i].TextScreenUpdates
|
||||
if updates then updates[self] = nil end
|
||||
end
|
||||
end
|
||||
|
||||
net.Receive("textscreens_download", function(len, ply)
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
local ent = net.ReadEntity()
|
||||
if not IsValid( ent ) then return end
|
||||
if ent:GetClass() ~= "sammyservers_textscreen" then return end
|
||||
|
||||
if not canSendUpdate(ply, ent) then return end
|
||||
|
||||
ent:SendLines(ply)
|
||||
end)
|
||||
|
||||
function ENT:SendLines(ply)
|
||||
if not self.lines then self.lines = {} end
|
||||
|
||||
net.Start("textscreens_update")
|
||||
net.WriteEntity(self)
|
||||
net.WriteTable(self.lines)
|
||||
|
||||
if ply then
|
||||
net.Send(ply)
|
||||
else
|
||||
net.Broadcast()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Broadcast()
|
||||
self:SendLines(nil)
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
ENT.Type = "anim"
|
||||
ENT.Base = "base_entity"
|
||||
ENT.PrintName = "SammyServers Textscreen"
|
||||
ENT.Author = "SammyServers"
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminSpawnable = false
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:NetworkVar("Bool", 0, "IsPersisted")
|
||||
end
|
||||
|
||||
local function textScreenCanTool(ply, trace, tool)
|
||||
-- only allow textscreen, remover, and permaprops tool
|
||||
if IsValid(trace.Entity) and trace.Entity:GetClass() == "sammyservers_textscreen" and tool ~= "textscreen" and tool ~= "remover" and tool ~= "permaprops" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
hook.Add("CanTool", "3D2DTextScreensPreventTools", textScreenCanTool)
|
||||
154
addons/3d2d_textscreens/lua/textscreens_config.lua
Normal file
154
addons/3d2d_textscreens/lua/textscreens_config.lua
Normal file
@@ -0,0 +1,154 @@
|
||||
textscreenFonts = {}
|
||||
|
||||
local function addFont(font, t)
|
||||
if CLIENT then
|
||||
t.size = 100
|
||||
surface.CreateFont(font, t)
|
||||
t.size = 50
|
||||
surface.CreateFont(font .. "_MENU", t)
|
||||
end
|
||||
|
||||
table.insert(textscreenFonts, font)
|
||||
end
|
||||
|
||||
--[[
|
||||
---------------------------------------------------------------------------
|
||||
Custom fonts - requires server restart to take affect -- "Screens_" will be removed from the font name in spawnmenu
|
||||
---------------------------------------------------------------------------
|
||||
--]]
|
||||
|
||||
-- Default textscreens font
|
||||
addFont("Coolvetica outlined", {
|
||||
font = "coolvetica",
|
||||
weight = 400,
|
||||
antialias = false,
|
||||
outline = true
|
||||
})
|
||||
|
||||
addFont("Coolvetica", {
|
||||
font = "coolvetica",
|
||||
weight = 400,
|
||||
antialias = false,
|
||||
outline = false
|
||||
})
|
||||
|
||||
-- Trebuchet
|
||||
addFont("Screens_Trebuchet outlined", {
|
||||
font = "Trebuchet MS",
|
||||
weight = 400,
|
||||
antialias = false,
|
||||
outline = true
|
||||
})
|
||||
|
||||
addFont("Screens_Trebuchet", {
|
||||
font = "Trebuchet MS",
|
||||
weight = 400,
|
||||
antialias = false,
|
||||
outline = false
|
||||
})
|
||||
|
||||
-- Arial
|
||||
addFont("Screens_Arial outlined", {
|
||||
font = "Arial",
|
||||
weight = 600,
|
||||
antialias = false,
|
||||
outline = true
|
||||
})
|
||||
|
||||
addFont("Screens_Arial", {
|
||||
font = "Arial",
|
||||
weight = 600,
|
||||
antialias = false,
|
||||
outline = false
|
||||
})
|
||||
|
||||
-- Roboto Bk
|
||||
addFont("Screens_Roboto outlined", {
|
||||
font = "Roboto Bk",
|
||||
weight = 400,
|
||||
antialias = false,
|
||||
outline = true
|
||||
})
|
||||
|
||||
addFont("Screens_Roboto", {
|
||||
font = "Roboto Bk",
|
||||
weight = 400,
|
||||
antialias = false,
|
||||
outline = false
|
||||
})
|
||||
|
||||
-- Helvetica
|
||||
addFont("Screens_Helvetica outlined", {
|
||||
font = "Helvetica",
|
||||
weight = 400,
|
||||
antialias = false,
|
||||
outline = true
|
||||
})
|
||||
|
||||
addFont("Screens_Helvetica", {
|
||||
font = "Helvetica",
|
||||
weight = 400,
|
||||
antialias = false,
|
||||
outline = false
|
||||
})
|
||||
|
||||
-- akbar
|
||||
addFont("Screens_Akbar outlined", {
|
||||
font = "akbar",
|
||||
weight = 400,
|
||||
antialias = false,
|
||||
outline = true
|
||||
})
|
||||
|
||||
addFont("Screens_Akbar", {
|
||||
font = "akbar",
|
||||
weight = 400,
|
||||
antialias = false,
|
||||
outline = false
|
||||
})
|
||||
|
||||
-- csd
|
||||
addFont("Screens_csd outlined", {
|
||||
font = "csd",
|
||||
weight = 400,
|
||||
antialias = false,
|
||||
outline = true
|
||||
})
|
||||
|
||||
addFont("Screens_csd", {
|
||||
font = "csd",
|
||||
weight = 400,
|
||||
antialias = false,
|
||||
outline = false
|
||||
})
|
||||
|
||||
if CLIENT then
|
||||
|
||||
local function addFonts(path)
|
||||
local files, folders = file.Find("resource/fonts/" .. path .. "*", "MOD")
|
||||
|
||||
for k, v in ipairs(files) do
|
||||
if string.GetExtensionFromFilename(v) == "ttf" then
|
||||
local font = string.StripExtension(v)
|
||||
if table.HasValue(textscreenFonts, "Screens_" .. font) then continue end
|
||||
print("-- " .. font .. "\n" .. [[
|
||||
addFont("Screens_ ]] .. font .. [[", {
|
||||
font = font,
|
||||
weight = 400,
|
||||
antialias = false,
|
||||
outline = true
|
||||
})
|
||||
]])
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in ipairs(folders) do
|
||||
addFonts(path .. v .. "/")
|
||||
end
|
||||
end
|
||||
|
||||
concommand.Add("get_fonts", function(ply)
|
||||
addFonts("")
|
||||
end)
|
||||
|
||||
end
|
||||
@@ -0,0 +1,413 @@
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#tool.textscreen.name"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
local textBox = {}
|
||||
local lineLabels = {}
|
||||
local labels = {}
|
||||
local sliders = {}
|
||||
local rainbowCheckboxes = {}
|
||||
local textscreenFonts = textscreenFonts
|
||||
local rainbow_enabled = cvars.Number("ss_enable_rainbow", 1)
|
||||
local max_characters = cvars.Number("ss_max_characters", 0)
|
||||
|
||||
for i = 1, 5 do
|
||||
TOOL.ClientConVar["text" .. i] = ""
|
||||
TOOL.ClientConVar["size" .. i] = 20
|
||||
TOOL.ClientConVar["r" .. i] = 255
|
||||
TOOL.ClientConVar["g" .. i] = 255
|
||||
TOOL.ClientConVar["b" .. i] = 255
|
||||
TOOL.ClientConVar["a" .. i] = 255
|
||||
TOOL.ClientConVar["font" .. i] = 1
|
||||
TOOL.ClientConVar["rainbow" .. i] = 0
|
||||
end
|
||||
|
||||
cleanup.Register("textscreens")
|
||||
|
||||
if (CLIENT) then
|
||||
TOOL.Information = {
|
||||
{ name = "left" },
|
||||
{ name = "right" },
|
||||
{ name = "reload" },
|
||||
}
|
||||
-- Add default english language strings here, in case no localisation exists
|
||||
language.Add("tool.textscreen.name", "3D2D Textscreen")
|
||||
language.Add("tool.textscreen.desc", "Create a textscreen with multiple lines, font colours and sizes.")
|
||||
language.Add("tool.textscreen.left", "Spawn a textscreen.") -- Does not work with capital T in tool. Same with right and reload.
|
||||
language.Add("tool.textscreen.right", "Update textscreen with settings.")
|
||||
language.Add("tool.textscreen.reload", "Copy textscreen.")
|
||||
language.Add("Undone.textscreens", "Undone textscreen")
|
||||
language.Add("Undone_textscreens", "Undone textscreen")
|
||||
language.Add("Cleanup.textscreens", "Textscreens")
|
||||
language.Add("Cleanup_textscreens", "Textscreens")
|
||||
language.Add("Cleaned.textscreens", "Cleaned up all textscreens")
|
||||
language.Add("Cleaned_textscreens", "Cleaned up all textscreens")
|
||||
language.Add("SBoxLimit.textscreens", "You've hit the textscreen limit!")
|
||||
language.Add("SBoxLimit_textscreens", "You've hit the textscreen limit!")
|
||||
end
|
||||
|
||||
function TOOL:LeftClick(tr)
|
||||
if (tr.Entity:GetClass() == "player") then return false end
|
||||
if (CLIENT) then return true end
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if hook.Run("PlayerSpawnTextscreen", ply, tr) == false then return false end
|
||||
|
||||
if not (self:GetWeapon():CheckLimit("textscreens")) then return false end
|
||||
-- ensure at least 1 line of the textscreen has text before creating entity
|
||||
local hasText = false
|
||||
for i = 1, 5 do
|
||||
local text = self:GetClientInfo("text" .. i) or ""
|
||||
if text ~= "" then
|
||||
hasText = true
|
||||
end
|
||||
end
|
||||
if not hasText then return false end
|
||||
local textScreen = ents.Create("sammyservers_textscreen")
|
||||
textScreen:SetPos(tr.HitPos)
|
||||
local angle = tr.HitNormal:Angle()
|
||||
angle:RotateAroundAxis(tr.HitNormal:Angle():Right(), -90)
|
||||
angle:RotateAroundAxis(tr.HitNormal:Angle():Forward(), 90)
|
||||
textScreen:SetAngles(angle)
|
||||
textScreen:Spawn()
|
||||
textScreen:Activate()
|
||||
|
||||
undo.Create("textscreens")
|
||||
undo.AddEntity(textScreen)
|
||||
undo.SetPlayer(ply)
|
||||
undo.Finish()
|
||||
ply:AddCount("textscreens", textScreen)
|
||||
ply:AddCleanup("textscreens", textScreen)
|
||||
|
||||
for i = 1, 5 do
|
||||
local txt = self:GetClientInfo("text" .. i) or ""
|
||||
textScreen:SetLine(
|
||||
i, -- Line
|
||||
max_characters ~= 0 and string.Left(txt, max_characters) or txt, -- text
|
||||
Color( -- Color
|
||||
tonumber(self:GetClientInfo("r" .. i)) or 255,
|
||||
tonumber(self:GetClientInfo("g" .. i)) or 255,
|
||||
tonumber(self:GetClientInfo("b" .. i)) or 255,
|
||||
tonumber(self:GetClientInfo("a" .. i)) or 255
|
||||
),
|
||||
tonumber(self:GetClientInfo("size" .. i)) or 20,
|
||||
-- font
|
||||
tonumber(self:GetClientInfo("font" .. i)) or 1,
|
||||
|
||||
rainbow_enabled == 1 and tonumber(self:GetClientInfo("rainbow" .. i)) or 0
|
||||
)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:RightClick(tr)
|
||||
if (tr.Entity:GetClass() == "player") then return false end
|
||||
if (CLIENT) then return true end
|
||||
local traceEnt = tr.Entity
|
||||
|
||||
if (IsValid(traceEnt) and traceEnt:GetClass() == "sammyservers_textscreen") then
|
||||
for i = 1, 5 do
|
||||
local txt = tostring(self:GetClientInfo("text" .. i))
|
||||
traceEnt:SetLine(
|
||||
i, -- Line
|
||||
max_characters ~= 0 and string.Left(txt, max_characters) or txt, -- text
|
||||
Color( -- Color
|
||||
tonumber(self:GetClientInfo("r" .. i)) or 255,
|
||||
tonumber(self:GetClientInfo("g" .. i)) or 255,
|
||||
tonumber(self:GetClientInfo("b" .. i)) or 255,
|
||||
tonumber(self:GetClientInfo("a" .. i)) or 255
|
||||
),
|
||||
tonumber(self:GetClientInfo("size" .. i)) or 20,
|
||||
-- font
|
||||
tonumber(self:GetClientInfo("font" .. i)) or 1,
|
||||
|
||||
rainbow_enabled and tonumber(self:GetClientInfo("rainbow" .. i)) or 0
|
||||
)
|
||||
end
|
||||
|
||||
traceEnt:Broadcast()
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL:Reload(tr)
|
||||
if (SERVER) then return true end
|
||||
local traceEnt = tr.Entity
|
||||
if (not isentity(traceEnt) or traceEnt:GetClass() ~= "sammyservers_textscreen") then return false end
|
||||
|
||||
for i = 1, 5 do
|
||||
local linedata = traceEnt.lines[i]
|
||||
RunConsoleCommand("textscreen_r" .. i, linedata.color.r)
|
||||
RunConsoleCommand("textscreen_g" .. i, linedata.color.g)
|
||||
RunConsoleCommand("textscreen_b" .. i, linedata.color.b)
|
||||
RunConsoleCommand("textscreen_a" .. i, linedata.color.a)
|
||||
RunConsoleCommand("textscreen_size" .. i, linedata.size)
|
||||
RunConsoleCommand("textscreen_text" .. i, linedata.text)
|
||||
RunConsoleCommand("textscreen_font" .. i, linedata.font)
|
||||
RunConsoleCommand("textscreen_rainbow" .. i, linedata.rainbow)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local conVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel(CPanel)
|
||||
local logo = vgui.Create("DImage", CPanel)
|
||||
logo:SetSize(267, 134)
|
||||
logo:SetImage("textscreens/logo.png")
|
||||
CPanel:AddItem(logo)
|
||||
|
||||
CPanel:AddControl("Header", {
|
||||
Text = "#tool.textscreen.name",
|
||||
Description = "#tool.textscreen.desc"
|
||||
})
|
||||
|
||||
local function TrimFontName(fontnum)
|
||||
return string.Left(textscreenFonts[fontnum], 8) == "Screens_" and string.TrimLeft(textscreenFonts[fontnum], "Screens_") or textscreenFonts[fontnum]
|
||||
end
|
||||
|
||||
local changefont
|
||||
local fontnum = textscreenFonts[GetConVar("textscreen_font1"):GetInt()] ~= nil and GetConVar("textscreen_font1"):GetInt() or 1
|
||||
|
||||
cvars.AddChangeCallback("textscreen_font1", function(convar_name, value_old, value_new)
|
||||
fontnum = textscreenFonts[tonumber(value_new)] ~= nil and tonumber(value_new) or 1
|
||||
local font = TrimFontName(fontnum)
|
||||
changefont:SetText("Change font (" .. font .. ")")
|
||||
end)
|
||||
|
||||
local function ResetFont(lines, text)
|
||||
if #lines >= 5 then
|
||||
fontnum = 1
|
||||
for i = 1, 5 do
|
||||
RunConsoleCommand("textscreen_font" .. i, 1)
|
||||
end
|
||||
end
|
||||
for k, i in pairs(lines) do
|
||||
if text then
|
||||
RunConsoleCommand("textscreen_text" .. i, "")
|
||||
labels[i]:SetText("")
|
||||
end
|
||||
labels[i]:SetFont(textscreenFonts[fontnum] .. "_MENU")
|
||||
end
|
||||
end
|
||||
|
||||
resetall = vgui.Create("DButton", resetbuttons)
|
||||
resetall:SetSize(100, 25)
|
||||
resetall:SetText("Reset all")
|
||||
|
||||
resetall.DoClick = function()
|
||||
local menu = DermaMenu()
|
||||
|
||||
menu:AddOption("Reset colors", function()
|
||||
for i = 1, 5 do
|
||||
RunConsoleCommand("textscreen_r" .. i, 255)
|
||||
RunConsoleCommand("textscreen_g" .. i, 255)
|
||||
RunConsoleCommand("textscreen_b" .. i, 255)
|
||||
RunConsoleCommand("textscreen_a" .. i, 255)
|
||||
end
|
||||
end)
|
||||
|
||||
menu:AddOption("Reset sizes", function()
|
||||
for i = 1, 5 do
|
||||
RunConsoleCommand("textscreen_size" .. i, 20)
|
||||
sliders[i]:SetValue(20)
|
||||
labels[i]:SetFont(textscreenFonts[fontnum] .. "_MENU")
|
||||
end
|
||||
end)
|
||||
|
||||
menu:AddOption("Reset textboxes", function()
|
||||
for i = 1, 5 do
|
||||
RunConsoleCommand("textscreen_text" .. i, "")
|
||||
textBox[i]:SetValue("")
|
||||
end
|
||||
end)
|
||||
|
||||
menu:AddOption("Reset fonts", function()
|
||||
ResetFont({1, 2, 3, 4, 5}, false)
|
||||
end)
|
||||
|
||||
if rainbow_enabled == 1 then
|
||||
menu:AddOption("Reset rainbow", function()
|
||||
for i = 1, 5 do
|
||||
rainbowCheckboxes[i]:SetValue(0)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
menu:AddOption("Reset everything", function()
|
||||
for i = 1, 5 do
|
||||
RunConsoleCommand("textscreen_r" .. i, 255)
|
||||
RunConsoleCommand("textscreen_g" .. i, 255)
|
||||
RunConsoleCommand("textscreen_b" .. i, 255)
|
||||
RunConsoleCommand("textscreen_a" .. i, 255)
|
||||
RunConsoleCommand("textscreen_size" .. i, 20)
|
||||
sliders[i]:SetValue(20)
|
||||
RunConsoleCommand("textscreen_text" .. i, "")
|
||||
RunConsoleCommand("textscreen_font" .. i, 1)
|
||||
textBox[i]:SetValue("")
|
||||
if rainbow_enabled == 1 then
|
||||
rainbowCheckboxes[i]:SetValue(0)
|
||||
end
|
||||
end
|
||||
ResetFont({1, 2, 3, 4, 5}, true)
|
||||
end)
|
||||
|
||||
menu:Open()
|
||||
end
|
||||
|
||||
CPanel:AddItem(resetall)
|
||||
resetline = vgui.Create("DButton")
|
||||
resetline:SetSize(100, 25)
|
||||
resetline:SetText("Reset line")
|
||||
|
||||
resetline.DoClick = function()
|
||||
local menu = DermaMenu()
|
||||
|
||||
for i = 1, 5 do
|
||||
menu:AddOption("Reset line " .. i, function()
|
||||
RunConsoleCommand("textscreen_r" .. i, 255)
|
||||
RunConsoleCommand("textscreen_g" .. i, 255)
|
||||
RunConsoleCommand("textscreen_b" .. i, 255)
|
||||
RunConsoleCommand("textscreen_a" .. i, 255)
|
||||
RunConsoleCommand("textscreen_size" .. i, 20)
|
||||
sliders[i]:SetValue(20)
|
||||
RunConsoleCommand("textscreen_text" .. i, "")
|
||||
textBox[i]:SetValue("")
|
||||
ResetFont({i}, true)
|
||||
end)
|
||||
end
|
||||
|
||||
menu:AddOption("Reset all lines", function()
|
||||
for i = 1, 5 do
|
||||
RunConsoleCommand("textscreen_r" .. i, 255)
|
||||
RunConsoleCommand("textscreen_g" .. i, 255)
|
||||
RunConsoleCommand("textscreen_b" .. i, 255)
|
||||
RunConsoleCommand("textscreen_a" .. i, 255)
|
||||
RunConsoleCommand("textscreen_size" .. i, 20)
|
||||
sliders[i]:SetValue(20)
|
||||
RunConsoleCommand("textscreen_text" .. i, "")
|
||||
RunConsoleCommand("textscreen_font" .. i, 1)
|
||||
textBox[i]:SetValue("")
|
||||
end
|
||||
ResetFont({1, 2, 3, 4, 5}, true)
|
||||
end)
|
||||
|
||||
menu:Open()
|
||||
end
|
||||
|
||||
CPanel:AddItem(resetline)
|
||||
|
||||
-- Change font
|
||||
changefont = vgui.Create("DButton")
|
||||
changefont:SetSize(100, 25)
|
||||
changefont:SetText("Change font (" .. TrimFontName(fontnum) .. ")" )
|
||||
|
||||
changefont.DoClick = function()
|
||||
local menu = DermaMenu()
|
||||
|
||||
for i = 1, #textscreenFonts do
|
||||
local font = TrimFontName(i)
|
||||
menu:AddOption(font, function()
|
||||
fontnum = i
|
||||
for o = 1, 5 do
|
||||
RunConsoleCommand("textscreen_font" .. o, i)
|
||||
labels[o]:SetFont(textscreenFonts[fontnum] .. "_MENU")
|
||||
end
|
||||
changefont:SetText("Change font (" .. font .. ")")
|
||||
end)
|
||||
end
|
||||
|
||||
menu:Open()
|
||||
end
|
||||
|
||||
CPanel:AddItem(changefont)
|
||||
|
||||
CPanel:AddControl("ComboBox", {
|
||||
MenuButton = 1,
|
||||
Folder = "textscreen",
|
||||
Options = {
|
||||
["#preset.default"] = conVarsDefault
|
||||
},
|
||||
CVars = table.GetKeys(conVarsDefault)
|
||||
})
|
||||
|
||||
for i = 1, 5 do
|
||||
lineLabels[i] = CPanel:AddControl("Label", {
|
||||
Text = "Line " .. i,
|
||||
Description = "Line " .. i
|
||||
})
|
||||
|
||||
lineLabels[i]:SetFont("Default")
|
||||
|
||||
CPanel:AddControl("Color", {
|
||||
Label = "Line " .. i .. " font color",
|
||||
Red = "textscreen_r" .. i,
|
||||
Green = "textscreen_g" .. i,
|
||||
Blue = "textscreen_b" .. i,
|
||||
Alpha = "textscreen_a" .. i,
|
||||
ShowHSV = 1,
|
||||
ShowRGB = 1,
|
||||
Multiplier = 255
|
||||
})
|
||||
|
||||
if rainbow_enabled == 1 then
|
||||
rainbowCheckboxes[i] = vgui.Create("DCheckBoxLabel")
|
||||
rainbowCheckboxes[i]:SetText("Rainbow Text")
|
||||
rainbowCheckboxes[i]:SetTextColor(Color(0,0,0,255))
|
||||
rainbowCheckboxes[i]:SetConVar("textscreen_rainbow" .. i)
|
||||
rainbowCheckboxes[i]:SetTooltip("Enable for rainbow text")
|
||||
rainbowCheckboxes[i]:SetValue(GetConVar("textscreen_rainbow" .. i):GetInt())
|
||||
CPanel:AddItem(rainbowCheckboxes[i])
|
||||
end
|
||||
|
||||
sliders[i] = vgui.Create("DNumSlider")
|
||||
sliders[i]:SetText("Font size")
|
||||
sliders[i]:SetMinMax(20, 100)
|
||||
sliders[i]:SetDecimals(0)
|
||||
sliders[i]:SetValue(GetConVar("textscreen_size" .. i))
|
||||
sliders[i]:SetConVar("textscreen_size" .. i)
|
||||
|
||||
CPanel:AddItem(sliders[i])
|
||||
textBox[i] = vgui.Create("DTextEntry")
|
||||
textBox[i]:SetUpdateOnType(true)
|
||||
textBox[i]:SetEnterAllowed(true)
|
||||
textBox[i]:SetConVar("textscreen_text" .. i)
|
||||
textBox[i]:SetValue(GetConVar("textscreen_text" .. i):GetString())
|
||||
|
||||
textBox[i].OnTextChanged = function()
|
||||
labels[i]:SetText(textBox[i]:GetValue())
|
||||
end
|
||||
|
||||
if max_characters ~= 0 then
|
||||
textBox[i].AllowInput = function()
|
||||
if string.len(textBox[i]:GetValue()) >= max_characters then return true end
|
||||
end
|
||||
end
|
||||
|
||||
CPanel:AddItem(textBox[i])
|
||||
|
||||
labels[i] = CPanel:AddControl("Label", {
|
||||
Text = #GetConVar("textscreen_text" .. i):GetString() >= 1 and GetConVar("textscreen_text" .. i):GetString() or "Line " .. i,
|
||||
Description = "Line " .. i
|
||||
})
|
||||
|
||||
labels[i]:SetFont(textscreenFonts[fontnum] .. "_MENU")
|
||||
labels[i]:SetAutoStretchVertical(true)
|
||||
labels[i]:SetDisabled(true)
|
||||
labels[i]:SetHeight(50)
|
||||
|
||||
labels[i].Think = function()
|
||||
labels[i]:SetColor(
|
||||
Color(
|
||||
GetConVar("textscreen_r" .. i):GetInt(),
|
||||
GetConVar("textscreen_g" .. i):GetInt(),
|
||||
GetConVar("textscreen_b" .. i):GetInt(),
|
||||
GetConVar("textscreen_a" .. i):GetInt()
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user