--[[ | This file was obtained through the combined efforts | of Madbluntz & Plymouth Antiquarian Society. | | Credits: lifestorm, Gregory Wayne Rossel JR., | Maloy, DrPepper10 @ RIP, Atle! | | Visit for more: https://plymouth.thetwilightzone.ru/ --]] local bit = bit local IsValid = IsValid local pairs = pairs local table = table local L = L local netstream = netstream local Entity = Entity local print = print local math = math local tostring = tostring local CAMI = CAMI local Vector = Vector local game = game local RunConsoleCommand = RunConsoleCommand local net = net local player = player local ipairs = ipairs local ents = ents local string = string local timer = timer local ix = ix local PLUGIN = PLUGIN --Links ix.command.Add("Discord", { description = "Obtenir un lien vers le serveur Discord", privilege = "Basic Commands", OnRun = function(self, client) net.Start("ixOpenURL") net.WriteString(ix.config.Get("DiscordLink")) net.Send(client) end, bNoIndicator = true }) ix.command.Add("Content", { description = "Obtenir un lien vers le Workshop", privilege = "Basic Commands", OnRun = function(self, client) net.Start("ixOpenURL") net.WriteString(ix.config.Get("ContentLink")) net.Send(client) end }) ix.command.Add("Forum", { description = "Obtenir un lien vers les forums", privilege = "Basic Commands", OnRun = function(self, client) net.Start("ixOpenURL") net.WriteString(ix.config.Get("ForumLink")) net.Send(client) end, bNoIndicator = true }) --Basic Admin ix.command.Add("PGI", { description = "Obtenez les informations de base de quelqu'un et copiez son SteamID.", arguments = { bit.bor(ix.type.player, ix.type.optional) }, --alias = "PlyGetInfo", privilege = "Commandes d'administration de base", OnRun = function(self, client, target) if (!target) then target = client:GetEyeTraceNoCursor().Entity end if (!IsValid(target) or !target:IsPlayer()) then client:NotifyLocalized("bastionPGIInvalidTarget") return end net.Start("ixPlayerInfo") net.WriteEntity(target) net.Send(client) end, bNoIndicator = true }) ix.command.Add("PrintStaffList", { alias = "PSL", description = "Imprimez une liste des membres du personnel en ligne.", OnRun = function(self, client) local staff = {} local bFound = false for _, v in ipairs(player.GetAll()) do local incognitoSetting = ix.option.Get(v, "iconIncognitoMode", false) local iconIncognitoMode = !client:IsAdmin() and !client:IsSuperAdmin() and incognitoSetting if (v:IsAdmin() or v:IsSuperAdmin()) and !iconIncognitoMode then local userGroup = v:GetUserGroup() staff[userGroup] = staff[userGroup] or {} staff[userGroup][#staff[userGroup] + 1] = v bFound = true end end local toSend = {} for k, v in pairs(staff) do toSend[#toSend + 1] = {name = k, players = v} end table.SortByMember(toSend, "name", true) if (bFound) then net.Start("ixStaffList") net.WriteUInt(#toSend, 8) for _, v in ipairs(toSend) do net.WriteString(v.name) net.WriteUInt(#v.players, 8) for i = 1, #v.players do net.WriteEntity(v.players[i]) end end net.Send(client) else client:Notify("Il n'y a pas de STAFF en ligne actuellement.") end end, bNoIndicator = true }) ix.command.Add("PrintFactionList", { alias = "PFL", description = "Imprimer une liste des membres d'une faction actuellement en ligne (y compris sur un autre personnage).", arguments = { ix.type.string }, privilege = "Basic Admin Commands", OnRun = function(self, client, name) if (name == "") then return "@invalidArg", 2 end local faction = ix.faction.teams[name] if (!faction) then for _, v in ipairs(ix.faction.indices) do if (ix.util.StringMatches(L(v.name, client), name) or ix.util.StringMatches(v.uniqueID, name)) then faction = v break end end end if (faction) then local players = {} for _, v in ipairs(player.GetAll()) do if (v:HasWhitelist(faction.index)) then players[#players + 1] = v end end net.Start("ixStaffList") net.WriteUInt(1, 8) net.WriteString(faction.name) net.WriteUInt(#players, 8) for i = 1, #players do net.WriteEntity(players[i]) end net.Send(client) else return "@invalidFaction" end end, bNoIndicator = true }) ix.command.Add("PlaySound", { description = "Jouez un son pour tous les joueurs (lorsqu'aucune portée n'est donnée) ou ceux qui sont proches de vous.", arguments = { ix.type.string, bit.bor(ix.type.number, ix.type.optional) }, privilege = "Basic Admin Commands", OnRun = function(self, client, sound, range) local targets = range and {} or player.GetAll() if (range) then range = range * range local clientPos = client:EyePos() for _, target in ipairs(player.GetAll()) do if (target:EyePos():DistToSqr(clientPos) < range) then targets[#targets + 1] = target end end end net.Start("ixPlaySound") net.WriteString(PLUGIN.soundAlias[sound] or sound) net.Send(targets) end, indicator = "chatPerforming" }) ix.command.Add("ScreenShake", { description = "Shakes the screen of everyone in the specified range. Specify the amplitude, the frequency and the radius for it to work.", arguments = { ix.type.number, ix.type.number, ix.type.number, ix.type.number }, argumentNames = {"time(seconds)", "amplitude", "frequency", "radius"}, privilege = "Basic Admin Commands", OnRun = function(self, client, seconds, strength, frequency, radius) local vector = client:GetPos() util.ScreenShake(vector, strength or 5, frequency or 5, seconds, radius) end, indicator = "chatPerforming" }) ix.command.Add("PlaySoundGlobal", { description = "Jouez un son pour tous les joueurs.", arguments = { ix.type.string, }, privilege = "Basic Admin Commands", OnRun = function(self, client, sound) net.Start("ixPlaySound") net.WriteString(PLUGIN.soundAlias[sound] or sound) net.WriteBool(true) net.Send(player.GetAll()) end, indicator = "chatPerforming" }) ix.command.Add("ShowEdicts", { description = "Renvoie le nombre d'entités en réseau actuellement sur le serveur.", privilege = "Basic Admin Commands", OnRun = function(self, client) local edictsCount = ents.GetEdictCount() local edictsLeft = 8192 - edictsCount return string.format("Il y a actuellement %s édits sur le serveur. Vous pouvez avoir jusqu'à %s de plus.", edictsCount, edictsLeft) end, bNoIndicator = true }) ix.command.Add("ShowEntsInRadius", { description = "Affiche une liste d'entités dans un rayon donné.", privilege = "Basic Admin Commands", arguments = {ix.type.number}, OnRun = function(self, client, radius) local entities = {} local pos = client:GetPos() for _, v in pairs(ents.FindInSphere(pos, radius)) do if (!IsValid(v)) then continue end entities[#entities + 1] = table.concat({v:EntIndex(), v:GetClass(), v:GetModel() or "no model", v:GetPos():Distance(pos), v:MapCreationID()}, ", ") end netstream.Start(client, "ixShowEntsInRadius", table.concat(entities,"\n")) client:NotifyLocalized("entsPrintedInConsole") end, bNoIndicator = true, }) ix.command.Add("RemoveEntityByID", { description = "Affiche une liste d'entités dans un rayon donné.", superAdminOnly = true, arguments = {ix.type.number}, OnRun = function(self, client, number) local entity = Entity(number) if (IsValid(entity)) then client:NotifyLocalized("entityRemoved", number, entity:GetClass()) entity:Remove() else client:NotifyLocalized("entityNotFound", number) end end, bNoIndicator = true, }) if (CLIENT) then netstream.Hook("ixShowEntsInRadius", function(text) print(text) end) end ix.command.Add("LocalEvent", { description = "@cmdLocalEvent", privilege = "Event", arguments = { ix.type.string, bit.bor(ix.type.number, ix.type.optional) }, OnRun = function(self, client, event, range) local _range = range or (ix.config.Get("chatRange", 280) * 2) ix.chat.classes.localevent.range = _range * _range local doubleCommand = false -- This could probably be done a bit smarter but I'm sure it'll do. if (string.Left(string.lower(event), 11) == "/localevent") then doubleCommand = true event = string.Right(event, #event - 12) elseif (string.Left(string.lower(event), 10) == "localevent") then doubleCommand = true event = string.Right(event, #event - 11) end if (doubleCommand) then client:NotifyLocalized("textDoubleCommand", "/LocalEvent") end ix.chat.Send(client, "localevent", event) end, indicator = "chatPerforming" }) ix.command.Add("RemovePersistedProps", { description = "@cmdRemovePersistedProps", superAdminOnly = true, arguments = { ix.type.number }, OnRun = function(self, client, radius) if (radius < 0) then client:Notify("Radius must be a positive number!") return end for _, entity in ipairs(ents.FindInSphere(client:GetPos(), radius)) do if (!entity:GetNetVar("Persistent")) then continue end entity:Remove() end client:Notify("Removed all persisted props in a radius of " .. radius .. " units.") end }) ix.command.Add("Announce", { description = "@cmdAnnounce", arguments = { ix.type.text }, OnRun = function(self, client, event) ix.chat.Send(client, "announcement", event) end, OnCheckAccess = function(self, client) return !client or CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands") end, indicator = "chatTyping" }) -- Help ix.command.Add("Help", { description = "@cmdStaffHelp", arguments = ix.type.text, alias = {"GMHelp", "ModHelp"}, OnRun = function(self, client, text) client:Say("@ " .. text) end, OnCheckAccess = function(self, client) return !CAMI.PlayerHasAccess(client, "Helix - Hear Staff Chat") end, indicator = "chatTyping" }) -- Admin Chat ix.command.Add("Staff", { description = "Discutez avec d'autres membres du STAFF.", arguments = ix.type.text, privilege = "Hear Staff Chat", alias = {"Op", "Mod", "ModChat"}, OnRun = function(self, client, text) ix.chat.Send(client, "staff_chat", text) end, indicator = "chatTyping" }) -- Gamemaster Chat ix.command.Add("GameMaster", { description = "Discutez avec d'autres Gamemasters.", arguments = ix.type.text, privilege = "Hear GM Chat", alias = {"GMChat", "GM"}, OnRun = function(self, client, text) ix.chat.Send(client, "gm_chat", text) end, indicator = "chatTyping" }) -- Mentor Chat ix.command.Add("Mentor", { description = "Discutez avec d'autres mentors.", arguments = ix.type.text, privilege = "Hear Mentor Chat", alias = {"MChat", "M"}, OnRun = function(self, client, text) ix.chat.Send(client, "mentor_chat", text) end, indicator = "chatTyping" }) -- Fun Stuff ix.command.Add("Achievement", { description = "Quelqu'un a gagné une réalisation spéciale !", arguments = { ix.type.player, ix.type.text }, privilege = "Fun Stuff", OnRun = function(self, client, target, text) ix.chat.Send(client, "achievement_get", text, false, nil, {target, "ambient/water/drip" .. math.random( 1, 4 ) .. ".wav"}) end, indicator = "chatTyping" }) ix.command.Add("DarwinAward", { description = "Quelqu'un a mérité un exploit : il a fait le sacrifice ultime pour augmenter le QI moyen de l'humanité.", arguments = { ix.type.player }, privilege = "Fun Stuff", OnRun = function(self, client, target) if (!target:Alive()) then local pos = target:GetPos() target:Spawn() target:SetPos(pos) end target:SetMoveType(MOVETYPE_WALK) target:SetVelocity(Vector(0, 0, 4000)) timer.Simple(1, function() PLUGIN:Explode(target) end) ix.chat.Send(client, "achievement_get", "DARWIN AWARD", false, nil, {target, "ambient/alarms/razortrain_horn1.wav"}) end, indicator = "chatTyping" }) ix.command.Add("PlyRocket", { description = "To infinity, and beyond!.", arguments = { ix.type.player }, privilege = "Fun Stuff", OnRun = function(self, client, target) if (!target:Alive()) then local pos = target:GetPos() target:Spawn() target:SetPos(pos) end target:SetMoveType(MOVETYPE_WALK) target:SetVelocity(Vector(0, 0, 4000)) timer.Simple(1, function() PLUGIN:Explode(target) end) end, bNoIndicator = true }) ix.command.Add("SetTimeScale", { description = "@cmdTimeScale", arguments = { bit.bor(ix.type.number, ix.type.optional) }, privilege = "Fun Stuff", OnRun = function(self, client, number) local scale = math.Clamp(number or 1, 0.001, 5) game.SetTimeScale(scale) for _, v in ipairs(player.GetAll()) do if (self:OnCheckAccess(v)) then v:NotifyLocalized("bastionTimeScale", client:Name(), scale) end end end, bNoIndicator = true }) ix.command.Add("SetGravity", { description = "@cmdGravity", arguments = { bit.bor(ix.type.number, ix.type.optional) }, privilege = "Fun Stuff", OnRun = function(self, client, number) RunConsoleCommand("sv_gravity", number) for _, v in ipairs(player.GetAll()) do if (self:OnCheckAccess(v)) then v:NotifyLocalized("bastionGravity", client:Name(), number) end end end, bNoIndicator = true }) -- lookup commands ix.command.Add("LookupSteamID", { description = "Lookup a SteamID in the Bastion user database", arguments = { ix.type.text }, privilege = "Bastion Lookup", OnRun = function(self, client, target) if (string.find(target, "^STEAM_%d+:%d+:%d+$")) then PLUGIN:LookupSteamID(client, target) return elseif (string.len(target) == 17 and string.find(target, "^%d+$")) then PLUGIN:LookupSteamID(client, target) return end target = ix.util.FindPlayer(target, false) client:NotifyLocalized("bastionTargetSelected", target:Name()) PLUGIN:LookupSteamID(client, target:SteamID64()) end, bNoIndicator = true }) ix.command.Add("LookupIPUsers", { description = "Lookup a SteamID in the Bastion IP database", arguments = { ix.type.text }, privilege = "Bastion Lookup", OnRun = function(self, client, target) if (string.find(target, "^STEAM_%d+:%d+:%d+$")) then PLUGIN:LookupIPUsers(client, target) return elseif (string.len(target) == 17 and string.find(target, "^%d+$")) then PLUGIN:LookupIPUsers(client, target) return end target = ix.util.FindPlayer(target, false) client:NotifyLocalized("bastionTargetSelected", target:Name()) PLUGIN:LookupIPUsers(client, target:SteamID64()) end, bNoIndicator = true }) ix.command.Add("ProxyWhitelist", { description = "Whitelist a player as trusted to disable future proxy checks.", arguments = { ix.type.player }, privilege = "Bastion Whitelist", OnRun = function(self, client, target) if (PLUGIN:WhitelistPlayer(target)) then client:NotifyLocalized("whitelistDone") else client:NotifyLocalized("whitelistError") end end, indicator = "chatTyping" }) ix.command.Add("PlyGetCharacters", { description = "Get a list of a player's characters.", arguments = { ix.type.player }, adminOnly = true, OnRun = function(self, client, target) client:ChatNotify(target:SteamName() .. "'s characters:") client:ChatNotify("====================") for _, character in pairs(target.ixCharList) do client:ChatNotify(ix.char.loaded[character].vars.name) end end }) ix.command.Add("LTARP", { description = "Automatically ban a player for leaving to avoid RP after a grace period.", arguments = { ix.type.string, ix.type.number, bit.bor(ix.type.text, ix.type.optional), }, adminOnly = true, OnRun = function(self, client, steamID, days, reason) local target = player.GetBySteamID64(steamID) or player.GetBySteamID(steamID) if (target) then client:Notify(target:SteamName().." is still on the server as '"..target:Name().."!") return end if (days > 100) then client:Notify("Invalid duration entered. Max ban length is 100 days.") return end if (string.find(string.upper(steamID), "^STEAM")) then steamID = util.SteamIDTo64(string.upper(steamID)) end if (!PLUGIN.disconnects[steamID]) then client:Notify("Could not find a disconnect for "..steamID..", manually ban them if needed.") return end local info = PLUGIN.disconnects[steamID] if (info.timer) then client:Notify(steamID.." is already tagged for LTARP by "..info.bannedByName..".") return end local reconnectTime, maxBanDelay = 30, 40 if (info.time + reconnectTime * 60 < os.time()) then if (info.time + maxBanDelay * 60 < os.time()) then client:Notify(steamID.." disconnected more than "..maxBanDelay.." minutes ago already. Manually ban them if needed.") return end RunConsoleCommand("sam", "banid", steamID, tostring(days * 60 * 24), reason != "" and reason or "Leaving to avoid RP. Appeal on willard.network ~"..client:SteamName()) return end local uniqueID = "ixLTARP"..steamID local bannedBy = client and client:SteamName() or "console" timer.Create(uniqueID, info.time - os.time() + reconnectTime * 60, 1, function() if (IsValid(client)) then client:Notify(steamID.." did not reconnect and has been banned.") end RunConsoleCommand("sam", "banid", steamID, tostring(days * 60 * 24), reason != "" and reason or "Leaving to avoid RP. Appeal on willard.network ~"..bannedBy) end) info.timer = uniqueID info.bannedBy = client info.bannedByName = client and client:SteamName() or "console" client:Notify("Timer set! "..steamID.." will be banned in "..math.ceil((info.time - os.time() + reconnectTime * 60) / 60).." minutes.") end })