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