Initial commit

This commit is contained in:
2026-03-15 14:54:49 +03:00
commit 64f8029c06
4027 changed files with 254888 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
{
"title": "3D2D Textscreens",
"type": "tool",
"tags": [
"fun",
"roleplay"
],
"ignore": []
}

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View 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

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -0,0 +1,14 @@
tool.textscreen.name=3D2D Textscreen
tool.textscreen.desc=Create a textscreen with multiple lines, font colours and sizes.
tool.textscreen.left=Spawn a textscreen.
tool.textscreen.right=Update textscreen with settings.
tool.textscreen.reload=Copy textscreen.
Undone.textscreens=Undone textscreen
Undone_textscreens=Undone textscreen
Cleanup.textscreens=Textscreens
Cleanup_textscreens=Textscreens
Cleaned.textscreens=Cleaned up all textscreens
Cleaned_textscreens=Cleaned up all textscreens
SBoxLimit.textscreens=You've hit the textscreen limit!
SBoxLimit_textscreens=You've hit the textscreen limit!

View File

@@ -0,0 +1,14 @@
tool.textscreen.name=Pantalla de texto 3D2D
tool.textscreen.desc=Crear a Pantalla de texto con múltiples líneas, colores de fuente y tamaños.
tool.textscreen.left=Aparecer a Pantalla de texto.
tool.textscreen.right=Actualizar Pantalla de texto with settings.
tool.textscreen.reload=Dupdo Pantalla de texto.
Undone.textscreens=Deshecho Pantalla de texto
Undone_textscreens=Deshecho Pantalla de texto
Cleanup.textscreens=Pantalla de texto
Cleanup_textscreens=Pantalla de texto
Cleaned.textscreens=Limpió todas las pantallas de texto
Cleaned_textscreens=Limpió todas las pantallas de texto
SBoxLimit.textscreens=¡Has alcanzado el límite de la pantalla de texto!
SBoxLimit_textscreens=¡Has alcanzado el límite de la pantalla de texto!

View File

@@ -0,0 +1,14 @@
tool.textscreen.name=3D2D Textscreen
tool.textscreen.desc=Utwórz ekran tekstowy z wieloma liniami, kolorami czcionek i rozmiarami.
tool.textscreen.left=Utwórz ekran tekstowy.
tool.textscreen.right=Uaktualnij ekran tekstowy z wybranymi ustawieniami.
tool.textscreen.reload=Skopiuj ekran tekstowy.
Undone.textscreens=Cofnij utworzenie ekranu tekstowego
Undone_textscreens=Cofnij utworzenie ekranu tekstowego
Cleanup.textscreens=Ekrany tekstowe
Cleanup_textscreens=Ekrany tekstowe
Cleaned.textscreens=Usunięto wszystkie ekrany tekstowe
Cleaned_textscreens=Usunięto wszystkie ekrany tekstowe
SBoxLimit.textscreens=Przekroczyłeś limit ekranów tekstowych!
SBoxLimit_textscreens=Przekroczyłeś limit ekranów tekstowych!

View File

@@ -0,0 +1,14 @@
tool.textscreen.name=3D2D \u0422\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439\u0020\u044d\u043a\u0440\u0430\u043d
tool.textscreen.desc=\u0421\u043e\u0437\u0434\u0430\u0451\u0442\u0020\u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439\u0020\u044d\u043a\u0440\u0430\u043d\u0020\u0441\u0020\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438\u0020\u043b\u0438\u043d\u0438\u044f\u043c\u0438\u002c\u0020\u0446\u0432\u0435\u0442\u0430\u043c\u0438\u0020\u0438\u0020\u0440\u0430\u0437\u043c\u0435\u0440\u0430\u043c\u0438\u0020\u0448\u0440\u0438\u0444\u0442\u0430\u002e
tool.textscreen.left=\u0421\u043e\u0437\u0434\u0430\u0442\u044c\u0020\u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439\u0020\u044d\u043a\u0440\u0430\u043d\u002e
tool.textscreen.right=\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c\u0020\u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439\u0020\u044d\u043a\u0440\u0430\u043d\u0020\u0438\u0020\u0435\u0433\u043e\u0020\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u002e
tool.textscreen.reload=\u0421\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0020\u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439\u0020\u044d\u043a\u0440\u0430\u043d\u002e
Undone.textscreens=\u0422\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439\u0020\u044d\u043a\u0440\u0430\u043d\u0020\u043e\u0442\u043c\u0435\u043d\u0451\u043d
Undone_textscreens=\u0422\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439\u0020\u044d\u043a\u0440\u0430\u043d\u0020\u043e\u0442\u043c\u0435\u043d\u0451\u043d
Cleanup.textscreens=\u0422\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435\u0020\u044d\u043a\u0440\u0430\u043d\u044b
Cleanup_textscreens=\u0422\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435\u0020\u044d\u043a\u0440\u0430\u043d\u044b
Cleaned.textscreens=\u0423\u0431\u0440\u0430\u043d\u044b\u0020\u0432\u0441\u0435\u0020\u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435\u0020\u044d\u043a\u0440\u0430\u043d\u044b
Cleaned_textscreens=\u0423\u0431\u0440\u0430\u043d\u044b\u0020\u0432\u0441\u0435\u0020\u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435\u0020\u044d\u043a\u0440\u0430\u043d\u044b
SBoxLimit.textscreens=\u0412\u044b\u0020\u0434\u043e\u0441\u0442\u0438\u0433\u043b\u0438\u0020\u043b\u0438\u043c\u0438\u0442\u0430\u0020\u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0445\u0020\u044d\u043a\u0440\u0430\u043d\u043e\u0432\u0021
SBoxLimit_textscreens=\u0412\u044b\u0020\u0434\u043e\u0441\u0442\u0438\u0433\u043b\u0438\u0020\u043b\u0438\u043c\u0438\u0442\u0430\u0020\u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0445\u0020\u044d\u043a\u0440\u0430\u043d\u043e\u0432\u0021

View File

@@ -0,0 +1,14 @@
tool.textscreen.name=3D2D Metin Ekranı
tool.textscreen.desc=Birden çok satır, yazı tipi rengi ve boyutu olan bir metin ekranı oluşturun.
tool.textscreen.left=Bir metin ekranı oluştur.
tool.textscreen.right=Metin ekranını ayarlarla güncelleyin.
tool.textscreen.reload=Metin ekranını kopyala.
Undone.textscreens=Bitmemiş metin ekranı
Undone_textscreens=Bitmemiş metin ekranı
Cleanup.textscreens=Metin Ekranları
Cleanup_textscreens=Metin Ekranları
Cleaned.textscreens=Tüm metin ekranlarını temizle
Cleaned_textscreens=Tüm metin ekranlarını temizle
SBoxLimit.textscreens=Metin ekranı sınırına ulaştınız!
SBoxLimit_textscreens=Metin ekranı sınırına ulaştınız!