Advertisement
th3w1zard1

Commands Beta Version

Mar 24th, 2015
25,974
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 383.62 KB | None | 0 0
  1.     --Creator: Wizard
  2.     --Script Name: Command Script
  3.     --Website: http://phasorscripts.wordpress.com/
  4.     --Xfire: th3w1zard3
  5.     --Check Change Log for information on the updates
  6.     --Thank you AElite for the awesome work you did in updating this script to the latest phasor, and the other awesome features you put in.
  7.     --Without you I never would have updated to the newer phasor, and this script never would have been made.
  8.  
  9.     -- I FOUND A MAGICAL COMMAND THAT HELPED ME TEST THIS AMAZING SCRIPT: luac -p -l commands.lua | grep 'ETTABUP.*_ENV' (or ETGLOBAL for 5.1) 
  10.  
  11. --
  12. --Do Not Modify unless you really know what you are doing
  13. --
  14.     -- Counts
  15. local cur_players = 0
  16. local rtv_counter = 0
  17. local votekick_counter = 0
  18. local scorelimit = 50
  19.  
  20.     -- Strings
  21. local script_version = "5.2 The 'Nimbus' Release"
  22.  
  23.     -- Timers
  24. local infammo_timer
  25. local lo3_timer
  26. local maintimer
  27. local rtvtimer
  28. local votekicktimer
  29.  
  30.     -- Script Variables
  31. local changelog
  32. local dont_call_onservercommand
  33. local executingPlayerId
  34. local Game
  35. local gameend
  36. local gametype
  37. local http
  38. local flameId
  39. local Map
  40. local output_environment = -1
  41. local Persistent
  42. local processid
  43. local profilepath
  44. local server
  45. local server_prefix
  46. local someoneHidden = false
  47. local socket
  48. local team_play
  49. local team_play_temp
  50. local time_passed_value
  51. local timelimit_set_value
  52. local votekickPlayerId
  53.  
  54. -- Local variables defined for decreased execution time (but mostly to organize what is using the global environment)
  55. local io, tostring, tonumber, next, type, os, select = io, tostring, tonumber, next, type, os, select
  56. local sub, gsub, find, lower, format, match = string.sub, string.gsub, string.find, string.lower, string.format, string.match
  57. local insert, remove, concat = table.insert, table.remove, table.concat
  58. local ceil, floor = math.ceil, math.floor
  59.  
  60.  
  61.     -- Table Management
  62. local TM = setmetatable({
  63.         unused_tables = {},
  64.         __gc = function(self) self.unused_tables[#self.unused_tables+1] = self end,
  65.         __tostring = function(t)
  66.             local tableStr = "{ "
  67.             if next(t) then
  68.                 for k,v in next,t do
  69.                     if v == t then goto nextVal end
  70.                     k = type(k) ~= "number" and '["' .. k .. '"]' or k
  71.                     v = type(v) == "string" and '"' .. v .. '"' or tostring(v)
  72.                     tableStr = tableStr .. (k .. " = ") .. v .. ", "
  73.                     ::nextVal::
  74.                 end
  75.  
  76.                 tableStr = sub(tableStr, 1, #tableStr-2)
  77.             else
  78.                 tableStr = tableStr
  79.             end
  80.             return tableStr .. "}"
  81.         end,
  82.         deleteEntries = function(t)
  83.             for key,_ in next,t do
  84.                 t[key] = nil
  85.             end
  86.             return t
  87.         end
  88.     },
  89.     {
  90.         __call = function(TM, t)
  91.             local mt = getmetatable(t)
  92.             if mt then
  93.                 mt.__index = TM
  94.                 return t
  95.             else
  96.                 return setmetatable(t, TM)
  97.             end
  98.         end
  99.     }
  100. )
  101. TM.__index = TM
  102.  
  103.     -- Tables
  104. local access_table = {}
  105. --local addresses
  106. local admin_table = {}
  107. local ban_table = {}
  108. local ban_penalty = {}
  109. local bos_table = {}
  110. local Commands = {commandAliases = {}}
  111. Commands.__index = Commands -- class setup
  112. local commandAliases = Commands.commandAliases
  113. local connections = {}
  114. local cmdreply = setmetatable({index = 0}, {
  115.     __mode = "v", -- weak table
  116.     __len = function(self) return (rawget(self, "index") or 0) end,
  117.     --old method
  118.     --[[
  119.     __newindex = function(self, key, value)
  120.         if not tonumber(key) then
  121.             return
  122.         end
  123.  
  124.         local index = rawget(self, "index")
  125.         rawset(self, "index", value and (index+1) or (index-1)) -- update the index.
  126.         rawset(self, key, value or rawget(self, index))
  127.     end,]]
  128.     __call = function(self, bResetAll)
  129.         if not bResetAll then
  130.             local index = rawget(self, "index") + 1
  131.             rawset(self, "index", index)
  132.             return index
  133.         end
  134.         rawset(self, "header", nil)
  135.         rawset(self, "align", nil)
  136.         rawset(self, "delim", nil)
  137.         rawset(self, "separator", nil)
  138.         rawset(self, "index", 0)
  139.     end
  140. })
  141. local clients = {}
  142. local debug_players = {}
  143. -- REM: change back cobalthidden before release.
  144. local player_colors = {[0] = "white", "black", "red", "blue", "grey", "yellow", "green", "pink", "purple", "cyan", "cobalthidden", "orange", "teal", "sage", "brown", "tan", "maroon", "salmon", white = 0, black = 1, red = 2, blue = 3, grey = 4, yellow = 5, green = 6, pink = 7, purple = 8, cyan = 9, cobalthidden = 10, orange = 11, teal = 12, sage = 13, brown = 14, tan = 15, maroon = 16, salmon = 17}
  145. local team_colors = {[0] = "red", "blue", "white", "black", "pink", "yellow", "cobalthidden", "orange", "purple", "cyan", "maroon", "teal", "green", "sage", "brown", "salmon"}
  146. local player_scores = {[0] = 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
  147. local team_scores = {[0] = 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
  148. -- Default Scripted Game Variables
  149. local defaults = {
  150.     kickbans_file = "KicksAndBans",
  151.     commands_file = "commands",
  152.     admin_file = "admins",
  153.     banlist_file = "banned",
  154.     sharedhash_file = "sharedhashes",
  155.     ban_penalty = "5m 1d 10d",
  156.     remote_bansystem = false,
  157.     remotecontrol = false,
  158.     --tkban_type = "ip",
  159.     adminblocker = 0,
  160.     anticaps = false,
  161.     antispam = "players",
  162.     chatcommands = true,
  163.     chatids = true,
  164.     crouch_camo = false,
  165.     deathless = false,
  166.     debug_mode = false,
  167.     falldamage = true,
  168.     firstjoin_message = true,
  169.     hash_duplicates = true,
  170.     infinite_ammo = false,
  171.     killing_spree = true,
  172.     multiteam_vehicles = false,
  173.     noweapons = false,
  174.     pm_enabled = true,
  175.     respawn_time = -1,
  176.     rtv_enabled = true,
  177.     rtv_required = 50,
  178.     rtv_timeout = 120,
  179.     sa_message = true,
  180.     scrim_mode = false,
  181.     spam_max = 7,
  182.     spam_timeout = 60,
  183.     tbag_detection = true,
  184.     uniques_enabled = true,
  185.     votekick_enabled = true,
  186.     votekick_action = "kick",
  187.     votekick_required = 70,
  188.     votekick_timeout = 120,
  189.     wb_message = true
  190. }
  191.  
  192. local identities = {}
  193. identities.__index = identities
  194.  
  195. local leave_table = {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}
  196. local locations = {} -- map = {locname = {x, y, z}}
  197. local spawnWeapons = {}
  198. local tag_table = {}
  199. local objects
  200. local playerMT = {}
  201. local PlayerClass = {
  202.     [0]={drones = TM{}, weapons = {}},
  203.         {drones = TM{}, weapons = {}},
  204.         {drones = TM{}, weapons = {}},
  205.         {drones = TM{}, weapons = {}},
  206.         {drones = TM{}, weapons = {}},
  207.         {drones = TM{}, weapons = {}},
  208.         {drones = TM{}, weapons = {}},
  209.         {drones = TM{}, weapons = {}},
  210.         {drones = TM{}, weapons = {}},
  211.         {drones = TM{}, weapons = {}},
  212.         {drones = TM{}, weapons = {}},
  213.         {drones = TM{}, weapons = {}},
  214.         {drones = TM{}, weapons = {}},
  215.         {drones = TM{}, weapons = {}},
  216.         {drones = TM{}, weapons = {}},
  217.         {drones = TM{}, weapons = {}}
  218. }
  219. PlayerClass.__index = PlayerClass
  220.  
  221. for i = 0,15 do
  222.     setmetatable(PlayerClass[i], PlayerClass)
  223. end
  224.  
  225. local randomNames = {
  226.     Butcher = 1,
  227.     Caboose = 2,
  228.     Crazy = 3,
  229.     Cupid = 4,
  230.     Darling = 5,
  231.     Dasher = 6,
  232.     Disco = 7,
  233.     Donut = 8,
  234.     Dopey = 9,
  235.     Ghost = 10,
  236.     Goat = 11,
  237.     Grumpy = 12,
  238.     Hambone = 13,
  239.     Hollywood = 14,
  240.     Howard = 15,
  241.     Jack = 16,
  242.     Killer = 17,
  243.     King = 18,
  244.     Mopey = 19,
  245.     Noodle = 20,
  246.     Penguin = 21,
  247.     Pirate = 22,
  248.     Prancer = 23,
  249.     Saucy = 24,
  250.     Shadow = 25,
  251.     Sleepy = 26,
  252.     Snake = 27,
  253.     Sneak = 28,
  254.     Stompy = 29,
  255.     Stumpy = 30,
  256.     ["The Bear"] = 31,
  257.     ["The Big L"] = 32,
  258.     Tooth = 33,
  259.     ["Walla Walla"] = 34,
  260.     Weasel = 35,
  261.     Wheezy = 36,
  262.     Whicker = 37,
  263.     Whisp = 38,
  264.     Wilshire = 39
  265. }
  266. local rcon_passwords = {}
  267. local sharedhashes = {
  268.     ["f443106bd82fd6f3c22ba2df7c5e4094"] = 1,
  269.     ["c702226e783ea7e091c0bb44c2d0ec64"] = 2,
  270.     ["d72b3f33bfb7266a8d0f13b37c62fddb"] = 3,
  271.     ["55d368354b5021e7dd5d3d1525a4ab82"] = 4,
  272.     ["3d5cd27b3fa487b040043273fa00f51b"] = 5,
  273.     ["b661a51d4ccf44f5da2869b0055563cb"] = 6,
  274.     ["740da6bafb23c2fbdc5140b5d320edb1"] = 7,
  275.     ["10440b462f6cbc3160c6280c2734f184"] = 8,
  276.     ["7503dad2a08026fc4b6cfb32a940cfe0"] = 9,
  277.     ["4486253cba68da6786359e7ff2c7b467"] = 10,
  278.     ["f1d7c0018e1648d7d48f257dc35e9660"] = 11,
  279.     ["40da66d41e9c79172a84eef745739521"] = 12,
  280.     ["2863ab7e0e7371f9a6b3f0440c06c560"] = 13,
  281.     ["34146dc35d583f2b34693a83469fac2a"] = 14,
  282.     ["b315d022891afedf2e6bc7e5aaf2d357"] = 15,
  283.     ["81f9c914b3402c2702a12dc1405247ee"] = 16,
  284.     ["63bf3d5a51b292cd0702135f6f566bd1"] = 17,
  285.     ["6891d0a75336a75f9d03bb5e51a53095"] = 18,
  286.     ["325a53c37324e4adb484d7a9c6741314"] = 19,
  287.     ["0e3c41078d06f7f502e4bb5bd886772a"] = 20,
  288.     ["fc65cda372eeb75fc1a2e7d19e91a86f"] = 21,
  289.     ["f35309a653ae6243dab90c203fa50000"] = 22,
  290.     ["50bbef5ebf4e0393016d129a545bd09d"] = 23,
  291.     ["a77ee0be91bd38a0635b65991bc4b686"] = 24,
  292.     ["3126fab3615a94119d5fe9eead1e88c1"] = 25,
  293.     ["d41d8cd98f00b204e9800998ecf8427e"] = 26
  294. }
  295. local threads = {} -- list of all live threads
  296. local unique_table = TM(setmetatable({total = 0}, {__len = function(self) return self.total end}))
  297. local valid_maps = {}
  298. local valid_gametypes = {}
  299.  
  300.     -- Send Debug Messages
  301. local function sendDebugMessage(message)
  302.     local playerId
  303.     for playerId = 0,15 do
  304.         if debug_players[playerId] then
  305.             sendconsoletext(playerId, message)
  306.         end
  307.     end
  308. end
  309.  
  310.     -- Private Functions
  311.    
  312. -- Phasor doesn't automatically check limits for write functions, it just errors, so let's make our own check.
  313. local function writewithinlimit(address, value, writefunc, minlimit, maxlimit)
  314.     writefunc(address, value <= minlimit and minlimit or value >= maxlimit and maxlimit or value)
  315. end
  316.  
  317. local function writebyte(address, offset, value)
  318.     if value then
  319.         address = address + offset
  320.     else
  321.         value = offset
  322.     end
  323.     writewithinlimit(address, value, _G.writebyte, 0, 0xFF)
  324. end
  325.  
  326. local function writechar(address, offset, value)
  327.     if value then
  328.         address = address + offset
  329.     else
  330.         value = offset
  331.     end
  332.     writewithinlimit(address, value, _G.writechar, -0x80, 0x7F)
  333. end
  334.  
  335. local function writeword(address, offset, value)
  336.     if value then
  337.         address = address + offset
  338.     else
  339.         value = offset
  340.     end
  341.     writewithinlimit(address, value, _G.writeword, 0, 0xFFFF)
  342. end
  343.  
  344. local function writeshort(address, offset, value)
  345.     if value then
  346.         address = address + offset
  347.     else
  348.         value = offset
  349.     end
  350.     writewithinlimit(address, value, _G.writeshort, -0x8000, 0x7FFF)
  351. end
  352.  
  353. local function writedword(address, offset, value)
  354.     if value then
  355.         address = address + offset
  356.     else
  357.         value = offset
  358.     end
  359.     writewithinlimit(address, value, _G.writedword, 0, 0xFFFFFFFF)
  360. end
  361.  
  362. local function writeint(address, offset, value)
  363.     if value then
  364.         address = address + offset
  365.     else
  366.         value = offset
  367.     end
  368.     writewithinlimit(address, value, _G.writeint, -0x80000000, 0x7FFFFFFF)
  369. end
  370.  
  371. -- Phasor's read/writestring in previous versions are broken.
  372. local function readstring(address, length)
  373.     address = type(address) == "number" and address or error("bad argument #1 to 'readstring' expected number, got '" .. type(address) .. "'")
  374.     if length then
  375.         length = type(length) == "number" and length or error("bad argument #2 to 'readstring' expected number, got '" .. type(length) .. "'")
  376.     else
  377.         length = length or 256
  378.     end
  379.     local char_table = {}
  380.     local char = string.char
  381.     local word, dword, byte1, byte2, byte3, byte4
  382.     local i = 0
  383.     while i < length do
  384.         -- quickens read calls (screw you oxide for using virtualprotect)
  385.         if (length-i) >= 4 then
  386.             dword = readdword(address + i)
  387.  
  388.             byte1 = bit32.band(dword, 0xFF)
  389.             if byte1 == 255 or byte1 == 0 then break end
  390.             char_table[#char_table+1] = char(byte1)
  391.  
  392.             byte2 = bit32.band(bit32.rshift(dword, 8), 0xFF)
  393.             if byte2 == 255 or byte2 == 0 then break end
  394.             char_table[#char_table+1] = char(byte2)
  395.  
  396.             byte3 = bit32.band(bit32.rshift(dword, 16), 0xFF)
  397.             if byte3 == 255 or byte3 == 0 then break end
  398.             char_table[#char_table+1] = char(byte3)
  399.  
  400.             byte4 = bit32.band(bit32.rshift(dword, 24), 0xFF)
  401.             if byte4 == 255 or byte4 == 0 then break end
  402.             char_table[#char_table+1] = char(byte4)
  403.  
  404.             i = i + 4
  405.         elseif (length-i) >= 2 then
  406.             word = readword(address + i)
  407.  
  408.             byte1 = bit32.band(word, 0xFF)
  409.             if byte1 == 255 or byte1 == 0 then break end
  410.             char_table[#char_table+1] = char(byte1)
  411.  
  412.             byte2 = bit32.band(bit32.rshift(word, 8), 0xFF)
  413.             if byte2 == 255 or byte2 == 0 then break end
  414.             char_table[#char_table+1] = char(byte2)
  415.  
  416.             i = i + 2
  417.         else
  418.             byte1 = readbyte(address + i)
  419.             if byte1 == 0 or byte1 == 255 then break end
  420.             char_table[#char_table+1] = char(byte1)
  421.             i = i + 1
  422.         end
  423.     end
  424.     return table.concat(char_table)
  425. end
  426.  
  427. local function readwidestring(address, length)
  428.     address = type(address) == "number" and address or error("bad argument #1 to 'readwidestring' expected number, got '" .. type(address) .. "'")
  429.     if length then
  430.         length = type(length) == "number" and length or error("bad argument #2 to 'readwidestring' expected number, got '" .. type(length) .. "'")
  431.     else
  432.         length = length or 51001
  433.     end
  434.     local char_table = {}
  435.     local char = string.char
  436.     local word, dword, byte1, byte2, byte3, byte4
  437.     local i = 0
  438.     while i < length do
  439.         -- quickens read calls (screw you oxide for using virtualprotect)
  440.         if (length-i) >= 4 then
  441.             dword = readdword(address + i)
  442.  
  443.             byte1 = bit32.band(dword, 0xFF)
  444.             if byte1 == 255 or byte1 == 0 then break end
  445.             char_table[#char_table+1] = char(byte1)
  446.  
  447.             byte2 = bit32.band(bit32.rshift(dword, 8), 0xFF)
  448.             if byte2 ~= 255 or byte2 ~= 0 then break end
  449.  
  450.             byte3 = bit32.band(bit32.rshift(dword, 16), 0xFF)
  451.             if byte3 == 255 or byte3 == 0 then break end
  452.             char_table[#char_table+1] = char(byte3)
  453.  
  454.             byte4 = bit32.band(bit32.rshift(dword, 24), 0xFF)
  455.             if byte4 ~= 255 or byte4 ~= 0 then break end
  456.  
  457.             i = i + 4
  458.         else
  459.             word = readword(address + i)
  460.  
  461.             byte1 = bit32.band(word, 0xFF)
  462.             if byte1 == 255 or byte1 == 0 then break end
  463.             char_table[#char_table+1] = char(byte1)
  464.  
  465.             byte2 = bit32.band(bit32.rshift(word, 8), 0xFF)
  466.             if byte2 ~= 255 or byte2 ~= 0 then break end
  467.  
  468.             i = i + 2
  469.         end
  470.     end
  471.     return table.concat(char_table)
  472. end
  473.  
  474. local function writestring(address, offset, str)
  475.     address = type(address) == "number" and address or error("bad argument #1 to 'writestring' expected number, got '" .. type(address) .. "'")
  476.     if str then
  477.         offset = type(offset) == "number" and offset or error("bad argument #2 to 'writestring' expected number, got '" .. type(offset) .. "'")
  478.         str = type(str) == "string" and str or error("bad argument #3 to 'writestring' expected string, got '" .. type(str) .. "'")
  479.     else
  480.         str = type(offset) == "string" and offset or error("bad argument #2 to 'writestring' expected string, got '" .. type(offset) .. "'")
  481.         offset = nil
  482.     end
  483.     address = address + (offset or 0x0)
  484.     local byte_table = {}
  485.     local byte = string.byte
  486.     for char in string.gmatch(str, '.') do
  487.         byte_table[#byte_table+1] = byte(char)
  488.     end
  489.     local length = #byte_table
  490.     local i = 0
  491.     while i < length do
  492.         -- quickens write calls (screw you oxide for using virtualprotect)
  493.         if (length-i) >= 4 then
  494.             writedword(address + i, tonumber(string.format("%02X%02X%02X%02X", byte_table[i+4], byte_table[i+3], byte_table[i+2], byte_table[i+1]), 16))
  495.             i = i + 4
  496.         elseif (length-i) >= 2 then
  497.             writeword(address + i, tonumber(string.format("%02X%02X", byte_table[i+2], byte_table[i+1]), 16))
  498.             i = i + 2
  499.         else
  500.             writebyte(address + i, byte_table[i+1])
  501.             i = i + 1
  502.         end
  503.     end
  504. end
  505.  
  506. local function writewidestring(address, offset, str)
  507.     address = type(address) == "number" and address or error("bad argument #1 to 'writewidestring' expected number, got '" .. type(address) .. "'")
  508.     if str then
  509.         offset = type(offset) == "number" and offset or error("bad argument #2 to 'writewidestring' expected number, got '" .. type(offset) .. "'")
  510.         str = type(str) == "string" and str or error("bad argument #3 to 'writewidestring' expected string, got '" .. type(str) .. "'")
  511.     else
  512.         str = type(offset) == "string" and offset or error("bad argument #2 to 'writewidestring' expected string, got '" .. type(offset) .. "'")
  513.         offset = nil
  514.     end
  515.     address = address + (offset or 0x0)
  516.     local byte_table = {}
  517.     local byte = string.byte
  518.     for char in string.gmatch(str, '.') do
  519.         byte_table[#byte_table+1] = byte(char)
  520.     end
  521.     local length = #byte_table
  522.     while i < length do
  523.         -- quickens write calls (screw you oxide for using virtualprotect)
  524.         if i % 4 == 0 and length - i >= 4 then
  525.             writedword(address + i, tonumber((byte_table[i+2]*100) .. (byte_table[i+1]*100)))
  526.             i = i + 2
  527.         else
  528.             writeword(address + i, byte_table[i+1])
  529.             i = i + 1
  530.         end
  531.     end
  532. end
  533.  
  534. -- crash prevention code.
  535. local function createobject(mapId, ...)
  536.     if mapId and mapId ~= 0 and mapId ~= -1 then
  537.         return _G.createobject(mapId, ...)
  538.     end
  539. end
  540.  
  541. local function getteam(playerId)
  542.     if defaults.multiteam_vehicles or not team_play then
  543.         return playerId
  544.     end
  545.     return _G.getteam(playerId)
  546. end
  547.  
  548. -- Get Unused Table if available.
  549. function TM.New()
  550.  
  551.     local unused_tables = TM.unused_tables
  552.     local length = #unused_tables
  553.     local t = unused_tables[length]
  554.     if t then
  555.         -- use an unused table
  556.         unused_tables[length] = nil
  557.         t:deleteEntries()
  558.     else
  559.         -- no tables available, make a new one
  560.         t = setmetatable({}, TM)
  561.     end
  562.  
  563.     return t
  564. end
  565.  
  566. local function validate_ipv4(ip)
  567.     if not ip then return nil end
  568.     ip = gsub(gsub(ip, "[%s]*", ""), "x+", "*")
  569.     local a,b,c,slash,d,finish = match(ip, "^([^%.]+)%.([^%.]*)%.?([^%./]*)%.?(/?)([^%.]*)()")
  570.     a = a == "" and "*" or match(a or "", "[%d%*]+")
  571.     b = b == "" and "*" or match(b or "", "[%d%*]+")
  572.     c = c == "" and "*" or match(c or "", "[%d%*]+")
  573.     slash = slash ~= ""
  574.     d = d or ""
  575.     --print("IP VALIDATION I:",a,b,c,d,slash,finish)
  576.     if slash then
  577.         if d:find("/") or not match(d, "[%d%*]+") then return false end -- can't have two slashes
  578.         d = "0/"..d -- Alternate form 194.1.4/24
  579.     else
  580.         d = d == "" and "*" or match(d, "[%d%*/]+")
  581.     end
  582.  
  583.     if not a or not b or not c then
  584.         return false -- bad ip
  585.     end
  586.  
  587.     local found,a2,b2,c2,d2 = match(ip, "(%-)(%d+)%.(%d*)%.?(%d*)%.?(%d*)%c*$", finish)
  588.     --print("IP VALIDATION II:",found,a2,b2,c2,d2)
  589.     if not found then
  590.         if a2 and a ~= "" then return false end -- this should just never happen lol
  591.         return format("%s.%s.%s.%s",a,b,c,d)
  592.     elseif slash then
  593.         return false -- can't have a slash, and an iplimit.. lol
  594.     end
  595.     a2 = a2 == "" and "*" or match(a2, "[%d%*]+")
  596.     b2 = b2 == "" and "*" or match(b2, "[%d%*]+")
  597.     c2 = c2 == "" and "*" or match(c2, "[%d%*]+")
  598.     d2 = d2 == "" and "*" or match(d2, "[%d%*]+")
  599.  
  600.     if not a2 or not b2 or not c2 then
  601.         return false -- bad ip
  602.     end
  603.  
  604.     if c2:find("/") and d2:find("/") then return false end
  605.     return format("%s.%s.%s.%s-%s.%s.%s.%s", a,b,c,d,a2,b2,c2,d2)
  606. end
  607.  
  608. local function check_ip(ip)
  609.     local i = 1
  610.     local octets = 1
  611.     local octet = ""
  612.     local err = ""
  613.     local errors = 0
  614.     local blocks = {}--TM.New()
  615.     local c, block
  616.     while (i <= #ip + 1) do
  617.         c = sub(ip, i, i)
  618.         if c == "." or #ip+1 == i then
  619.             octets = octets + 1
  620.             block = tonumber(octet)
  621.             if not block or block > 255 or block < 0 or octets > 5 then
  622.                 errors = errors + 1
  623.                 err = err .. " \f3>" .. (block or "?") .. "<\f8"
  624.             else
  625.                 blocks[#blocks+1] = octet
  626.                 err = err .. "\f0 " .. block .. "\f8"
  627.             end
  628.             octet = ""
  629.         else
  630.             octet = octet .. c
  631.         end
  632.         i = i + 1
  633.     end
  634.  
  635.     local result = {}--TM.New()
  636.     result[1] = err
  637.  
  638.     if errors > 0 then
  639.         return result
  640.     end
  641.  
  642.     result[2] = blocks
  643.     return result
  644. end
  645.  
  646. local function ip2long(ip_addr)
  647.     local blocks = check_ip(ip_addr)[2] or error("Invalid IP-Address. IP_ADDR: " .. tostring(ip_addr) .. "\r\nError: " .. check_ip(ip_addr)[1])
  648.     local a = bit32.lshift(blocks[1], 24)
  649.     local b = #blocks >= 2 and bit32.lshift(blocks[2], 16)
  650.     local c = #blocks >= 3 and bit32.lshift(blocks[3], 8)
  651.     if not b or not c then return nil end
  652.     return bit32.bor(bit32.bor(a, b, c), blocks[4])
  653. end
  654.  
  655. local function convertSign(num, maxSize)
  656.     return num - bit32.band(num, maxSize)*2
  657. end
  658.  
  659. local function long2ip(addr)
  660.     addr = tonumber(addr) or error("Invalid 32-bit Long: " .. addr)
  661.     local a = bit32.rshift(bit32.band(addr, bit32.lshift(0xFF, 24)), 24)
  662.     local b = bit32.rshift(bit32.band(addr, bit32.lshift(0xFF, 16)), 16)
  663.     local c = bit32.rshift(bit32.band(addr, bit32.lshift(0xFF, 8)), 8)
  664.     local d = bit32.band(addr, 0xFF)
  665.     return format("%i.%i.%i.%i", convertSign(a, 255), convertSign(b, 255), convertSign(c, 255), convertSign(d, 255))
  666. end
  667.  
  668. local function netMatch(network, ip)
  669.     network = validate_ipv4(network)
  670.     if not network then return end
  671.    
  672.     -- if no ip to check, then just validate the network.
  673.     if not ip then return network end
  674.    
  675.     ip = validate_ipv4(ip)
  676.  
  677.     local orig_network = network
  678.     if ip == network then
  679.         --print("used network " .. network .. " for ip " .. ip)
  680.         return network
  681.     end
  682.     network = gsub(network, ' ', '')
  683.     if find(network, '*') then
  684.         if find(network, '/') then
  685.             network = tokenizestring(network, '/')[1]
  686.         end
  687.         local nCount
  688.         network, nCount = gsub(network, '*', '*')
  689.         network = gsub(network, '*', '0')
  690.         if nCount == 1 then
  691.             network = network .. '/24'
  692.         elseif nCount == 2 then
  693.             network = network .. '/16'
  694.         elseif nCount == 3 then
  695.             network = network .. '/8'
  696.         elseif nCount > 3 then
  697.             return network -- if *.*.*.*, then all, so matched
  698.         end
  699.     end
  700.  
  701.     if find(ip, '*') then
  702.         if find(ip, '/') then
  703.             ip = tokenizestring(ip, '/')[1]
  704.         end
  705.         local nCount
  706.         ip, nCount = gsub(ip, '*', '*')
  707.         ip = gsub(ip, '*', '0')
  708.         if nCount == 1 then
  709.             ip = ip .. '/24'
  710.         elseif nCount == 2 then
  711.             ip = ip .. '/16'
  712.         elseif nCount == 3 then
  713.             ip = ip .. '/8'
  714.         elseif nCount > 3 then
  715.             return ip -- if *.*.*.*, then all, so matched
  716.         end
  717.     end
  718.  
  719.     --print("from original network " .. orig_network .. ", used network " .. network .. " for " .. ip)
  720.  
  721.     local d = find(network, '-')
  722.     if not d then
  723.         local ip_arr = tokenizestring(network, "/")
  724.         local network_long = ip2long(ip_arr[1])
  725.         local mask = bit32.lshift(0xFFFFFFFF, (32 - (ip_arr[2] or 32)))
  726.         local ip_arr2 = tokenizestring(ip, "/")
  727.         local ip_long = ip2long(ip_arr2[1])
  728.         local mask2 = bit32.lshift(0xFFFFFFFF, (32 - (ip_arr2[2] or 32)))
  729.         return bit32.band(network_long, mask, mask2) == bit32.band(ip_long, mask, mask2)
  730.     else
  731.         local from = ip2long(sub(network, 1, d-1))
  732.         local to = ip2long(sub(network, d+1))
  733.         ip = ip2long(ip)
  734.         return ip >= from and ip <= to
  735.     end
  736. end
  737.  
  738. local function iptoplayer(ip)
  739.     for playerId = 0,15 do
  740.         if getplayer(playerId) and netMatch(getip(playerId) .. "/24", ip) then
  741.             return playerId
  742.         end
  743.     end
  744. end
  745.  
  746. local function getobject(objectId)
  747.     return objectId and _G.getobject(objectId) or nil
  748. end
  749.  
  750. -- hides a phasor bug where player 1 gets output from privatesay in their console...
  751. local function privatesay(playerId, message, appendServer)
  752.     _G.privatesay(playerId, message, appendServer)
  753.     if getplayer(0) then
  754.         sendconsoletext(0, " \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ")
  755.     end
  756. end
  757.  
  758. local function privateSayAdmins(message)
  759.     for playerId = 0,15 do
  760.         if getplayer(playerId) and PlayerClass[playerId].admin_entry then
  761.             sendconsoletext(playerId, message)
  762.             privatesay(playerId, message)
  763.         end
  764.     end
  765. end
  766.  
  767. local function getname(playerId)
  768.     return playerId and _G.getname(playerId) or "the Server"
  769. end
  770.  
  771. local function getMorePowerfulAdmin(adminEntry1, adminEntry2)
  772.     local access1 = #access_table[adminEntry1.level]
  773.     local access2 = #access_table[adminEntry2.level]
  774.     return access1 > access2 and adminEntry1 or access1 < access2 and adminEntry2 or access1 > 0
  775. end
  776.  
  777. local function lookupAdminEntry(playerId)
  778.     local ip = getip(playerId)
  779.     local retIndex = gethash(playerId)
  780.     local highestEntry = admin_table[retIndex]
  781.     local morePowerfulAdmin
  782.     for index,thisAdmin in next,admin_table do
  783.         if thisAdmin.type == "ip" and netMatch(index, ip) then
  784.             morePowerfulAdmin = highestEntry and getMorePowerfulAdmin(thisAdmin, highestEntry) or thisAdmin
  785.             if type(morePowerfulAdmin) == "table" then
  786.                 highestEntry = morePowerfulAdmin
  787.                 retIndex = index
  788.             end
  789.         end
  790.     end
  791.     return highestEntry, highestEntry and retIndex
  792. end
  793.  
  794. -- Table Methods and Metamethods.
  795.  
  796. function getOrCreateIdentities(hash, ip, name, playerId) -- arguments: hash, ip, name, playerId
  797.     local length, probably_unique_name, ip_addresses, names, hash_identity, ip_identity, name_identity
  798.    
  799.     hash_identity = identities[hash]
  800.     ip_identity = identities[ip]
  801.     name_identity = identities[name]
  802.    
  803.     -- check the ip range to see if it matches an already existing entry.
  804.     if not ip_identity then
  805.         for ip_key,v in next,identities do
  806.             if validate_ipv4(ip_key) and netMatch(ip, ip_key) then
  807.                 ip_identity = identities[ip_key]
  808.                 break
  809.             end
  810.         end
  811.     end
  812.    
  813.     if hash_identity then
  814.         if not ip_identity then
  815.             ip_addresses = hash_identity.ip_addresses
  816.             length = #ip_addresses+1
  817.             ip_addresses[length]    = ip
  818.             ip_addresses[ip]        = length
  819.             for i = 1,#ip_addresses do
  820.                 ip_identity = identities[ip_addresses[i]]
  821.                 if ip_identity then
  822.                     identities[ip] = ip_identity
  823.                     break
  824.                 end
  825.             end
  826.         end
  827.         if not name_identity then
  828.             names = hash_identity.names
  829.             length = #names+1
  830.             names[length]   = name
  831.             names[name]     = length
  832.             for i = 1,#names do
  833.                 name_identity = identities[names[i]]
  834.                 if name_identity then
  835.                     identities[name] = name_identity
  836.                     break
  837.                 end
  838.             end
  839.         end
  840.         hash_identity.playerId = playerId
  841.     end
  842.     if ip_identity then
  843.         if not hash_identity and not sharedhashes[hash] then
  844.             hash_identity = identities[ip]
  845.             identities[hash] = hash_identity
  846.             identities[ip].hash = hash
  847.         end
  848.         if not name_identity and not randomNames[name] then
  849.             names = ip_identity.names
  850.             length = #names+1
  851.             names[length]   = name
  852.             names[name]     = length
  853.             for i = 1,#names do
  854.                 name_identity = identities[names[i]]
  855.                 if name_identity then
  856.                     identities[name] = name_identity
  857.                     break
  858.                 end
  859.             end
  860.         end
  861.         ip_identity.playerId = playerId
  862.     end
  863.     if name_identity then
  864.  
  865.         if not hash_identity and not sharedhashes[hash] then
  866.             hash = name_identity.hash
  867.             hash_identity = identities[hash]
  868.             identities[hash] = hash_identity
  869.         end
  870.         if not ip_identity then
  871.             ip_addresses = hash_identity.ip_addresses
  872.             length = #ip_addresses+1
  873.             ip_addresses[length]    = ip
  874.             ip_addresses[ip]        = length
  875.             for i = 1,#ip_addresses do
  876.                 ip_identity = identities[ip_addresses[i]]
  877.                 if ip_identity then
  878.                     identities[ip] = ip_identity
  879.                     break
  880.                 end
  881.             end
  882.         end
  883.         name_identity.playerId = playerId
  884.     end
  885.    
  886.     ::CreateIdentity::
  887.     --Create a new identity for this new player.
  888.     if not ip_identity then
  889.         identity                = {playerId = playerId}
  890.         --identity.index        = identifier
  891.         identity.hash           = sharedhashes[hash] and {} or hash
  892.         identity.ip_addresses   = {ip, [ip] = 1}
  893.         identity.names          = randomNames[name] and {} or {name, [name] = 1}
  894.        
  895.         identities[hash]    = identity
  896.         identities[ip]      = identity
  897.         identities[name]    = identity
  898.        
  899.         identity.disarmed           = false
  900.         identity.tempadmin          = false
  901.         identity.spamcounter        = 0
  902.         identity.rcon_fails         = 0
  903.         identity.rconfail_timer     = -1
  904.         identity.muted              = false
  905.         identity.playerId           = playerId
  906.        
  907.         -- Calculate unique identity id by count.
  908.         identities[#identities+1] = identity
  909.        
  910.         --registered_names[name] = identity -- automatically register this name to this Hash/IP
  911.    
  912.         return identity, identity, identity
  913.     end
  914.     return hash_identity, ip_identity, name_identity
  915. end
  916.  
  917. -- Not currently using this, if I remember correctly.
  918. --[[function PlayerClass:__newindex(key, value)
  919.     if rawget(self, key) ~= nil then
  920.         rawset(self, key, value)
  921.         return
  922.     end
  923.    
  924.     local hash_identity = identities[rawget(self, "hash")]
  925.     if hash_identity then rawset(hash_identity, key, value) end
  926.    
  927.     local ip_identity = identities[rawget(self, "ip")]
  928.     if ip_identity then rawset(ip_identity, key, value) end
  929.    
  930.     local name_identity = identities[rawget(self, "name")]
  931.     if name_identity then rawset(name_identity, key, value) end
  932. end--]]
  933.  
  934. function PlayerClass:__index(key)
  935.     --hprintf(TM.__tostring(PlayerClass[2]))
  936.     local identity = rawget(self, "hash_identity") or rawget(identities, rawget(self, "hash"))
  937.     if identity then
  938.         return rawget(identity, key)
  939.     end
  940.    
  941.     local fallback_identity = rawget(self, "ip_identity") or rawget(identities, rawget(self, "ip"))
  942.     if fallback_identity then
  943.         return rawget(fallback_identity, key)
  944.     end
  945.    
  946.     identity = rawget(self, "name_identity") or rawget(identities, rawget(self, "name"))
  947.     if identity then
  948.         return rawget(identity, key)
  949.     end
  950.    
  951.     -- This will be used if all player identifiers are not unique
  952.     return rawget(fallback_identity, key)
  953. end
  954.  
  955. function PlayerClass:Initialize(playerId)
  956.     local player = rawget(PlayerClass, playerId)
  957.     local hash, ip, name = gethash(playerId), getip(playerId), getname(playerId)
  958.    
  959.     rawset(player, "admin_entry", lookupAdminEntry(playerId) or false)
  960.    
  961.     player.drones:deleteEntries()
  962.    
  963.     rawset(player, "hash", hash)
  964.     rawset(player, "ip", ip)
  965.     rawset(player, "name", name)
  966.    
  967.     -- Update our identities.
  968.     local hash_identity, ip_identity, name_identity = getOrCreateIdentities(hash, ip, name, playerId)
  969.  
  970.     rawset(player, "hash_identity", hash_identity)
  971.     rawset(player, "ip_identity", ip_identity)
  972.     rawset(player, "name_identity", name_identity)
  973.    
  974.     rawset(player, "afk", false)
  975.     rawset(player, "bulletmode", false)
  976.     rawset(player, "colorspawn", false)
  977.     rawset(player, "crouch", false)
  978.     rawset(player, "dmgmultiplier", 1)
  979.     rawset(player, "godmode", false)
  980.     rawset(player, "ghostmode", false)
  981.     rawset(player, "invisible", false)
  982.     rawset(player, "hidden", false)
  983.     rawset(player, "objspawnid", false)
  984.     rawset(player, "player_struct", getplayer(playerId) or false)
  985.     rawset(player, "playerId", playerId)
  986.     rawset(player, "playerIndex", resolveplayer(playerId) or -1)
  987.     rawset(player, "tbagname", "")
  988.     rawset(player, "x", 0)
  989.     rawset(player, "y", 0)
  990.     rawset(player, "z", 0)
  991.     return player
  992. end
  993.  
  994. local function GetGameAddresses(game)
  995.     if _SERVERAPP == "Sapp" then
  996.         addresses = { -- check these against the module to confirm they're all the same (these should take preference)
  997.             stats_globals = read_dword(sig_scan("33C0BF??????00F3AB881D") + 0x3), -- Confirmed. (Thanks Giraffe)
  998.             ctf_globals = read_dword(sig_scan("C6000083C0303D??????00")+8), -- Confirmed.
  999.             slayer_globals = read_dword(sig_scan("5733C0B910000000BFE8E05B00F3ABB910000000") + 19), -- Confirmed,
  1000.             oddball_globals = read_dword(sig_scan("BF??????00F3ABB951000000")+0x1), -- Confirmed.
  1001.             koth_globals = read_dword(sig_scan("BF??????00F3ABB96B000000")+0x1), -- Confirmed.
  1002.             race_globals = read_dword(sig_scan("BF??????00F3ABB952000000")+0x1), -- Confirmed.
  1003.             race_locs = 0x5F5078,
  1004.             gametype_base = read_dword(sig_scan("B9360000008BF3BF78545F00")+0x8), -- Confirmed.
  1005.             network_struct = read_dword(sig_scan("F3ABA1????????BA????????C740??????????E8????????668B0D") + 3),
  1006.             player_header_pointer = read_dword(sig_scan("DDD8A1??????008944244835") + 0x3), -- Confirmed (Thanks Giraffe)
  1007.             object_header_pointer = read_dword(sig_scan("8B0D????????8B513425FFFF00008D") + 2), -- Confirmed. (Thanks 002)
  1008.             collideable_objects_pointer = 0x6C69F4,
  1009.             map_header_base = 0x6E2C84,
  1010.             banlist_header = read_dword(sig_scan("A3??????00A1??????0033DB3BC3")+1), -- Confirmed.
  1011.             game_globals = nil, -- Don't care.
  1012.             gameinfo_header = read_dword(sig_scan("A1????????8B480C894D00") + 0x1), -- Confirmed. (Thanks Wizard)
  1013.             mapcycle_header = 0x598A8C,
  1014.             network_server_globals = 0x61FB44,
  1015.             hash_table_base = 0x5AFB14, -- Untested.
  1016.            
  1017.             -- Strings (Thanks to Giraffe for all the sigs in this section!)
  1018.             broadcast_version_address = read_dword(sig_scan("751768??????0068??????00BA") + 0x3), -- Confirmed.
  1019.             version_info_address = nil, -- Don't care.
  1020.             broadcast_game_address = read_dword(sig_scan("CCCCBA??????002BD08A08") + 0x3), -- Confirmed (halor = PC, halom = CE)
  1021.             server_ip_argument = read_dword(sig_scan("BA??????008BC72BD78A08880C024084C975F68B442404") + 0x1), -- Confirmed.
  1022.             server_port_address = read_dword(sig_scan("668B0D??????000BF2C605") + 0x3), -- Confirmed.
  1023.             server_path_address = read_dword(sig_scan("0000BE??????005657C605") + 0x3), -- Confirmed.
  1024.             computer_name_address = read_dword(sig_scan("68??????0068??????0068000401006A00") + 0x1), -- Confirmed
  1025.             profile_path_address = read_dword(sig_scan("68??????008D54245468") + 0x1), -- Confirmed.
  1026.             map_name_address =read_dword(sig_scan("66A3??????00890D??????00C3") + 0x2), -- Confirmed. (Full name)
  1027.             hardware_info_address = read_dword(sig_scan("BE??????008BC68B4DF064890D000000005F5E5B8BE55DC36A0C") + 0x1), -- Confirmed.
  1028.            
  1029.             map_name_address2 = read_dword(sig_scan("B8??????00E8??????0032C983F813") + 0x1), -- Confirmed. (File name)
  1030.             server_password_address = read_dword(sig_scan("F3ABA3??????00A3??????00A2??????00C705") + 0x3), -- Confirmed.
  1031.             logfile_path_address = read_dword(sig_scan("740ABB????5C00E8????0300") + 0x3), -- Confirmed. (CE Only)
  1032.             banlist_path_address = read_dword(sig_scan("68??????00E8??????0083C41068") + 0x1), -- Confirmed.
  1033.             banlist_path_address2 = read_dword(sig_scan("CCCCC605??????0000E8??????0085C0") + 0x4), -- Confirmed.
  1034.             --Patches
  1035.             rcon_password_address = read_dword(sig_scan("7740BA??????008D9B000000008A01") + 0x3), -- Confirmed.
  1036.             rcon_failed_address = read_dword(sig_scan("B8????????E8??000000A1????????55") + 1), -- Found by 002
  1037.             kill_message_address = read_dword(sig_scan("8B42348A8C28D500000084C9") + 3), -- Found by sehe (Write to 0x03EB01B1)
  1038.             color_patch1 = read_dword(sig_scan("741F8B482085C9750C")), -- Found by 002 (Write to 235 if not 0)
  1039.             color_patch2 = read_dword(sig_scan("EB1F8B482085C9750C")), -- Found by 002 (Write to 235)
  1040.             nonslayer_score_patch = sig_scan("8B??3883C404????74??57FFD0")+0x8, -- 0xEB = patched, 0x74 = normal
  1041.             slayer_score_patch = sig_scan("74178B94242808000052518B8C24280800005157FFD083C4108B8424240800003BF8530F94C383FFFF") -- 0xEB = patched, 0x74 = normal
  1042.         }
  1043.         --[[while true do
  1044.             cprint("nonslayer: " .. tostring(addresses.nonslayer_score_patch) .. " slayer: " .. tostring(addresses.slayer_score_patch))
  1045.         end--]]
  1046.     elseif game == "PC" then
  1047.         addresses = {
  1048.             -- Structs/headers.
  1049.             stats_header = 0x639720,
  1050.             stats_globals = 0x639898,
  1051.             ctf_globals = 0x639B98,
  1052.             slayer_globals = 0x63A0E8,
  1053.             oddball_globals = 0x639E58,
  1054.             koth_globals = 0x639BD0,
  1055.             race_globals = 0x639FA0,
  1056.             race_locs = 0x670F40,
  1057.             gametype_base = 0x671340,
  1058.             network_struct = 0x745BA0,
  1059.             camera_base = 0x69C2F8,
  1060.             player_header_pointer = 0x75ECE4,
  1061.             obj_header_pointer = 0x744C18,
  1062.             collideable_objects_pointer = 0x744C34,
  1063.             map_header_base = 0x630E74,
  1064.             banlist_header = 0x641280,
  1065.             game_globals = "???", -- (???) Why do I not have this for PC?
  1066.             gameinfo_header = 0x671420,
  1067.             mapcycle_header = 0x614B4C,
  1068.             network_server_globals = 0x69B934,
  1069.             sockaddr_pointer = 0x6A1F08,
  1070.             flags_pointer = 0x6A590C,
  1071.             hash_table_base = 0x6A2AE4,
  1072.  
  1073.             -- String/Data Addresses.
  1074.             init_file_address = 0x8EB38,
  1075.             broadcast_version_address = 0x5DF840,
  1076.             version_info_address = 0x5E02C0,
  1077.             broadcast_game_address = 0x5E4768,
  1078.             mapcycle_timeout = 0x614AC0,
  1079.             public_value_address = 0x6164C0,
  1080.             server_port_address = 0x625230,
  1081.             timelimit_address = 0x626630,
  1082.             server_path_address = 0x62C390,
  1083.             computer_name_address = 0x62CD60,
  1084.             profile_path_address = 0x635610,
  1085.             map_name_address = 0x63BC78,
  1086.             computer_specs_address = 0x662D04,
  1087.             map_name_address2 = 0x698F21,
  1088.             server_password_address = 0x69B93C,
  1089.             banlist_path_address = 0x69B950,
  1090.             rcon_password_address = 0x69BA5C,
  1091.  
  1092.             -- Patches
  1093.             nonslayer_score_patch = 0x47F382, -- 0xEB = patched, 0x74 = normal
  1094.             slayer_score_patch = 0x47F5D5, -- 0xEB = patched, 0x74 = normal
  1095.             ctf_msgs_patch = 0x481545, -- 0xEB = patched, 0x74 = normal
  1096.             color_patch = 0x4828FE, -- 0xEB = patched, 0x74 = normal
  1097.             devmode_patch1 = 0x4A4DBF, -- 0xEB = patched, 0x74 = normal
  1098.             devmode_patch2 = 0x4A4E7F, -- 0xEB = patched, 0x74 = normal
  1099.             servername_patch = 0x517D6B, -- 0x9090 = patched, 0x4B74 = normal
  1100.             hash_duplicate_patch = 0x59C518, -- 0x9090 = patched, 0xFD3B = normal
  1101.             hashcheck_patch = 0x59c280, -- 0xEB = patched, 0x74 = normal
  1102.             versioncheck_patch = 0x5152E7 -- 0xEB = patched, 0x7D = normal
  1103.         }
  1104.     elseif game == "CE" then
  1105.         addresses = {
  1106.             -- Structs/headers.
  1107.             stats_header = 0x5BD740,
  1108.             stats_globals = 0x5BD8B8,
  1109.             ctf_globals = 0x5BDBB8,
  1110.             slayer_globals = 0x5BE108,
  1111.             oddball_globals = 0x5BDE78,
  1112.             koth_globals = 0x5BDBF0,
  1113.             race_globals = 0x5BDFC0,
  1114.             race_locs = 0x5F5098,
  1115.             gametype_base = 0x5F5498,
  1116.             network_struct = 0x6C7980,
  1117.             camera_base = 0x62075C,
  1118.             player_globals = 0x6E1478, -- From OS.
  1119.             player_header_pointer = 0x6E1480,
  1120.             obj_header_pointer = 0x6C69F0,
  1121.             collideable_objects_pointer = 0x6C6A14,
  1122.             map_header_base = 0x6E2CA4,
  1123.             banlist_header = 0x5C52A0,
  1124.             game_globals = 0x61CFE0, -- (???)
  1125.             gameinfo_header = 0x5F55BC,
  1126.             mapcycle_header = 0x598A8C,
  1127.             network_server_globals = 0x61FB64,
  1128.             sockaddr_pointer = 0x626388,
  1129.             hash_table_base = 0x5AFB34,
  1130.  
  1131.             -- String/Data Addresses.
  1132.             init_file_address = 0x8EB26,
  1133.             broadcast_version_address = 0x564B34,
  1134.             version_info_address = 0x565104,
  1135.             broadcast_game_address = 0x569EAC,
  1136.             mapcycle_timeout = 0x598A00,
  1137.             public_value_address = 0x59A424,
  1138.             server_port_address = 0x5A91A0,
  1139.             timelimit_address = 0x5AA5B0,
  1140.             server_path_address = 0x5B0670,
  1141.             computer_name_address = 0x5B0D40,
  1142.             profile_path_address = 0x5B9630,
  1143.             map_name_address = 0x5BFC98,
  1144.             computer_specs_address = 0x5E6E5C,
  1145.             map_name_address2 = 0x61D151,
  1146.             server_password_address = 0x61FB6C,
  1147.             banlist_path_address = 0x61FB80,
  1148.             rcon_password_address = 0x61FC8C,
  1149.  
  1150.             -- Patches
  1151.             nonslayer_score_patch = 0x45BCB0, -- 0xEB = patched, 0x74 = normal
  1152.             slayer_score_patch = 0x45BE15, -- 0xEB = patched, 0x74 = normal
  1153.             ctf_msgs_patch = 0x45DA95, -- 0xEB = patched, 0x74 = normal
  1154.             color_patch = 0x45EB5E, -- 0xEB = patched, 0x74 = normal
  1155.             devmode_patch1 = 0x47DF0C, -- 0xEB = patched, 0x74 = normal
  1156.             devmode_patch2 = 0x47DFBC, -- 0xEB = patched, 0x74 = normal
  1157.             servername_patch = 0x4CE0CD, -- 0x9090 = patched, 0x4B74 = normal
  1158.             hash_duplicate_patch = 0x5302E8, -- 0x9090 = patched, 0xFD3B = normal
  1159.             hashcheck_patch = 0x530130, -- 0xEB = patched, 0x74 = normal
  1160.             versioncheck_patch = 0x4CB587, -- 0xEB = patched, 0x7D = normal
  1161.         }
  1162.     end
  1163. end
  1164.  
  1165. -- This is my ingenius way to execute a command and bypass ALL of my code.
  1166. -- So I can do sv_kick without having to worry about creating an infinite loop.
  1167. local function halo_svcmd(command, retBool)
  1168.     dont_call_onservercommand = true
  1169.     --print("BEFORE HALO_SVCMD")
  1170.     local response = svcmd(command, retBool)
  1171.     --print("AFTER HALO_SVCMD")
  1172.     dont_call_onservercommand = false
  1173.     return retBool and response
  1174. end
  1175.  
  1176. local function halo_svcmdplayer(command, playerId, retBool)
  1177.     dont_call_onservercommand = true
  1178.     --print "BEFORE HALO_SVCMDPLAYER"
  1179.     local response = svcmdplayer(command, playerId, retBool)
  1180.     --print "AFTER HALO_SVCMDPLAYER"
  1181.     dont_call_onservercommand = false
  1182.     return retBool and response
  1183. end
  1184.  
  1185. local function svcmd(command, retBool)
  1186.     --print "BEFORE SVCMD"
  1187.     if OnServerCommandAttempt(nil, command) ~= false then
  1188.         --print "AFTER SVCMD"
  1189.         return _G.svcmd(command, retBool)
  1190.     end
  1191. end
  1192.  
  1193. local function svcmdplayer(command, playerId, retBool)
  1194.     --print("BEFORE SVCMDPLAYER)
  1195.     if OnServerCommandAttempt(playerId, command) ~= false and OnServerCommand(playerId, command) ~= false then
  1196.         --print("AFTER SVCMDPLAYER)
  1197.         return halo_svcmd(command, retBool) or ""
  1198.     end
  1199. end
  1200.  
  1201.  
  1202. math.randomseed(ceil(os.clock()) + os.time())
  1203. local getsuckyrand = math.random
  1204. getsuckyrand(1, 10) getsuckyrand(1, 10) getsuckyrand(1, 10)
  1205. --Low and High are INCLUSIVE.
  1206. local function rand(low, high)
  1207.  
  1208.     low = assert(tonumber(low), "bad argument #1 to 'rand' (number expected, got " .. type(low) .. ")")
  1209.     high = assert(tonumber(high), "bad argument #2 to 'rand' (number expected, got " .. type(high) .. ")")
  1210.  
  1211.     return getsuckyrand(low, high)
  1212. end
  1213. local getrandomnumber = rand
  1214.  
  1215. -- I am having weird issues with resolveplayer not working correctly, so I'm overriding it.
  1216. local function resolveplayer(playerId)
  1217.     return playerId and PlayerClass[playerId].playerIndex
  1218. end
  1219.  
  1220. -- This function will get the XYZ coordinates of an object, and return them as 3 separate variables.
  1221. -- It will also determine if the object has a parent (i.e player in a vehicle) and return those coords instead.
  1222. -- I don't trust Phasor's getobjectcoords, and this way I know exactly how it will work.
  1223. local function getobjectcoords(objectId)
  1224.     local m_object = getobject(objectId)
  1225.     local vehicleObjId = readdword(m_object + 0x11C)
  1226.     local m_vehicleObj = getobject(vehicleObjId)
  1227.  
  1228.     -- Replace m_object with vehicle object struct (if there is one)
  1229.     m_object = m_vehicleObj or m_object
  1230.  
  1231.     return readfloat(m_object + 0x5C),readfloat(m_object + 0x60),readfloat(m_object + 0x64)
  1232. end
  1233.  
  1234. -- This is the same as getplayerobjectid except it returns BOTH the player's object struct and playerObjId
  1235. -- Returns the object struct and the object ID, or nil.
  1236. local function getplayerobject(playerId)
  1237.     local playerObjId = playerObjId or getplayerobjectid(playerId)
  1238.     return getobject(playerObjId), playerObjId
  1239. end
  1240.  
  1241. -- Gets the object ID of the player's vehicle.
  1242. -- Accepts argument 'playerId' (memory ID)
  1243. -- Returns the vehicle's object ID, or nil
  1244. local function getplayervehicleid(playerId)
  1245.     local m_playerObj = getplayerobject(playerId)
  1246.     return m_playerObj and readdword(m_playerObj + 0x11C)
  1247. end
  1248.  
  1249. -- This is the same as getplayervehicleid except it returns BOTH the vehicle's object struct and vehicleObjId.
  1250. -- Returns the vehicle's object struct and vehicle's object ID, or nil.
  1251. local function getplayervehicle(playerId)
  1252.     local vehicleObjId = getplayervehicleid(playerId)
  1253.     return getobject(vehicleObjId), vehicleObjId
  1254. end
  1255.  
  1256. -- Gets the object ID of the player's weapon.
  1257. -- Accepts arguments 'playerId' (memory ID) and 'slot' (weapon slot) which is a number from 0 to 3.
  1258. -- Slot is an optional argument. If not passed, then getplayerweaponid returns player's current weapon ID.
  1259. -- Returns the weapon's object ID, or 0xFFFFFFFF if no weapon, or nil if the player is dead
  1260. local function getplayerweaponid(playerId, slot)
  1261.  
  1262.     local m_playerObj = getplayerobject(playerId)
  1263.  
  1264.     if not m_playerObj then
  1265.         return
  1266.     end
  1267.  
  1268.     -- Return vehicle's weapon if they are in a vehicle.
  1269.     local m_vehicleObj = getplayervehicle(playerId)
  1270.     if m_vehicleObj then
  1271.         return readdword(m_vehicleObj + 0x2F8)
  1272.     end
  1273.  
  1274.     -- Return current weapon if no slot passed.
  1275.     if not slot then
  1276.         return readdword(m_playerObj + 0x118)
  1277.     end
  1278.  
  1279.     -- Return weapon at the specified slot.
  1280.     return readdword(m_playerObj + 0x2F8 + slot*4)
  1281. end
  1282.  
  1283. -- This is the same as getplayerweaponid except it returns BOTH the weapon's object struct and weaponObjId.
  1284. -- Returns the weapon's object struct and weapon's object ID, or nil.
  1285. local function getplayerweapon(playerId, slot)
  1286.     local weaponObjId = getplayerweaponid(playerId, slot)
  1287.     return getobject(weaponObjId), weaponObjId
  1288. end
  1289.  
  1290. -- This function will determine if the given playerId is currently in a vehicle or not.
  1291. -- This function will return a boolean.
  1292. -- This function was created because I was having problems with Phasor's isinvehicle function.
  1293. local function isinvehicle(playerId)
  1294.     return not not getplayervehicle(playerId)
  1295. end
  1296.  
  1297. local function cleanupdrones(playerId)
  1298.     local player = PlayerClass[playerId]
  1299.     local vehicleObjId
  1300.     for i = 1,#player.drones do vehicleObjId = player.drones[i]
  1301.         if getobject(vehicleObjId) then
  1302.             destroyobject(vehicleObjId)
  1303.         end
  1304.         player.drones[i] = nil
  1305.     end
  1306. end
  1307.  
  1308. local function setspeed(playerId, speed)
  1309.     local m_player = assert(getplayer(playerId), "bad argument #1 to 'setspeed' (valid playerId expected, got '" .. type(playerId) .. "')")
  1310.     speed = assert(tonumber(speed), "bad argument #2 to 'setspeed' (number expected, got '" .. type(speed) .. "')")
  1311.     writefloat(m_player + 0x6C, speed and speed < 999999999999999999999999999999 and speed or 999999999999999999999999999999)
  1312. end
  1313.  
  1314. -- This function will set a player's color
  1315. -- Accepts playerId, and color carried as a number enumerator.
  1316. local function setcolor(playerId, color)
  1317.     local m_player = assert(getplayer(playerId), "bad argument #1 to 'setspeed' (valid playerId expected, got '" .. type(playerId) .. "')")
  1318.     color = assert(tonumber(color), "bad argument #2 to 'setcolor' (number expected, got '" .. type(color) .. "')")
  1319.     writebyte(m_player + 0x60, color)
  1320.  
  1321.     local m_playerObj, playerObjId = getplayerobject(playerId)
  1322.  
  1323.     if not m_playerObj then
  1324.         return
  1325.     end
  1326.    
  1327.     local player = PlayerClass[playerId]
  1328.     local x,y,z = getobjectcoords(playerObjId)
  1329.     player.colorspawn = true
  1330.     player.x,player.y,player.z = x,y,z
  1331.     destroyobject(playerObjId)
  1332. end
  1333.  
  1334.  
  1335. -- This local function gets the player's memory ID from their object struct
  1336. -- Accepts the object ID of the player as an argument
  1337. -- Returns the playerId, or nil.
  1338. local function objectidtoplayer(objectId)
  1339.     local m_object = getobject(objectId)
  1340.     if m_object then
  1341.         local playerId = readword(m_object + 0xC0)
  1342.         local m_player = getplayer(playerId)
  1343.         if m_player then
  1344.             return playerId
  1345.         end
  1346.     end
  1347. end
  1348.  
  1349. --[[ General lua functions ]]--
  1350.  
  1351. local function round(val, place)
  1352.     place = place or 0 return floor(val * (10 ^ place) + 0.5) * (10 ^ -place)
  1353. end
  1354.  
  1355. local function formatTime(time)
  1356.     time = tonumber(time)
  1357.     if time == -1 then
  1358.         return "--"
  1359.     elseif time then
  1360.         local temp = time
  1361.         local centuries = floor(temp / 3153600000)
  1362.         temp = temp - centuries * 3153600000
  1363.         local years = floor(temp / 31536000)
  1364.         temp = temp - years * 31536000
  1365.         local weeks = floor(temp / 604800)
  1366.         temp = temp - weeks * 604800
  1367.         local days = floor(temp / 86400)
  1368.         temp = temp - days * 86400
  1369.         local hours = floor(temp / 3600)
  1370.         temp = temp - hours * 3600
  1371.         local minutes = floor(temp / 60)
  1372.         temp = temp - minutes * 60
  1373.         local seconds = floor(temp)
  1374.         return format("%02d:%02d:%02d:%02d:%02d:%02d", years, weeks, days, hours, minutes, seconds)
  1375.     else
  1376.         return time
  1377.     end
  1378. end
  1379.  
  1380. local function wordtotime(timeStr, bancount)
  1381.     local length = #timeStr
  1382.     local time
  1383.  
  1384.     -- Check if timeStr is in the correct format before we do anything.
  1385.     if tonumber(sub(timeStr, 1, length-1)) and match(sub(timeStr, length, length), "[cywdhms]") then
  1386.         time = 0
  1387.         local num = ""
  1388.         local holder, tempnum, char
  1389.         for i = 1,length do
  1390.             char = sub(timeStr, i, i)
  1391.             if tonumber(char) then
  1392.                 num = num .. char
  1393.             else
  1394.                 tempnum = tonumber(num)
  1395.                 holder = 0
  1396.                 holder = char == "s" and tempnum
  1397.                 holder = char == "m" and tempnum * 60 or holder
  1398.                 holder = char == "h" and tempnum * 3600 or holder
  1399.                 holder = char == "d" and tempnum * 86400 or holder
  1400.                 holder = char == "w" and tempnum * 604800 or holder
  1401.                 holder = char == "y" and tempnum * 31536000 or holder
  1402.                 holder = char == "c" and tempnum * 3153600000 or holder
  1403.                 holder = holder or 1
  1404.                 time = time + holder
  1405.             end
  1406.         end
  1407.         if time > 0 then
  1408.             return time, char
  1409.         end
  1410.     end
  1411.     time = tonumber(timeStr)
  1412.     if time == 0 and bancount then
  1413.         return ban_penalty[bancount], "?"
  1414.     elseif time then
  1415.         return time, "*"
  1416.     end
  1417. end
  1418.  
  1419. local function timetoword(time)
  1420.     time = tonumber(time)
  1421.     if time then
  1422.         local returntime = ""
  1423.         local centuries = floor(time / 3153600000)
  1424.         time = time - centuries * 3153600000
  1425.         local years = floor(time / 31536000)
  1426.         time = time - years * 31536000
  1427.         local weeks = floor(time / 604800)
  1428.         time = time - weeks * 604800
  1429.         local days = floor(time / 86400)
  1430.         time = time - days * 86400
  1431.         local hours = floor(time / 3600)
  1432.         time = time - hours * 3600
  1433.         local minutes = floor(time / 60)
  1434.         time = time - minutes * 60
  1435.         local seconds = floor(time)
  1436.  
  1437.         returntime = seconds > 0 and (seconds == 1 and "1 second" or seconds .. " seconds") or returntime
  1438.         returntime = minutes > 0 and (minutes == 1 and "1 minute" or minutes .. " minutes " .. returntime) or returntime
  1439.         returntime = hours > 0 and (hours == 1 and "1 hour" or hours .. " hours " .. returntime) or returntime
  1440.         returntime = days > 0 and (days == 1 and "1 day" or days .. " days " .. returntime) or returntime
  1441.         returntime = weeks > 0 and (weeks == 1 and "1 week" or weeks .. " weeks " .. returntime) or returntime
  1442.         returntime = years > 0 and (years == 1 and "1 year" or years .. " years " .. returntime) or returntime
  1443.         returntime = centuries > 0 and (centuries == 1 and "1 century" or centuries .. " centuries " .. returntime) or returntime
  1444.         return returntime ~= "" and returntime or "0 seconds"
  1445.     end
  1446. end
  1447.  
  1448. local function getTimeAndReason(timeandreason)
  1449.     local words = tokenizecmdstring(timeandreason)
  1450.     local count = #words
  1451.  
  1452.     local time
  1453.     local reasons = {}--TM.New()
  1454.  
  1455.     local timetypes_used = ""
  1456.     local word, addTime, timetype, reasons_started
  1457.     for i = 1,count do word = words[i]
  1458.         if not reasons_started then
  1459.             addTime, timetype = wordtotime(word)
  1460.             if timetype and (find(timetypes_used, timetype) or find(timetypes_used, "[%?%*]")) then
  1461.                 return "You can only use 1 of each time type (cywdhms)\nIf you specified a number, you cannot specify multiple time arguments.\nCheck the guide for more information"
  1462.             elseif addTime then
  1463.                 time = (time or 0) + addTime
  1464.                 if not find(timetypes_used, timetype) then
  1465.                     timetypes_used = timetypes_used .. timetype
  1466.                 end
  1467.             else
  1468.                 reasons_started = true
  1469.                 reasons[#reasons+1] = word
  1470.             end
  1471.         else
  1472.             reasons[#reasons+1] = word
  1473.         end
  1474.     end
  1475.     return (time or -1), (reasons[2] and concat(reasons, " ") or reasons[1] or "None Given")
  1476. end
  1477.  
  1478. local function gettag(type_or_id, tagname)
  1479.     if tagname then
  1480.         return tag_table[type_or_id] and tag_table[type_or_id][tagname] or nil
  1481.     elseif tag_table[type_or_id] then
  1482.         return tag_table[type_or_id].tag_class, tag_table[type_or_id].tag_name
  1483.     end
  1484. end
  1485.  
  1486. local function getObjType(objectId)
  1487.     local m_object = getobject(objectId)
  1488.     return m_object and readword(m_object + 0xB4) or nil
  1489. end
  1490.  
  1491. local function resetweapons(playerId)
  1492.     if getplayerweapon(playerId) then
  1493.         for slot = 0,3 do
  1494.             local m_weapon, weaponObjId = getplayerweapon(playerId, slot)
  1495.             if m_weapon then
  1496.                 destroyobject(weaponObjId)
  1497.             end
  1498.         end
  1499.     end
  1500.     local obj_tag_id = readdword(true and getplayerobject(playerId)) -- Confirmed with HMT. Tag Meta ID / MapID / TagID.
  1501.     local tag_address = gettagaddress(obj_tag_id)
  1502.     local address_tag_data = readdword(tag_address + 0x14)
  1503.     local number_of_starting_weapons = readdword(address_tag_data, 0x2D8)
  1504.     local tagdata_unit_weapons = readdword(address_tag_data + 0x2D8+0x4)
  1505.     for i = 0,3 do
  1506.         local weapon_mapId = readdword(tagdata_unit_weapons + i*0x24 + 0xC)
  1507.         if weapon_mapId and weapon_mapId ~= 0 then
  1508.             assignweapon(playerId, createobject(weapon_mapId, 0, 60, false, 3, 2, 1))
  1509.         end
  1510.     end
  1511.     --[[local address_starting_profile = readdword(address_tag_data + 0x348 + 0x4)
  1512.     local primary_weapon_mapId = readdword(address_tag_data + 0x348 + 0x4 + 0x28 + 0xC)
  1513.     local secondary_weapon_mapId = readdword(address_tag_data + 0x348 + 0x4 + 0x3C + 0xC)
  1514.     say(tostring(primary_weapon_mapId))
  1515.     if primary_weapon_mapId then
  1516.         assignweapon(playerId, createobject(primary_weapon_mapId, 0, 60, false, 3, 2, 1))
  1517.     end
  1518.     if secondary_weapon_mapId then
  1519.         assignweapon(playerId, createobject(secondary_weapon_mapId, 0, 60, false, 1, 2, 3))
  1520.     end--]]
  1521. end
  1522.  
  1523. local function ResetPlayer(playerId)
  1524.     local player = PlayerClass[playerId]
  1525.     local m_playerObj, playerObjId = getplayerobject(playerId)
  1526.     if playerObjId ~= 0xFFFFFFFF and m_playerObj then
  1527.         player.godmode = false
  1528.         cleanupdrones(playerId)
  1529.         resetweapons(playerId)
  1530.     end
  1531.     player.bulletmode = false
  1532.     player.disarmed = false
  1533.     player.dmgmultiplier = 1
  1534.     player.ghostmode = false
  1535.     player.hidden = false
  1536.     player.objspawnid = false
  1537.     player.suspended = false
  1538. end
  1539.  
  1540. local function remoteBanCheck(ban_entry)
  1541.     local centralbanlist = defaults.remote_bansystem
  1542.     return not centralbanlist or (ban_entry.remote and centralbanlist.mode >= 1 or not ban_entry.remote and centralbanlist.mode ~= 2)
  1543. end
  1544.  
  1545. local function findBanlistEntry(name, hash, ip, bantype)
  1546.     local retBanEntry
  1547.     local cur_time = os.time()
  1548.     for id = 1,#ban_table do ban_entry = ban_table[id]
  1549.         if remoteBanCheck(ban_entry) then
  1550.             if not ban_entry.time or (ban_entry.time == -1 or ban_entry.time > cur_time) then
  1551.                 if not bantype or bantype == ban_entry.type then
  1552.                     if ban_entry.type == "hash" and ban_entry.hash == hash or ban_entry.type == "ip" and netMatch(ban_entry.ip, ip) then
  1553.                         --hprintf("NAME: " .. tostring(ban_entry.name) .. " REMOTECHECK: " .. tostring(remoteBanCheck(ban_entry)) .. " BANENTRY TIME: " .. tostring(ban_entry.time) .. " CURTIME: " .. tostring(cur_time))
  1554.                         return ban_entry
  1555.                     elseif (ban_entry.type == "name" and ban_entry.name == name) or ban_entry.type == "chat" and (ban_entry.hash == hash or netMatch(ban_entry.ip, ip)) then
  1556.                         retBanEntry = ban_entry
  1557.                     end
  1558.                 end
  1559.             end
  1560.         end
  1561.     end
  1562.     if retBanEntry then
  1563.         --hprintf("NAME: " .. tostring(retBanEntry.name) .. " REMOTECHECK: " .. tostring(remoteBanCheck(retBanEntry)) .. " BANENTRY TIME: " .. tostring(retBanEntry.time) .. " CURTIME: " .. tostring(cur_time))
  1564.     end
  1565.     return retBanEntry
  1566. end
  1567.  
  1568. local function punishIfOnBanlist(playerId)
  1569.     local ban_entry = findBanlistEntry(getname(playerId), gethash(playerId), getip(playerId))
  1570.    
  1571.     if ban_entry then
  1572.         if ban_entry.type == "hash" or ban_entry.type == "ip" then
  1573.             tempBanPlayer(resolveplayer(playerId))
  1574.         elseif ban_entry.type == "chat" then
  1575.             PlayerClass[playerId].muted = true
  1576.         elseif ban_entry.type == "name" and ban_entry.name == name then
  1577.             svcmd("sv_kick " .. resolveplayer(playerId) .. " Found on the Name Banlist.")
  1578.         end
  1579.         return true
  1580.     end
  1581.    
  1582.     return false
  1583. end
  1584.  
  1585. local function loadBanTextEntry(line, bantype, filename)
  1586.  
  1587.     -- Sometimes a random blank line appears in the file, let's make sure not to error for those
  1588.     if not match(line, "%g%g%g+") or sub(line, 1, 1) == "#" then
  1589.         return
  1590.     end
  1591.  
  1592.     local t = {}--TM.New()
  1593.     local pos, endline, timestr, formatBantype, count, unique_index
  1594.  
  1595.     -- create a new table for the ban entry
  1596.     local b = {}--TM.New()
  1597.  
  1598.     -- A line can ONLY have the following format: Name,HashOrIp[:IP][,Bancount[,Time[,Bantype]]]
  1599.     -- The exception is namebans, which will always be: Name[,,,,Bantype] where Bantype can only be the string 'name' and nothing else
  1600.     -- Examples of valid chat bans:
  1601.     --  ,123456789abcdef123456789abcdef:127.0.0.1
  1602.     --  wizard,123456789abcdef123456789abcdef:127.0.0.1
  1603.     --  wizard,123456789abcdef123456789abcdef:127.0.0.1,1
  1604.     --  wizard,123456789abcdef123456789abcdef:127.0.0.1,1,--
  1605.     --  wizard,123456789abcdef123456789abcdef:127.0.0.1,1,--,chat
  1606.     --  wizard,123456789abcdef123456789abcdef:127.0.0.1,1,2015-03-27 04:10:52,chat,he was spamming
  1607.  
  1608.     -- First half: Match chatban (name,hash:ip) or hashban (name,hash) or nameban (name[,,,,bantype])
  1609.  
  1610.     -- if this matches then this is a chatban
  1611.     b.name,b.hash,b.ip,endline = match(line, "^(.-[^,]?),?(%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x+)[:,]([^,]+)(.-)$")
  1612.     b.ip = b.ip and (b.ip == "" and b.ip or validate_ipv4(b.ip))
  1613.     if b.hash and b.ip then
  1614.         formatBantype = "chat"
  1615.         unique_index = b.hash .. (b.ip or "") .. "chat"
  1616.         goto ReadSecondHalf
  1617.     end
  1618.  
  1619.     -- this will match a hash ban
  1620.     b.name,b.hash,endline = match(line, "^(.-[^,]?),?(%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x+)(.*)$")
  1621.     if b.hash then
  1622.         formatBantype = "hash"
  1623.         unique_index = b.hash .. "hash"
  1624.         goto ReadSecondHalf
  1625.     end
  1626.  
  1627.     -- this will match an IP ban.
  1628.     b.name,b.ip,endline = match(line, "^(.-[^,]?),([^,]+)(.-)$")
  1629.     b.ip = b.ip and validate_ipv4(b.ip)
  1630.     if not b.ip then
  1631.         -- sapp's ipbans.txt
  1632.         b.name,b.ip,b.reason = match(line, "^(.-[^:]?):([^:]+)(.-)$")
  1633.         b.ip = b.ip and validate_ipv4(b.ip)
  1634.     end
  1635.     if b.ip then
  1636.         formatBantype = "ip"
  1637.         unique_index = b.ip .. "ip"
  1638.         goto ReadSecondHalf
  1639.     end
  1640.  
  1641.     -- and lastly this will match a name ban.
  1642.     b.name,b.type = match(line, "^(.-),+(%w-)")
  1643.     if b.name then
  1644.         formatBantype = "name"
  1645.         unique_index = b.name .. "name"
  1646.         goto ReadSecondHalf
  1647.     end
  1648.  
  1649.     error(filename .. " is formatted incorrectly! Line: " .. line)
  1650.  
  1651.     ::ReadSecondHalf::
  1652.     -- This part matches the rest of the line. Here are some examples that it will match (starting from the end of the string)
  1653.     --                                                           (nothing here)
  1654.     --      ,1                                                  ,(count)
  1655.     --      ,5,--                                               ,(count),(infinite time)
  1656.     --      ,2,2015-06-13 05:29:51,chat                         ,(count),(time),(bantype)
  1657.     --      ,3,-1,chat,offensive language                       ,(count),(infinite time),(bantype),(reason)
  1658.  
  1659.     if not b.reason and endline and endline ~= "" then
  1660.         count,timestr,b.type,b.reason = match(endline, "^,(%d+),?([%d%s%-:]*),?(%w*),?(.-)$")
  1661.         b.reason = b.reason and b.reason ~= "" and gsub(b.reason, ",", "") or "None Given"
  1662.  
  1663.     -- these don't exist in a nameban
  1664.     elseif not b.type or b.type == "" then
  1665.         b.count = nil
  1666.         b.type = nil
  1667.         b.reason = nil
  1668.         timestr = nil
  1669.     end
  1670.  
  1671.     -- Check if the ban types are what they should be.
  1672.     -- I try to make my code stop using tons of checks, but this is the one time where it actually needs them
  1673.     b.type = b.type and b.type ~= "" and b.type
  1674.     assert(not b.type or b.type == formatBantype, filename .. " is formatted incorrectly! expected bantype " .. formatBantype .. " instead got " .. tostring(b.type) .. " on line: " .. line)
  1675.     assert(not bantype or bantype == formatBantype, filename .. " should only have '" .. tostring(bantype) .. "' bans. Ban of type '" .. formatBantype .. "' was found in the line: " .. line)
  1676.  
  1677.     b.type = formatBantype
  1678.  
  1679.     if timestr then
  1680.         -- Match the time.
  1681.         -- Time format: YYYY-MM-DD HH:MM:SS
  1682.         t.year, t.month, t.day, t.hour, t.min, t.sec = match(timestr, "^(%d%d%d%d)%-(%d%d)%-(%d%d)%s+(%d%d):(%d%d):(%d%d)$")
  1683.  
  1684.         -- convert 'ban expiration date' to 'seconds remaining until ban expires'
  1685.         if t.sec then
  1686.             b.time = os.time(t)
  1687.         -- else time will become -1 (infinite)
  1688.         else
  1689.             b.time = -1
  1690.         end
  1691.     -- time not specified in ban file, should be indefinite.
  1692.     else
  1693.         b.time = -1
  1694.     end
  1695.  
  1696.     if formatBantype ~= "name" then
  1697.         count = tonumber(count)
  1698.         b.count = count and count > 0 and count or 1
  1699.     end
  1700.  
  1701.     b.name = b.name == "" and "Unnamed" or gsub(b.name, ",", "")
  1702.  
  1703.     return b, unique_index
  1704. end
  1705.  
  1706. local function toBanTextEntry(entry)
  1707.     local time, bantype = entry.time, entry.type
  1708.     time = time == -1 and "--" or os.date("%Y-%m-%d %X", time)
  1709.  
  1710.     if bantype == "chat" then
  1711.         return entry.name..","..entry.hash..":"..(entry.ip or "1.2.3.4")..","..entry.count..","..time..","..bantype..","..entry.reason
  1712.     elseif bantype == "hash" then
  1713.         return entry.name..","..entry.hash..","..entry.count..","..time..","..bantype..","..entry.reason
  1714.     elseif bantype == "ip" then
  1715.         return entry.name..","..entry.ip..","..entry.count..","..time..","..bantype..","..entry.reason
  1716.     elseif bantype == "name" then
  1717.         return entry.name..",,,,"..bantype--..","..reason       reasons don't exist for namebans.. yet
  1718.     end
  1719. end
  1720.  
  1721. local function download(host, file, port, output)
  1722.     port = port or 80
  1723.    
  1724.     local client = socket.tcp()
  1725.    
  1726.     client:settimeout(1, 'b')
  1727.     client:settimeout(1, 't')
  1728.    
  1729.     local status, status2, err = pcall(client.connect, client, host, port)
  1730.    
  1731.     if not status or not status2 then
  1732.         print("Connection failed with error : " .. err)
  1733.         return
  1734.     end
  1735.    
  1736.     coroutine.yield(client)
  1737.    
  1738.     -- Stop luasocket from blocking. You can play with these values
  1739.     client:settimeout(0.01, 'b')
  1740.     client:settimeout(0.01, 't')
  1741.    
  1742.     client:send("GET " .. file .. " HTTP/1.1\r\nHOST: " .. host .. ":" .. port .. "\r\n\r\n")
  1743.    
  1744.     local count = 0 -- counts number of bytes read
  1745.     local buffer, status, overflow
  1746.     while true do
  1747.         coroutine.yield(client)
  1748.         buffer, status, overflow = client:receive(65536)
  1749.         -- If buffer is not nil the call was a success (changed in LuaSocket 2.0)
  1750.         if buffer then
  1751.             --print("Successfully received " .. #buffer .. " without timeout.")
  1752.             output[#output+1] = buffer
  1753.             count = count + #buffer
  1754.         else
  1755.             --print('"' .. status .. '" with ' .. #overflow .. ' bytes of ' .. file)
  1756.             output[#output+1] = overflow
  1757.             count = count + #overflow
  1758.         end
  1759.         if status == "closed" then break end
  1760.     end
  1761.     client:close()
  1762. end
  1763.  
  1764. local function OnHttpReceive(output)
  1765.     local entry, unique_index, hash, ip, name, bantype
  1766.     local cur_time = os.time()
  1767.     for line in string.gmatch(output, "[^\r\n]*") do
  1768.         entry, unique_index = loadBanTextEntry(line, nil, "remote banlist")
  1769.         if entry and not ban_table[unique_index] then
  1770.             entry.remote = true
  1771.             ban_table[#ban_table+1] = entry
  1772.             ban_table[unique_index] = #ban_table
  1773.             if not entry.time or entry.time > cur_time then
  1774.                 for playerId = 0,15 do
  1775.                     if getplayer(playerId) then
  1776.                         hash, ip, name = gethash(playerId), getip(playerId), getname(playerId)
  1777.                         bantype = entry.type
  1778.                         if bantype == "hash" and hash == entry.hash or entry.type == "ip" and netMatch(entry.ip, ip) then
  1779.                             tempBanPlayer(resolveplayer(playerId))
  1780.                             break
  1781.                         elseif bantype == "chat" and (entry.hash == hash or netMatch(entry.ip, ip)) then
  1782.                             PlayerClass[playerId].muted = true
  1783.                         elseif bantype == "name" and entry.name == name then
  1784.                             svcmd("sv_kick " .. resolveplayer(playerId) .. " Found in a Remote Ban Entry during a reload.")
  1785.                             break
  1786.                         end
  1787.                     end
  1788.                 end
  1789.             end
  1790.         end
  1791.     end
  1792. end
  1793.  
  1794. function handleHttpRequest(id, count, userdata) -- userdata = {[1] = coroutine thread, [2] = extraArg}
  1795.  
  1796.     --local start = os.clock()
  1797.     local status, res = coroutine.resume(userdata[1])
  1798.     --local finish = os.clock()
  1799.     --print("TIME: " .. (finish - start) * 1000 .. " ms")
  1800.    
  1801.     if not res then -- thread finished its task?
  1802.         --print("Finished")
  1803.         output = concat(userdata[3])
  1804.         local sizeOfFile = match(output, "Content%-Length: (%d+)")
  1805.         OnHttpReceive(sizeOfFile and sub(output, -sizeOfFile, -2) or output, userdata[2])
  1806.         http_receiving = false
  1807.         return false
  1808.     end
  1809.     return true
  1810. end
  1811.  
  1812. local function HTTPGET(host, file, port, extraArg)
  1813.    
  1814.     if http_receiving then
  1815.         return
  1816.     end
  1817.  
  1818.     local output = {}
  1819.     -- create coroutine, and return the handle for the timer.
  1820.     local timerID = registertimer(
  1821.         1000,
  1822.         "handleHttpRequest",
  1823.         {  
  1824.             coroutine.create(
  1825.                 function()
  1826.                     download(host, file, port, output)
  1827.                 end
  1828.             ),
  1829.             extraArg,
  1830.             output
  1831.         }
  1832.     )
  1833.     http_receiving = true
  1834.     return timerID
  1835. end
  1836.  
  1837. local function reloadRemoteBanlist()
  1838.     local args = defaults.remote_bansystem
  1839.     HTTPGET(args.host, args.banfile, args.port)
  1840. end
  1841.  
  1842. local function loadBanFile(filename, bantype)
  1843.     local file = io.open(filename)
  1844.     if not file then
  1845.         return
  1846.     end
  1847.  
  1848.     local ban_entry, unique_index
  1849.     for line in file:lines() do
  1850.  
  1851.         ban_entry, unique_index = loadBanTextEntry(line, bantype, filename)
  1852.  
  1853.         -- Make sure this entry hasn't already been added before we add it.
  1854.         if ban_entry and not ban_table[unique_index] then
  1855.             ban_table[#ban_table+1] = ban_entry
  1856.             ban_table[unique_index] = #ban_table
  1857.         end
  1858.     end
  1859.     file:close()
  1860. end
  1861.  
  1862. -- Save all bans to banned.txt
  1863. local function updateBanFiles(bantype)
  1864.     local writetbl = {}--TM.New()
  1865.     local entry
  1866.     local file, err = io.open(profilepath .. defaults.banlist_file .. ".txt", "w")
  1867.     local time, type
  1868.     local args = defaults.remote_bansystem
  1869.     for id = 1,#ban_table do entry = ban_table[id]
  1870.         if not args or (entry.remote and args.mode >= 1 or not entry.remote and args.mode ~= 2) then
  1871.             writetbl[#writetbl+1] = toBanTextEntry(entry)
  1872.         end
  1873.     end
  1874.     local output = concat(writetbl, "\n")
  1875.     file:write(output)
  1876.     file:close()
  1877.  
  1878.     -- Update the remote banlist.
  1879.     if args and args.mode >= 2 then
  1880.         http.request(args.http_source, "&bans=" .. output .. ",&unban=false")
  1881.     end
  1882. end
  1883.  
  1884. local function updateAdminFiles()
  1885.     local file = io.open(profilepath .. defaults.admin_file .. ".txt", "w")
  1886.     local writetbl = {}--TM.New()
  1887.     for index,admin_entry in next,admin_table do
  1888.         writetbl[#writetbl+1] = admin_entry.name .. "," .. index .. "," .. admin_entry.level .. "," .. admin_entry.type
  1889.     end
  1890.     file:write(concat(writetbl, "\n"))
  1891.     file:close()
  1892. end
  1893.  
  1894. local function loadAllAdminFiles()
  1895.     local timestamp = os.date"%Y_%m_%d_%H_%M_%S"
  1896.     local file = io.open(profilepath .. "admin.txt")
  1897.     if file then
  1898.         local name, hash, level
  1899.         for line in file:lines() do
  1900.  
  1901.             -- format the line (name, hash, level)
  1902.             name, hash, level = match(line, "^(%w-),(%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x+),(%d+)%c*$")
  1903.             if hash then
  1904.                 admin_table[hash] = {name = name, level = tonumber(level), type = "hash"}
  1905.             end
  1906.         end
  1907.         file:close()
  1908.         os.rename(profilepath .. "admin.txt", profilepath .. "old_admin_" .. timestamp .. ".txt")
  1909.     end
  1910.  
  1911.     -- Now stores IP admins as well.
  1912.     file = io.open(profilepath .. defaults.admin_file .. ".txt")
  1913.     if file then
  1914.         local name, hash, ip, level, admintype
  1915.         for line in file:lines() do
  1916.             -- format the line (name, hash, level)
  1917.             name, hash, level = match(line, "^(%w-),(%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x+),(%d+)")
  1918.             if hash then
  1919.                 admin_table[hash] = {name = name, level = tonumber(level), type = "hash"}
  1920.             else
  1921.                 -- format the line (name, hash, level, ip)
  1922.                 name, ip, level = match(line, "^(%w-),(%g-),(%d+)")
  1923.                 ip = validate_ipv4(ip)
  1924.                 assert(ip, defaults.admin_file .. ".txt is incorrectly formatted! Line: " .. line)
  1925.  
  1926.                 admin_table[ip] = {name = name, level = tonumber(level), type = "ip"}
  1927.             end
  1928.         end
  1929.         file:close()
  1930.     end
  1931.  
  1932.     -- IP Admins now use admins.txt, but this is here for backwards compatibility.
  1933.     file = io.open(profilepath .. "ipadmins.txt")
  1934.     if file then
  1935.         local name, level, ip
  1936.         for line in file:lines() do
  1937.  
  1938.             -- format the line (name, hash, level, ip)
  1939.             name, ip, level = match(line, "^(%w-),(%g-),(%d+)%c*$")
  1940.             ip = validate_ipv4(ip)
  1941.             if ip then
  1942.                 admin_table[ip] = {name = name, level = tonumber(level), type = "ip"}
  1943.             end
  1944.         end
  1945.         file:close()
  1946.         os.rename(profilepath .. "ipadmins.txt", profilepath .. "old_ipadmins_" .. timestamp .. ".txt")
  1947.     end
  1948.  
  1949.     updateAdminFiles()
  1950. end
  1951.  
  1952. function remoteTimer(id, count)
  1953.  
  1954.     -- This code will check if someone is trying to login to this TCP server.
  1955.     local client, err = server:accept()
  1956.     local length = #clients
  1957.     if not err then
  1958.         client:send"Welcome to the Remote Control interface provided in Wizard's Command Script!\r\n Type 'rcon password command' to execute a command. The Rcon password you use MUST be a global rcon (with sv_rcon_add)\r\n"
  1959.         length = length + 1
  1960.         clients[length] = {socket = client, info = client:getpeername(), client.logged_in}
  1961.         client:settimeout(0)
  1962.     elseif err ~= "timeout" then
  1963.         hprintf("There was an error accepting a client.\r\nError: " .. err)
  1964.     end
  1965.    
  1966.     local command, rcon
  1967.     for i = 1,length do client = clients[i]
  1968.         command, err = client.socket:receive()
  1969.        
  1970.         -- Problem getting response from client.
  1971.         if err == "timeout" then
  1972.             goto continue
  1973.         elseif err then
  1974.             client.socket:close()
  1975.             hprintf("Remote client '" .. client.info .. "' disconnected with error: " .. err)
  1976.             remove(clients, i)
  1977.             goto continue
  1978.        
  1979.         -- Logout code.
  1980.         elseif command == "logout" or command == "quit" or command == "exit" or command == "close" then
  1981.             client.socket:send"You have been disconnected. Have a good day"
  1982.             client.socket:close()
  1983.             remove(clients, i)
  1984.             goto continue
  1985.         end
  1986.  
  1987.         rcon, command = match(command, "^rcon (%w%w%w%w%w%w%w%w) (%g+)%c*$")
  1988.        
  1989.         -- Validate the command.
  1990.         if not rcon or not command then
  1991.             client.socket:send"Invalid Command attempt.\r\nrcon <password> <command>\r\n"
  1992.             goto continue
  1993.         elseif OnServerCommandAttempt(-1, command, rcon) == false then
  1994.             client.socket:send"Bad rcon password given. This will be reported."
  1995.             goto continue
  1996.         end
  1997.        
  1998.         hprintf("Remote client '" .. client.info .. "' executed '" .. command .. "'")
  1999.         local response
  2000.         if command ~= "sv_script_unload" and command ~= "sv_script_reload" and command ~= "sv_script_load" and command ~= "reload" and command ~= "load" and command ~= "unload" and command ~= "lua_load" and command ~= "lua_unload" then
  2001.             response = svcmd(command, true)
  2002.         end
  2003.         response = type(response) == "table" and response[1] and concat(response) or "Failed to receive output for command."
  2004.         client.socket:send(response .. "\r\nType your command here:")
  2005.  
  2006.        
  2007.         ::continue::
  2008.     end
  2009.     return true
  2010. end
  2011.  
  2012. -- changes 'sv_myCommand', '/myCommand', and '\myCommand' into 'myCommand'
  2013. local function getvalidformat(command)
  2014.     if not command then return end
  2015.     local sv_found, slash_found, both_found = sub(command, 1, 3), sub(command, 1, 1), sub(command, 1, 4)
  2016.     command = gsub(gsub(command, "_", ""), " ", "")
  2017.     if sv_found == "sv_" then
  2018.         return sub(command, 3)
  2019.     elseif slash_found == "\\" or slash_found == "/" then
  2020.         return sub(command, 2)
  2021.     elseif both_found == "\\sv_" or both_found == "/sv_" then
  2022.         return sub(command, 4)
  2023.     end
  2024.     return command
  2025. end
  2026.  
  2027. local function getaccess(playerId)
  2028.     if playerId then
  2029.         local adminEntry = PlayerClass[playerId].admin_entry
  2030.         return adminEntry and adminEntry.level
  2031.     else
  2032.         return 0
  2033.     end
  2034. end
  2035.  
  2036. local function SelectRandomPlayer(team)
  2037.     local t = {}--TM.New()
  2038.     local size = 0
  2039.     for playerId = 0,15 do
  2040.         if getplayer(playerId) and (not team or getteam(playerId) == team) then
  2041.             size = size + 1
  2042.             t[size] = playerId
  2043.         end
  2044.     end
  2045.     if size > 0 then
  2046.         return t[rand(1, size)]
  2047.     end
  2048. end
  2049.  
  2050. -- Origstring is the string to search in, wild is the string to search for.
  2051. local function wildstring(origstring, wild, case_sensative)
  2052.  
  2053.     -- If not case sensitive then make all arguments lowercase.
  2054.     if not case_sensative then
  2055.         origstring, wild = lower(origstring), lower(wild)
  2056.     end
  2057.  
  2058.     wild = gsub(gsub(gsub(wild, "?", "."), "*", ".*"), " ", "%s")
  2059.  
  2060.     local found = match(origstring, wild)
  2061.     if found and #found == #origstring then
  2062.         return true
  2063.     end
  2064.     return false
  2065. end
  2066.  
  2067. local function getvalidplayers(expression, executorPlayerId)
  2068.     local players = {}--TM.New()
  2069.     if cur_players ~= 0 and expression then
  2070.         if expression == "*" then
  2071.             for playerId = 0,15 do
  2072.                 if getplayer(playerId) then
  2073.                     players[#players+1] = playerId
  2074.                 end
  2075.             end
  2076.         elseif expression == "me" then
  2077.             if executorPlayerId then
  2078.                 players[1] = executorPlayerId
  2079.             end
  2080.         elseif player_colors[expression] then
  2081.             local color = player_colors[expression]
  2082.             local m_player
  2083.             for playerId = 0,15 do
  2084.                 m_player = getplayer(playerId)
  2085.                 if m_player then
  2086.                     if color == readword(m_player + 0x60) then
  2087.                         players[#players+1] = playerId
  2088.                     end
  2089.                 end
  2090.             end
  2091.         elseif expression == "red" then
  2092.             for playerId = 0,15 do
  2093.                 if getplayer(playerId) and getteam(playerId) == 0 then
  2094.                     players[#players+1] = playerId
  2095.                 end
  2096.             end
  2097.         elseif expression == "blue" then
  2098.             for playerId = 0,15 do
  2099.                 if getplayer(playerId) and getteam(playerId) == 1 then
  2100.                     players[#players+1] = playerId
  2101.                 end
  2102.             end
  2103.         elseif expression == "randomred" or expression == "randred" then
  2104.             players[1] = SelectRandomPlayer(0)
  2105.         elseif expression == "randomblue" or expression == "randblue" then
  2106.             players[1] = SelectRandomPlayer(1)
  2107.         elseif (tonumber(expression) or 0) >= 1 and tonumber(expression) <= 16 then
  2108.             local playerId = tonumber(expression)
  2109.             if getplayer(rresolveplayer(playerId)) then
  2110.                 players[1] = rresolveplayer(playerId)
  2111.             end
  2112.         elseif expression == "rand" or expression == "random" then
  2113.             players[1] = SelectRandomPlayer()
  2114.         elseif expression == "admins" then
  2115.             for playerId = 0,15 do
  2116.                 if getplayer(playerId) and getaccess(playerId) then
  2117.                     players[#players+1] = playerId
  2118.                 end
  2119.             end
  2120.         elseif expression == "nearest" or expression == "closest" then
  2121.             local m_playerObj, playerObjId = getplayerobject(executorPlayerId)
  2122.             local m_playerObj2, X, Y, Z, dist, closest_player
  2123.             if m_playerObj then
  2124.                 local x,y,z = getobjectcoords(playerObjId)
  2125.                 local min_dist = 9001
  2126.                 for playerId = 0,15 do
  2127.                     if playerId ~= executorPlayerId then
  2128.                         m_playerObj2, playerObjId2 = getplayerobject(playerId)
  2129.                         if m_playerObj2 then
  2130.                             X,Y,Z = getobjectcoords(playerObjId2)
  2131.                             dist = (X - x)^2 + (Y - y)^2 + (Z - z)^2 -- dont need square root since its a comparison
  2132.                             if min_dist > dist then
  2133.                                 min_dist = dist
  2134.                                 closest_player = playerId
  2135.                             end
  2136.                         end
  2137.                     end
  2138.                 end
  2139.                 players[1] = closest_player
  2140.             end
  2141.         elseif expression == "farthest" then
  2142.             local m_playerObj, playerObjId = getplayerobject(executorPlayerId)
  2143.             local m_playerObj2, X, Y, Z, dist, farthest_player
  2144.             if m_playerObj then
  2145.                 local x,y,z = getobjectcoords(playerObjId)
  2146.                 local max_dist = 0
  2147.                 for playerId = 0,15 do
  2148.                     if playerId ~= executorPlayerId then
  2149.                         m_playerObj2, playerObjId2 = getplayerobject(playerId)
  2150.                         if m_playerObj2 then
  2151.                             X,Y,Z = getobjectcoords(playerObjId2)
  2152.                             dist = (X - x)^2 + (Y - y)^2 + (Z - z)^2 -- dont need square root since its a comparison
  2153.                             if max_dist < dist then
  2154.                                 max_dist = dist
  2155.                                 farthest_player = playerId
  2156.                             end
  2157.                         end
  2158.                     end
  2159.                 end
  2160.                 players[1] = farthest_player
  2161.             end
  2162.         else
  2163.             for playerId = 0,15 do
  2164.                 if getplayer(playerId) and wildstring(getname(playerId), expression) then
  2165.                     players[#players+1] = playerId
  2166.                 end
  2167.             end
  2168.         end
  2169.         return next(players) and players
  2170.     end
  2171.     return false
  2172. end
  2173.  
  2174. local tag_vehi_types = { -- 0x2F4
  2175.     [0] = "Human Tank",
  2176.     "Human Jeep",
  2177.     "Human Boat",
  2178.     "Human Plane",
  2179.     "Alien Scout",
  2180.     "Alien Fighter",
  2181.     "Turret",
  2182. }
  2183.  
  2184. local tag_weap_types = { -- 0x30C
  2185.     [0] = "None",
  2186.     [1694528097] = "AI: Sentinel Beam (ar)",
  2187.     [98] = "Special: Skull Ball (b)",
  2188.     [1811939430] = "Special: Flag (f)",
  2189.     [7239015] = "Vehicle (Covenant): Type-26 Banshee; Type-32 RAV Ghost; Type-25 (and Type-52?) Wraith (gun)",
  2190.     [29799] = "Vehicle (Covenant): Type-26 ASG Shade Gun Turret; DX-class Spirit Dropship (gt)",
  2191.     [26467] = "Vehicle (Human): M12 Warthog (cg)",
  2192.     [1852727651] = "Vehicle (Human): M808B MBT Scorpion (cannon)",
  2193.     [1811968609] = "Weapon (Human): MA5 Assault Rifle; Gravity Rifle (ar)",
  2194.     [1811969126] = "Weapon (Human): M7057 Flamethrower (ft)",
  2195.     [28776] = "Weapon (Human): M6 Pistol (hp)",
  2196.     [1811967090] = "Weapon (Human): M19 SSM / M41 SSR Rocket Launcher (rl)",
  2197.     [1811965811] = "Weapon (Human): M90 CAWS Shotgun (sg)",
  2198.     [1811968627] = "Weapon (Human): 99D-S2 Sniper Rifle (sr)",
  2199.     [25190] = "Weapon, Melee (Covenant): Energy Sword (fb)",
  2200.     [1811968614] = "Weapon (Covenant): Type-33 Fuel Rod Gun (fr)",
  2201.     [1811965294] = "Weapon (Covenant): Type-33 GML Needler (ne)",
  2202.     [1811968112] = "Weapon (Covenant): Plasma Pistol (pp)",
  2203.     [1811968624] = "Weapon (Covenant): Plasma Rifle (pr)",
  2204.     [1811964784] = "Weapon (Covenant): Plasma Cannon (pc)"
  2205. }
  2206.  
  2207. local function LoadTags()
  2208.    
  2209.     local map_base = 0x40440000
  2210.     local tag_table_base = readdword(map_base) -- Confirmed. (0x40440028)
  2211.     local tag_table_count = readdword(map_base + 0xC) -- Confirmed. Number of tags in the tag table.
  2212.     local tag_table_size = 0x20 -- Confirmed.
  2213.  
  2214.     local reverse = string.reverse
  2215.     local tag_class, tag_id, tag_name_address, tag_name, address_tag_data, vehi_type, weap_type
  2216.     for i=0,(tag_table_count - 1) do
  2217.         tag_class = reverse(readstring(tag_table_base + (tag_table_size * i), 4))
  2218.         tag_id = readdword(tag_table_base + 0xC + (tag_table_size * i))
  2219.         tag_name_address = readdword(tag_table_base + 0x10 + tag_table_size * i)
  2220.         tag_name = readstring(tag_name_address)
  2221.         tag_table[tag_class] = tag_table[tag_class] or {tag_id}
  2222.         tag_table[tag_class][tag_name] = tag_id
  2223.         tag_table[tag_class][#tag_table[tag_class]+1] = tag_id
  2224.         tag_table[tag_id] = {}--{}--TM.New()
  2225.         tag_table[tag_id].tag_name = tag_name
  2226.         tag_table[tag_id].tag_class = tag_class
  2227.         tag_address = readdword(map_base) + i * tag_table_size -- 0x40440028
  2228.         if tag_class == "vehi" then
  2229.             address_tag_data = readdword(tag_address, 0x14)
  2230.             vehi_type = readword(address_tag_data + 0x2F4)
  2231.             tag_table[tag_id].vehi_type = tag_vehi_types[vehi_type]
  2232.             if vehi_type and vehi_type >= 0 and vehi_type <= 6 and not tag_table[vehi_type] then
  2233.                 tag_table[vehi_type] = tag_id
  2234.             end
  2235.         elseif tag_class == "weap" then
  2236.             address_tag_data = readdword(tag_address, 0x14)
  2237.             weap_type = readword(address_tag_data + 0x2F4)
  2238.             tag_table[tag_id].weap_type = tag_weap_types[weap_type]
  2239.             if not weap_type or not tag_table[weap_type] then
  2240.                 tag_table[weap_type] = tag_id
  2241.             end
  2242.         end
  2243.     end
  2244.    
  2245.     hprintf("Found " .. tostring(#tag_table.vehi) .. " vehicles and " .. tostring(#tag_table.weap) .. " weapons")
  2246.  
  2247.     flameid = gettagid("proj", "weapons\\flamethrower\\flame")
  2248.    
  2249.     objects = {
  2250.         cyborg = {"bot, masterchief", type = "bipd", mapId = gettag("bipd", "characters\\cyborg_mp\\cyborg_mp"), name = "Cyborg"},
  2251.         captain = {"keyes", type = "bipd", mapId = gettag("bipd", "characters\\captain\\captain"), name = "Captain Keyes"},
  2252.         cortana = {type = "bipd", mapId = gettag("bipd", "characters\\cortana\\cortana"), name = "Cortana"},
  2253.         cortana2 = {type = "bipd", mapId = gettag("bipd", "characters\\cortana\\halo_enhanced\\halo_enhanced"), name = "Cortana2"},
  2254.         crewman = {type = "bipd", mapId = gettag("bipd", "characters\\crewman\\crewman"), name = "Crewman"},
  2255.         elite = {type = "bipd", mapId = gettag("bipd", "characters\\elite\\elite"), name = "Elite"},
  2256.         elite2 = {type = "bipd", mapId = gettag("bipd", "characters\\elite\\elite special"), name = "Elite Special"},
  2257.         engineer = {type = "bipd", mapId = gettag("bipd", "characters\\engineer\\engineer"), name = "Engineer"},
  2258.         flood = {type = "bipd", mapId = gettag("bipd", "characters\\flood_captain\\flood_captain"), name = "Flood Captain"},
  2259.         flood2 = {type = "bipd", mapId = gettag("bipd", "characters\\flood_infection\\flood_infection"), name = "Flood Infection"},
  2260.         flood3 = {type = "bipd", mapId = gettag("bipd", "characters\\floodcarrier\\floodcarrier"), name = "Flood Carrier"},
  2261.         floodelite = {type = "bipd", mapId = gettag("bipd", "characters\\floodcombat elite\\floodcombat elite"), name = "FloodCombat Elite"},
  2262.         floodhuman = {type = "bipd", mapId = gettag("bipd", "characters\\floodcombat_human\\floodcombat_human"), name = "FloodCombat Human"},
  2263.         grunt = {"pedobear", type = "bipd", mapId = gettag("bipd", "characters\\grunt\\grunt"), name = "Pedobear"},
  2264.         hunter = {type = "bipd", mapId = gettag("bipd", "characters\\hunter\\hunter"), name = "Hunter"},
  2265.         marine = {type = "bipd", mapId = gettag("bipd", "characters\\marine\\marine"), name = "Marine"},
  2266.         marine2 = {"marinesuicide", type = "bipd", mapId = gettag("bipd", "characters\\marine_suicidal\\marine_suicidal"), name = "Marine Suicidal"},
  2267.         monitor = {type = "bipd", mapId = gettag("bipd", "characters\\monitor\\monitor"), name = "Monitor"},
  2268.         sentinel = {type = "bipd", mapId = gettag("bipd", "characters\\sentinel\\sentinel"), name = "Sentinel"},
  2269.         johnson = {type = "bipd", mapId = gettag("bipd", "characters\\johnson\\johnson"), name = "Sgt. Johnson"},
  2270.         camouflage = {"camo", type = "eqip", mapId = gettag("eqip", "powerups\\active camouflage"), name = "Camouflage"},
  2271.         doublespeed = {"dblspd", type = "eqip", mapId = gettag("eqip", "powerups\\double speed"), name = "Double Speed"},
  2272.         fullspec = {"fullspectrum", type = "eqip", mapId = gettag("eqip", "powerups\\full-spectrum vision"), name = "Full-Spectrum Vision"},
  2273.         fnade = {"nades", "frag", "frags", type = "eqip",  mapId = gettag("eqip", "weapons\\frag grenade\\frag grenade"), name = "Frag Grenade"},
  2274.         pnade = {"plasmas", "plasma", type = "eqip", mapId = gettag("eqip", "weapons\\plasma grenade\\plasma grenade"), name = "Plasma Grenade"},
  2275.         overshield = {"os", type = "eqip", mapId = gettag("eqip", "powerups\\over shield"), name = "Overshield"},
  2276.         rifleammo = {type = "eqip", mapId = gettag("eqip", "powerups\\assault rifle ammo\\assault rifle ammo"), name = "Assault Rifle Ammo"},
  2277.         healthpack = {"health", type = "eqip", mapId = gettag("eqip", "powerups\\health pack"), name = "Health Pack"},
  2278.         needlerammo = {"needleammo", type = "eqip", mapId = gettag("eqip", "powerups\\needler ammo\\needler ammo"), name = "Needler Ammo"},
  2279.         pistolammo = {type = "eqip", mapId = gettag("eqip", "powerups\\pistol ammo\\pistol ammo"), name = "Pistol Ammo"},
  2280.         rocketammo = {type = "eqip", mapId = gettag("eqip", "powerups\\rocket launcher ammo\\rocket launcher ammo"), name = "Rocket Ammo"},
  2281.         shottyammo = {"shotgunammo", type = "eqip", mapId = gettag("eqip", "powerups\\shotgun ammo\\shotgun ammo"), name = "Shotgun Ammo"},
  2282.         sniperammo = {type = "eqip", mapId = gettag("eqip", "powerups\\sniper rifle ammo\\sniper rifle ammo"), name = "Sniper Ammo"},
  2283.         flameammo = {type = "eqip", mapId = gettag("eqip", "powerups\\flamethrower ammo\\flamethrower ammo"), name = "Flamethrower Ammo"},
  2284.         energysword = {"esword", type = "weap", mapId = gettag("weap", "weapons\\energy sword\\energy sword"), name = "Energy Sword"},
  2285.         oddball = {"ball", type = "weap", mapId = gettag("weap", "weapons\\ball\\ball"), name = "Oddball"},
  2286.         flag = {type = "weap", mapId = gettag("weap", "weapons\\flag\\flag"), name = "Flag"},
  2287.         fuelrod = {"frg", "rod", "plasmacannon", type = "weap", mapId = gettag("weap", "weapons\\plasma_cannon\\plasma_cannon"), name = "Fuel Rod"},
  2288.         gravitygun = {"ggun", type = "weap", mapId = gettag("weap", "weapons\\gravity rifle\\gravity rifle"), name = "Gravity Gun"},
  2289.         needler = {type = "weap", mapId = gettag("weap", "weapons\\needler\\mp_needler"), name = "Needler"},
  2290.         pistol = {type = "weap", mapId = gettag("weap", "weapons\\pistol\\pistol"), name = "Pistol"},
  2291.         plasmapistol = {"ppistol", type = "weap", mapId = gettag("weap", "weapons\\plasma pistol\\plasma pistol"), name = "Plasma Pistol"},
  2292.         plasmarifle = {"prifle", type = "weap", mapId = gettag("weap", "weapons\\plasma rifle\\plasma rifle"), name = "Plasma Rifle"},
  2293.         assaultrifle = {"rifle", "arifle", "assault", type = "weap", mapId = gettag("weap", "weapons\\assault rifle\\assault rifle"), name = "Assault Rifle"},
  2294.         rocketlauncher = {"rocket", "rox", type = "weap", mapId = gettag("weap", "weapons\\rocket launcher\\rocket launcher"), name = "Rocket Launcher"},
  2295.         shotgun = {"shotty", type = "weap", mapId = gettag("weap", "weapons\\shotgun\\shotgun"), name = "Shotgun"},
  2296.         sniper = {"sniperrifle", type = "weap", mapId = gettag("weap", "weapons\\sniper rifle\\sniper rifle"), name = "Sniper Rifle"},
  2297.         flamethrower = {"flamer", type = "weap", mapId = gettag("weap", "weapons\\flamethrower\\flamethrower"), name = "Flamethrower"},
  2298.         wraith = {type = "vehi", mapId = gettag("vehi", "vehicles\\wraith\\wraith"), name = "Wraith"},
  2299.         pelican = {"peli", type = "vehi", mapId = gettag("vehi", "vehicles\\pelican\\pelican"), name = "Pelican"},
  2300.         ghost = {type = "vehi", type = "vehi", mapId = gettag("vehi", "vehicles\\ghost\\ghost_mp"), name = "Ghost"},
  2301.         warthog = {"hog", type = "vehi",  mapId = gettag("vehi", "vehicles\\warthog\\mp_warthog"), name = "Warthog"},
  2302.         rocketwarthog = {"rhog", type = "vehi", mapId = gettag("vehi", "vehicles\\rwarthog\\rwarthog"), name = "Rocket Warthog"},
  2303.         banshee = {"shee", type = "vehi", mapId = gettag("vehi", "vehicles\\banshee\\banshee_mp"), name = "Banshee"},
  2304.         tank = {"scorpion", type = "vehi", mapId = gettag("vehi", "vehicles\\scorpion\\scorpion_mp"), name = "Tank"},
  2305.         turret = {"shade", type = "vehi", mapId = gettag("vehi", "vehicles\\c gun turret\\c gun turret_mp"), name = "Gun Turret"},
  2306.         sheebolt = {type = "proj", mapId = gettag("proj", "vehicles\\banshee\\banshee bolt"), name = "Shee Bolt"},
  2307.         sheerod = {type = "proj", mapId = gettag("proj", "vehicles\\banshee\\mp_banshee fuel rod"), name = "Shee Rod"},
  2308.         turretbolt = {type = "proj", mapId = gettag("proj", "vehicles\\c gun turret\\mp gun turret"), name = "Turret Bullet"},
  2309.         ghostbolt = {type = "proj", mapId = gettag("proj", "vehicles\\ghost\\ghost bolt"), name = "Ghost Bolt"},
  2310.         tankshot = {type = "proj", mapId = gettag("proj", "vehicles\\scorpion\\bullet"), name = "Tank Bullet"},
  2311.         tankshell = {type = "proj", mapId = gettag("proj", "vehicles\\scorpion\\tank shell"), name = "Tank Shell"},
  2312.         hogshot = {type = "proj", mapId = gettag("proj", "vehicles\\warthog\\bullet"), name = "Hog Bullet"},
  2313.         rifleshot = {type = "proj", mapId = gettag("proj", "weapons\\assault rifle\\bullet"), name = "Rifle Bullet"},
  2314.         flame = {type = "proj", mapId = gettag("proj", "weapons\\flamethrower\\flame"), name = "Flame Projectile"},
  2315.         needlershot = {type = "proj", mapId = gettag("proj", "weapons\\needler\\mp_needle"), name = "Needler Shard"},
  2316.         pistolshot = {type = "proj", mapId = gettag("proj", "weapons\\pistol\\bullet"), name = "Pistol Bullet"},
  2317.         priflebolt = {type = "proj", mapId = gettag("proj", "weapons\\plasma pistol\\bolt"), name = "Plasma Rifle Bolt"},
  2318.         ppistolbolt = {type = "proj", mapId = gettag("proj", "weapons\\plasma rifle\\bolt"), name = "Plasma Pistol Bolt"},
  2319.         ppistolcbolt = {type = "proj", mapId = gettag("proj", "weapons\\plasma rifle\\charged bolt"), name = "Plasma Pistol Charged Bolt"},
  2320.         rocketproj = {type = "proj", mapId = gettag("proj", "weapons\\rocket launcher\\rocket"), name = "Rocket Projectile"},
  2321.         shottyshot = {type = "proj", mapId = gettag("proj", "weapons\\shotgun\\pellet"), name = "Shotgun Pellet"},
  2322.         snipershot = {type = "proj", mapId = gettag("proj", "weapons\\sniper rifle\\sniper bullet"), name = "Sniper Bullet"},
  2323.         fuelrodshot = {type = "proj", mapId = gettag("proj", "weapons\\plasma_cannon\\plasma_cannon"), name = "Fuel Rod Bolt"},
  2324.     }
  2325.    
  2326.     -- Use enum in vehi_type as a backup way to determine default vehicles tag ids without their tagnames.
  2327.     objects.tank.mapId = objects.tank.mapId or tag_table[0] and tag_table[0]
  2328.     objects.warthog.mapId = objects.warthog.mapId or tag_table[1] and tag_table[1]
  2329.     objects.rocketwarthog.mapId = objects.rocketwarthog.mapId or tag_table[1] and tag_table[1]
  2330.     objects.pelican.mapId = objects.pelican.mapId or tag_table[3] and tag_table[3]
  2331.     objects.ghost.mapId = objects.ghost.mapId or tag_table[4] and tag_table[4]
  2332.     objects.banshee.mapId = objects.banshee.mapId or tag_table[5] and tag_table[5]
  2333.     objects.turret.mapId = objects.turret.mapId or tag_table[6] and tag_table[6]
  2334.    
  2335.     objects.oddball.mapId = objects.oddball.mapId or tag_table[98] and say("Oddball: USING BACKUP TAG") or tag_table[98]
  2336.     objects.energysword.mapId = objects.energysword.mapId or tag_table[25190] and say("Energy Sword: USING BACKUP TAG") or tag_table[25190]
  2337.     objects.pistol.mapId = objects.pistol.mapId or tag_table[28776] and say("Pistol: USING BACKUP TAG") or tag_table[28776]
  2338.     objects.flag.mapId = objects.flag.mapId or tag_table[1811939430] and say("Flag: USING BACKUP TAG") or tag_table[1811939430]
  2339.     objects.needler.mapId = objects.needler.mapId or tag_table[1811965294] and say("Needler: USING BACKUP TAG") or tag_table[1811965294]
  2340.     objects.plasmapistol.mapId = objects.plasmapistol.mapId or tag_table[1811968112] and say("Plasma Pistol: USING BACKUP TAG") or tag_table[1811968112]
  2341.     objects.fuelrod.mapId = objects.fuelrod.mapId or tag_table[1811968614] and say("Fuelrod: USING BACKUP TAG") or tag_table[1811968614]
  2342.     objects.plasmarifle.mapId = objects.plasmarifle.mapId or tag_table[1811968624] and say("Plasma Rifle: USING BACKUP TAG") or tag_table[1811968624]
  2343.     objects.assaultrifle.mapId = objects.assaultrifle.mapId or tag_table[1811968609] and say("Assault Rifle: USING BACKUP TAG") or tag_table[1811968609]
  2344.     objects.rocketlauncher.mapId = objects.rocketlauncher.mapId or tag_table[1811967090] and say("Rocket Launcher: USING BACKUP TAG") or tag_table[1811967090]
  2345.     objects.shotgun.mapId = objects.shotgun.mapId or tag_table[1811965811] and say("Shotgun: USING BACKUP TAG") or tag_table[1811965811]
  2346.     objects.sniper.mapId = objects.sniper.mapId or tag_table[1811968627] and say("Sniper: USING BACKUP TAG") or tag_table[1811968627]
  2347.     objects.flamethrower.mapId = objects.flamethrower.mapId or tag_table[1811969126] and say("Flamethrower: USING BACKUP TAG") or tag_table[1811969126]
  2348.    
  2349.     -- Set Object Aliases.
  2350.     for name,thisObject in next,objects do
  2351.         for i = 1,#thisObject do
  2352.             objects[thisObject[i]] = thisObject
  2353.         end
  2354.         objects[name] = thisObject
  2355.     end
  2356.  
  2357. end
  2358.  
  2359. function votekickTimer(id, count)
  2360.     say("The VoteKick on " .. getname(votekickPlayerId) .. " has expired!")
  2361.     votekicktimer = nil
  2362.     votekickPlayerId = nil
  2363.     votekick_counter = -defaults.votekick_timeout
  2364.     for playerId = 0,15 do
  2365.         PlayerClass[playerId].used_votekick = false
  2366.     end
  2367.     return false
  2368. end
  2369.  
  2370. local function WriteLog(filename, logStr)
  2371.     local file = io.open(filename, "a")
  2372.     if file then
  2373.         file:write(format("%s\t%s\n", os.date"%Y/%m/%d %H:%M:%S", logStr))
  2374.         file:close()
  2375.     end
  2376. end
  2377.  
  2378. local function cmdlog(message)
  2379.     WriteLog(profilepath .. "logs\\" .. defaults.commands_file .. ".log", message)
  2380. end
  2381.  
  2382. -- This local function makes sure that we never have any commands that output more than 8 lines
  2383. -- We need this because Halo only lets you see 8 lines of text at a time in the chat
  2384. -- This local function will also split lines into more lines if a line is too long.
  2385. -- If a person is executing \pl in the chat, we want them to be able to see players 1 through 16, therefore this local function is born.
  2386. -- Arguments are output, maximum number of lines to use (MIGHT go over maxlines if the line length is already too long)
  2387. -- maxlinesize is the maximum number of characters a line can have
  2388. -- If output is a table, this local function will check for the keys 'align', 'header', 'delim', and 'separator', otherwise it'll read it as a string.
  2389. local function formatOutput(output, maxlines, maxlinesize)
  2390.     -- error if the arguments were passed incorrectly.
  2391.     if type(output) ~= "string" and type(output) ~= "table" then
  2392.         error("bad argument #1 to 'formatOutput' (expected table or string, got " .. type(output) .. ")" .. " Value: " .. tostring(output))
  2393.     elseif maxlines and type(maxlines) ~= "number" then
  2394.         error("bad argument #2 to 'formatOutput' (expected number, got " .. type(maxlines) .. " Value: " .. tostring(maxlines))
  2395.     elseif maxlinesize and type(maxlinesize) ~= "number" then
  2396.         error("bad argument #3 to 'formatOutput' (expected number, got " .. type(maxlinesize) .. " Value: " .. tostring(maxlinesize))
  2397.     end
  2398.  
  2399.     -- handle our arguments
  2400.     maxlines = maxlines or 9001
  2401.     maxlinesize = maxlinesize or 9001
  2402.     local newOutput = type(output) == "string" and tokenizestring(output, "\n") or output
  2403.  
  2404.     -- Get number of lines from our output. Respects __len metamethod.
  2405.     local mt = type(output) == "table" and getmetatable(output)
  2406.     local len = mt and mt.__len
  2407.     local numOfLines = len and len(newOutput) or #newOutput
  2408.  
  2409.     local function insert(t, pos, v)
  2410.         if v then
  2411.             assert(type(pos) == "number", "bad argument #2 to 'insert' expected number, got " .. type(pos))
  2412.             for i = numOfLines+1,pos+1,-1 do
  2413.                 rawset(t, i, rawget(t, i-1))
  2414.             end
  2415.             t[pos] = v
  2416.         else
  2417.             t[numOfLines+1] = pos
  2418.         end
  2419.         numOfLines = numOfLines + 1
  2420.     end
  2421.  
  2422.     local function remove(t, key)
  2423.         t = type(t) == "table" and t or error("bad argument #1 to 'remove' expected table, got " .. type(t))
  2424.         key = key or numOfLines
  2425.         t[key] = nil
  2426.         if type(key) == "number" then
  2427.             for i = key,numOfLines do
  2428.                 rawset(t, i, rawget(t, i+1))
  2429.             end
  2430.         end
  2431.         numOfLines = numOfLines - 1
  2432.     end
  2433.  
  2434.     local header = newOutput.header
  2435.     local linesCombined = ceil((numOfLines + (header and 1 or 0))/maxlines)
  2436.  
  2437.     -- duplicate the header by linesCombined times.
  2438.     if header then
  2439.         assert(type(header) == "string", "Output header needs to be a string, got " .. type(header))
  2440.  
  2441.         for i = 1,linesCombined do
  2442.             insert(newOutput, 1, header)
  2443.         end
  2444.     end
  2445.  
  2446.     -- If we have no more output, then we don't need to do anything more.
  2447.     if numOfLines == 1 and header or numOfLines == 0 then
  2448.         return newOutput[1]
  2449.     end
  2450.  
  2451.     if newOutput.align then
  2452.  
  2453.         local delimiter = newOutput.delim or "|"
  2454.         local separator = newOutput.separator or delimiter
  2455.  
  2456.         local mins = {}--TM.New()
  2457.         local length, lineParts
  2458.  
  2459.         -- This loop gets the largest possible size for each line part.
  2460.         for i = 1,numOfLines do
  2461.             lineParts = tokenizestring(newOutput[i], delimiter)
  2462.             for j = 1,#lineParts do
  2463.                 -- Format every string to the biggest length possible for that entry.
  2464.                 length = #lineParts[j]
  2465.                 if not mins[j] or length > mins[j] then
  2466.                     mins[j] = length
  2467.                 end
  2468.             end
  2469.         end
  2470.  
  2471.         -- This loop will make all line parts the same size (by adding spaces). string.format makes this easy for us.
  2472.         local numOfLineParts
  2473.         for i = 1,numOfLines do
  2474.             lineParts = tokenizestring(newOutput[i], delimiter)
  2475.             numOfLineParts = #lineParts
  2476.             for j = 1,numOfLineParts do
  2477.                 lineParts[j] = format("%-" .. mins[j] .. "s", lineParts[j])
  2478.             end
  2479.             lineParts[numOfLineParts] = sub(lineParts[numOfLineParts], 1, -1) -- removes the last delimiter in the line
  2480.             newOutput[i] = concat(lineParts, separator)
  2481.         end
  2482.     end
  2483.  
  2484.     -- If our output uses too many lines, then we now need to combine lines until we are within maxlines
  2485.     local lineIter = 1
  2486.     local numOfLinesToCombine = floor(numOfLines / linesCombined)
  2487.     while numOfLines > maxlines do
  2488.  
  2489.         -- combine 'linesCombined' lines into 1 line.
  2490.         for i = 2,linesCombined do -- should be 1,linesCombined-1 but 2,linesCombined works fine
  2491.             if lineIter+1 > numOfLines then break end
  2492.             newOutput[lineIter] = newOutput[lineIter] .. " - " .. newOutput[lineIter+1]
  2493.             remove(newOutput, lineIter+1)
  2494.         end
  2495.         lineIter = lineIter + 1
  2496.  
  2497.         -- Check if we need to increase the number of lines to combine per iteration.
  2498.         -- Also checks if we're done
  2499.         if numOfLinesToCombine == 1 then
  2500.             linesCombined = linesCombined - 1
  2501.             if linesCombined < 2 then break end
  2502.             numOfLinesToCombine = floor(numOfLines / linesCombined)
  2503.  
  2504.         -- This is our counter.
  2505.         else
  2506.             numOfLinesToCombine = numOfLinesToCombine - 1
  2507.         end
  2508.     end
  2509.  
  2510.     -- Make sure the line isn't too long.
  2511.     -- If it is, we put the part that's too long into a new table which we will put back into output later.
  2512.     lineIter = 1
  2513.     local line, length
  2514.     while newOutput[lineIter] do
  2515.         line = newOutput[lineIter]
  2516.         length = #line
  2517.         if length > maxlinesize then
  2518.             newOutput[lineIter] = sub(line, 1, maxlinesize) -- first part of line
  2519.             insert(newOutput, lineIter+1, sub(line, maxlinesize)) -- insert a new line right after this one with the second part
  2520.         end
  2521.         lineIter = lineIter + 1
  2522.     end
  2523.     return concat(newOutput, "\n", 1, numOfLines)
  2524. end
  2525.  
  2526. function delayMsg(id, count, arguments)
  2527.     local msg, playerId = arguments[1], arguments[2]
  2528.     msg = type(msg) == "table" and concat(msg, "\n") or msg
  2529.     if playerId then
  2530.         if output_environment == 2 then
  2531.             say(msg, false)
  2532.         elseif output_environment == 3 then
  2533.             privatesay(playerId, msg, false)
  2534.         end
  2535.     end
  2536.     return false
  2537. end
  2538.  
  2539. local function sendresponse(message, playerId, log)
  2540.     if not message then
  2541.         -- this will reset all the properties of cmdreply
  2542.         cmdreply(true)
  2543.         return
  2544.     end
  2545.  
  2546.     local playerCheck = getplayer(playerId)
  2547.     local tempmessage = message
  2548.  
  2549.     if not playerCheck then
  2550.         message = formatOutput(message)
  2551.         hprintf(message)
  2552.     elseif output_environment == 1 then
  2553.         message = formatOutput(message, 20, 76)
  2554.         sendconsoletext(playerId, message)
  2555.     elseif output_environment == 2 or output_environment == 3 then
  2556.         message = formatOutput(message, 6, 100)
  2557.         registertimer(0, "delayMsg", {message, playerId})
  2558.     end
  2559.     if log and playerCheck then
  2560.         cmdlog("Response to " .. getname(playerId) .. " (" .. PlayerClass[playerId].admin_entry.name .. "): " .. message)
  2561.     end
  2562.  
  2563.     -- this will reset all the properties of cmdreply
  2564.     if tempmessage == cmdreply then cmdreply(true) end
  2565. end
  2566.  
  2567. local function getscorelimit()
  2568.     if gametype == 1 then
  2569.         return readint(addresses.ctf_globals + 0x18)
  2570.     elseif gametype == 2 then
  2571.         return scorelimit
  2572.         --return readbyte(addresses.gametype_base + 0x58, score)
  2573.     elseif gametype == 3 then
  2574.         return readint(addresses.oddball_globals)
  2575.     elseif gametype == 4 then
  2576.         return readint(addresses.koth_globals + team*4)
  2577.     elseif gametype == 5 then
  2578.         return readint(addresses.race_globals + team*4 + 0x88)
  2579.     else
  2580.         return readbyte(addresses.gametype_base + 0x58)
  2581.     end
  2582. end
  2583.  
  2584. local function setscorelimit(score)
  2585.     if gametype == 1 then
  2586.         writeint(addresses.ctf_globals + 0x18, score)
  2587.     elseif gametype == 2 then
  2588.         scorelimit = score
  2589.         --writebyte(addresses.gametype_base + 0x58, score)
  2590.     elseif gametype == 3 then
  2591.         writeint(addresses.oddball_globals, score)
  2592.     elseif gametype == 4 then
  2593.         writeint(addresses.koth_globals + team*4, score)
  2594.     elseif gametype == 5 then
  2595.         writeint(addresses.race_globals + team*4 + 0x88, score)
  2596.     else
  2597.         writebyte(addresses.gametype_base + 0x58, score)
  2598.     end
  2599. end
  2600.  
  2601. local function getscore(playerId)
  2602.     if gametype == 1 then
  2603.         return readshort(getplayer(playerId) + 0xC8)
  2604.     elseif gametype == 2 then
  2605.         return player_scores[playerId]
  2606.         --return readint(addresses.slayer_globals + 0x40 + playerId*4)
  2607.     elseif gametype == 3 then
  2608.         local oddball_game = readbyte(addresses.gametype_base + 0x8C)
  2609.         if oddball_game == 0 or oddball_game == 1 then
  2610.             return readint(addresses.oddball_globals + 0x84 + playerId*4)
  2611.         else
  2612.             return readint(addresses.oddball_globals + player*4 + 0x104)
  2613.         end
  2614.     elseif gametype == 4 then
  2615.         return readshort(getplayer(playerId) + 0xC4)
  2616.     elseif gametype == 5 then
  2617.         return readshort(getplayer(playerId) + 0xC6)
  2618.     end
  2619. end
  2620.  
  2621. local function setscore(playerId, score)
  2622.     if gametype == 1 then
  2623.         writeshort(getplayer(playerId)+0xC8, score)
  2624.     elseif gametype == 2 then
  2625.         if team_play then
  2626.             local curscore = player_scores[playerId]
  2627.             local diff = math.abs(score - curscore)
  2628.             if curscore > score then
  2629.                 team_scores[getteam(playerId)] = team_scores[getteam(playerId)] + curscore
  2630.             elseif curscore < score then
  2631.                 team_scores[getteam(playerId)] = team_scores[getteam(playerId)] - curscore
  2632.             end
  2633.         end
  2634.         player_scores[playerId] = score
  2635.         writeshort(addresses.slayer_globals + 0x40 + playerId*4, score)
  2636.     elseif gametype == 3 then
  2637.         local oddball_game = readbyte(addresses.gametype_base + 0x8C)
  2638.         if oddball_game == 0 or oddball_game == 1 then
  2639.             writeint(addresses.oddball_globals + 0x84 + playerId*4, score * 30)
  2640.         else
  2641.             writeint(addresses.oddball_globals + 0x84 + playerId*4, score)
  2642.         end
  2643.     elseif gametype == 4 then
  2644.         writeshort(getplayer(playerId) + 0xC4, score * 30)
  2645.     elseif gametype == 5 then
  2646.         writeshort(getplayer(playerId) + 0xC6, score)
  2647.     end
  2648. end
  2649.  
  2650. local function getteamscore(team)
  2651.     if gametype == 1 then
  2652.         return readint(addresses.ctf_globals + team*4 + 0x10)
  2653.     elseif gametype == 2 then
  2654.         return team_scores[team]
  2655.         --return readint(addresses.slayer_globals + team*4)
  2656.     elseif gametype == 3 then
  2657.         return readint(addresses.oddball_globals + team*4 + 0x4)
  2658.     elseif gametype == 4 then
  2659.         return readint(addresses.koth_globals + team*4)
  2660.     elseif gametype == 5 then
  2661.         return readint(addresses.race_globals + team*4 + 0x88)
  2662.     end
  2663. end
  2664.  
  2665. local function setteamscore(team, score)
  2666.     if gametype == 1 then
  2667.         writeint(addresses.ctf_globals + team*4 + 0x10, score)
  2668.     elseif gametype == 2 then
  2669.         team_scores[team] = score
  2670.         --writeint(addresses.slayer_globals + team*4, score)
  2671.     elseif gametype == 3 then
  2672.         writeint(addresses.oddball_globals + team*4 + 0x4, score)
  2673.     elseif gametype == 4 then
  2674.         writeint(addresses.koth_globals + team*4, score)
  2675.     elseif gametype == 5 then
  2676.         writeint(addresses.race_globals + team*4 + 0x88, score)
  2677.     end
  2678. end
  2679.  
  2680. local function WriteChangeLog()
  2681.     local file = io.open("changelog_" .. script_version .. ".txt", "w")
  2682.     local changelog = {}--TM.New()
  2683.     changelog[#changelog+1] = "Changelog for Commands Script"
  2684.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2685.     changelog[#changelog+1] = "Commands Version 5.2 The 'Nimbus' Release (Released __, 2015)"
  2686.     changelog[#changelog+1] = "--Added a firefist command, to be explained later."
  2687.     changelog[#changelog+1] = "--Readded the ghost and unghost commands due to many requests"
  2688.     changelog[#changelog+1] = "--Added a central (remote) banlist feature. Please check out the readme for information on how to use it."
  2689.     changelog[#changelog+1] = "--Ban reasons will now show 'unbanned by (admin name)' when they have been unbanned."
  2690.     changelog[#changelog+1] = "--Even more bug fixes and small features, including compatibility with Sapp."
  2691.     changelog[#changelog+1] = "--Removed all the memoizing crap that I put in the previous version. It was causing a lot of rare issues, and probably wasn't helping performance much"
  2692.     changelog[#changelog+1] = "--Fixed an issue that happened onload that was caused by people using windows default notepad to edit the init.txt"
  2693.     changelog[#changelog+1] = "--Added 'farthest' expression for player arguments, so you can now do things like /kill farthest to kill the farthest player to you."
  2694.     changelog[#changelog+1] = "--Added 'nearest' expression for player arguments, so you can now do things like /kill nearest to kill the nearest player to you."
  2695.     changelog[#changelog+1] = "--Added colors as player arguments, you can now pass colors as player expressions like /kill yellow will kill all yellow people in the server"
  2696.     changelog[#changelog+1] = "--Improved the killingspree feature. It will now announce when someone's spree has ended, and how many kills they racked up."
  2697.     changelog[#changelog+1] = "--Removed 'log' as an alias for the login command so as not to interfere with the already existing 'log' command from Sapp."
  2698.     changelog[#changelog+1] = "--Fixed a bug that would cause the 'list' command to crash if there were no admins on the server."
  2699.     changelog[#changelog+1] = "--Fixed a bug with the Noweapons command."
  2700.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2701.     changelog[#changelog+1] = "Commands Version 5.13 The 'Nimbus' Release (Released February 21th, 2015)"
  2702.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2703.     changelog[#changelog+1] = "--Fixed a few minor bugs, there was a couple of issues with the banlist saving/reloading that happened in rare situations"
  2704.     changelog[#changelog+1] = "--Revamped even more code for optimization, and added lots of memoizing."
  2705.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2706.     changelog[#changelog+1] = "Commands Version 5.01 The 'Nimbus' Release (Released February 20th, 2015)"
  2707.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2708.     changelog[#changelog+1] = "--Fixed a very minor issue with banlist reloading. (was still loading from unused_banlist.txt, not a major problem)"
  2709.     changelog[#changelog+1] = "--Found out that the 'tbag' feature Aelite added was only supposed to apply to kills, so that is now a thing"
  2710.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2711.     changelog[#changelog+1] = "Commands Version 5.0 The 'Nimbus' Release (**WIZARD IS BACK** Released February 19, 2015)"
  2712.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2713.     changelog[#changelog+1] = "--You can change logfile and text files with the following new commands: sv_sharedhash_file, sv_banlist_file, sv_admin_file, sv_commands_file and sv_kickbans_file"
  2714.     changelog[#changelog+1] = "--This script will no longer load the defaults.txt if this script was loaded from the persistent folder (Phasor Only)"
  2715.     changelog[#changelog+1] = "--Time arguments for all commands have changed. All now use the format 5d 3s 2y 5m etc. If you do not specify a character (cywdhms) at the end of your time, then it will default to seconds, so something like sv_respawn_time 500m is different than sv_respawn_time 500."
  2716.     changelog[#changelog+1] = "--Commands that use a player's IP now appends a /24 at the end, which contains the range of 256 addresses within the range of the original IP address. That means if you use sv_ipban 1 and player 1 has an IP of 192.168.0.1, it will ban all the IPs from 192.168.0.0 through 192.168.0.255. This is just a default, you can change it to the old way by appending a /32 at the end of the player."
  2717.     changelog[#changelog+1] = "--The mute command is now the same command as textban, unmute will now untextban a player while sv_unban will unban a textban ID (from sv_banlist)"
  2718.     changelog[#changelog+1] = "--Timestamps added to the ban files are now YY-MM-DD HH:MM:SS instead of just a huge number that represents seconds (you can modify ban expire time a lot easier now)"
  2719.     changelog[#changelog+1] = "--This script will now load sapp's 'ipbans.txt' file."
  2720.     changelog[#changelog+1] = "--Loading/saving of admins/bans are much more reliable now, the script will error if your file is formatted incorrectly"
  2721.     changelog[#changelog+1] = "--All scripted game variables (like deathless, infinite ammo, noweapons) now are integrated completely and will not spam the output window onnewgame anymore"
  2722.     changelog[#changelog+1] = "--Kick/Ban/Mute commands now let you pass reason and time normally, you don't have to use _ for reasons anymore."
  2723.     changelog[#changelog+1] = "--All structures now follow a global naming scheme that I plan to use in all my scripts from now on"
  2724.     changelog[#changelog+1] = "--All code now uses my phasor functions to get addresses (getplayerobject, getplayerweapon, etc) for increased performance"
  2725.     changelog[#changelog+1] = "--This script now uses local variables to optimize performance."
  2726.     changelog[#changelog+1] = "--Revamped ALL functions to execute faster with better code. Some of them I haven't even touched since version 1.0. The first version."
  2727.     changelog[#changelog+1] = "--Added a /disconnect and sv_disconnect command which will give a player a 'lost network connection' screen"
  2728.     changelog[#changelog+1] = "--Removed a few useless commands that never did work but somehow people found out about (probably because of /list lol)"
  2729.     changelog[#changelog+1] = "--Gethelp added. Usage: sv_gethelp (command) or /help (command) without ()"
  2730.     changelog[#changelog+1] = "--Global rcons functionality updated (see guide for details)"
  2731.     changelog[#changelog+1] = "--List command updated so it will not take a 'page' argument. To get a list of commands, type sv_list or /list"
  2732.     changelog[#changelog+1] = "--Organized all commands by table so now all commands are fully documented with help notes and everything"
  2733.     changelog[#changelog+1] = "--textbanlist, iprangebanlist, ipbanlist, and namebanlist are all deprecated. Commands will save the bans in the 'banned.txt' (or whatever sv_banlist_file is set to (banned.txt by default)) file from now on."
  2734.     changelog[#changelog+1] = "--Commands now uses admins.txt for both hash admins and IP admins, ipadmins.txt will still be read for backwards compatibility."
  2735.     changelog[#changelog+1] = "--The old deprecated ban files will now have 'archived_' in front of them. Same goes for the admin files."
  2736.     changelog[#changelog+1] = "--Commands will automatically load the old ban files for backwards compatibility so you do not need to do anything with that. Just know that the old files won't get updated anymore."
  2737.     changelog[#changelog+1] = "--All banlist and unban commands are now deprecated and have been removed. Use sv_banlist and sv_unban to view the banlist and unban people."
  2738.     changelog[#changelog+1] = "--Anyone joining with a hacked hash (like hash 'myfakehashtrollu') will not be allowed into the server"
  2739.     changelog[#changelog+1] = "--Chat commands now directly execute server commands (/e is now deprecated) and the script is much smaller because of it"
  2740.     changelog[#changelog+1] = "--Rewrote BOS functionality"
  2741.     changelog[#changelog+1] = "--Rewrote the Spawn functionality and made the code 10x smaller by using better and more efficient coding"
  2742.     changelog[#changelog+1] = "--I've fixed things here and there, added things that were removed from my original Commands."
  2743.     changelog[#changelog+1] = "--Fixed /read (it never worked). Also accepts number structs."
  2744.     changelog[#changelog+1] = "--Fixed /write to not break on invalid syntax. Also accepts number structs.."
  2745.     changelog[#changelog+1] = "--Added randomred and randomblue to expressions list."
  2746.     changelog[#changelog+1] = "--Added a control command (FINALLY)"
  2747.     changelog[#changelog+1] = "--Fixed sending negative numbers to setplasmas and setfrags"
  2748.     changelog[#changelog+1] = "--Fixed occasional glitches with setammo."
  2749.     changelog[#changelog+1] = "--Rewrote the access system. You now do not have to start at lvl 0 being the highest, you can now have levels in any order"
  2750.     changelog[#changelog+1] = "--Script also tells you if your access.ini is not formatted correctly and why and then raises an error."
  2751.     changelog[#changelog+1] = "--Changed sv_status to sv_status_more as to not interfere with normal sv_status"
  2752.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2753.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2754.     changelog[#changelog+1] = "Commands Version 4.2(Released August 3rd, 2013)"
  2755.     changelog[#changelog+1] = "--Update Reason: Bug fixes and Added Features"
  2756.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2757.         changelog[#changelog+1] = ""
  2758.     changelog[#changelog+1] = "--Added the time limit address thanks to wizard. sv_time_cur is now compatible with Halo CE"
  2759.     changelog[#changelog+1] = "--Added the sendconsoletext overload to the command scripts. Thank you Nuggetz."
  2760.     changelog[#changelog+1] = "--Added 'sv_hash_duplicates' command which enables/disables the checking of duplicate keys in the server."
  2761.     changelog[#changelog+1] = "--Added 'sv_multiteam_vehicles' Enables/Disables the ability to enter a vehicle with another playerId in FFA."
  2762.         changelog[#changelog+1] = ""
  2763.     changelog[#changelog+1] = "--Modified all tables that used the hash for identication, and changed it to IP"
  2764.         changelog[#changelog+1] = ""
  2765.     changelog[#changelog+1] = "--Fixed minor bug with votekick"
  2766.     changelog[#changelog+1] = "--Fixed issue with sv_superban"
  2767.     changelog[#changelog+1] = "--Fixed AntiCaps command. WARNING: If you use a chatfilter script. Load that script before this one."
  2768.     changelog[#changelog+1] = "--Fixed issue with team play detection"
  2769.     changelog[#changelog+1] = "--Fixed minor bugs."
  2770.         changelog[#changelog+1] = ""
  2771.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2772.     changelog[#changelog+1] = "Commands Version 4.1(Released July 23rd, 2013)"
  2773.     changelog[#changelog+1] = "--Update Reason: Bug fixes"
  2774.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2775.         changelog[#changelog+1] = ""
  2776.     changelog[#changelog+1] = "--Fixed minor bugs"
  2777.         changelog[#changelog+1] = ""
  2778.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2779.     changelog[#changelog+1] = "Commands Version 4.0(Released July 21st, 2013)"
  2780.     changelog[#changelog+1] = "--Update Reason: make it compatible with new Phasor"
  2781.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2782.         changelog[#changelog+1] = ""
  2783.     changelog[#changelog+1] = "--Added 'sv_addrcon' This gives you the ability to have more than one rcon."
  2784.     changelog[#changelog+1] = "--Added 'sv_delrcon' Removes rcons from the rcon list."
  2785.     changelog[#changelog+1] = "--Added 'sv_rconlist' Displays all available rcons"
  2786.     changelog[#changelog+1] = "--Added 'sv_iprangeban' bans entire IP Range"
  2787.     changelog[#changelog+1] = "--Added 'sv_iprangeunban' Removes an IP from the banlist"
  2788.     changelog[#changelog+1] = "--Added 'sv_iprangebanlist' Shows all IP's banned"
  2789.     changelog[#changelog+1] = "--Added 'sv_read' command."
  2790.     changelog[#changelog+1] = "--Added 'sv_load' shortcut for sv_script_load."
  2791.     changelog[#changelog+1] = "--Added 'sv_unload' shortcut for sv_script_unload."
  2792.     changelog[#changelog+1] = "--Added 'sv_resetplayer' and '/resetplayer' removes all troll command settings."
  2793.     changelog[#changelog+1] = "--Added 'sv_damage' Increases playerId damage."
  2794.     changelog[#changelog+1] = "--Added reason to sv_textban"
  2795.     changelog[#changelog+1] = "--Added Command_Balance local function since sv_team_balance is not a command anymore for the moment."
  2796.         changelog[#changelog+1] = ""
  2797.     changelog[#changelog+1] = "--Modified Reason is said to the public"
  2798.     changelog[#changelog+1] = "--Modified Adminblocker the admin is notified if a command is being executed on them."
  2799.     changelog[#changelog+1] = "--Modified AntiSpam changed from boolean to a type: all, players, off"
  2800.     changelog[#changelog+1] = "--Modified 'sv_commands' -> 'sv_cmds'"
  2801.     changelog[#changelog+1] = "--Modified 'sv_ipban' now accepts IP's'"
  2802.     changelog[#changelog+1] = "--Modified AFK detection. Works better"
  2803.     changelog[#changelog+1] = "--Modified NameBan. Banned names are changed to 'playerId' on join."
  2804.     changelog[#changelog+1] = "--Modified Tbag Detection: Detects victim location. You must be near the victims death to be able to tbag him/her."
  2805.         changelog[#changelog+1] = ""
  2806.     changelog[#changelog+1] = "--Fixed most bugs with the new phasor"
  2807.     changelog[#changelog+1] = "--Fixed 'sv_scrimmode'"
  2808.     changelog[#changelog+1] = "--Fixed @ bug"
  2809.     changelog[#changelog+1] = "--Fixed AccessMerging bug when -1 was given to any other level other than 0"
  2810.     changelog[#changelog+1] = "--Fixed minor Bos Bug"
  2811.     changelog[#changelog+1] = "--Fixed setscore bug"
  2812.         changelog[#changelog+1] = ""
  2813.     changelog[#changelog+1] = "--Removed sv_pinglist command"
  2814.     changelog[#changelog+1] = "--Removed sv_hash_check, sv_version, and sv_version_check. Phasor has them built in."
  2815.     changelog[#changelog+1] = "--Removed Portal Blocking"
  2816.     changelog[#changelog+1] = "--Removed /setname until further notice"
  2817.         changelog[#changelog+1] = ""
  2818.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2819.     changelog[#changelog+1] = "Commands Version 3.0.1 (Released February 28th, 2013)"
  2820.     changelog[#changelog+1] = "--Update Reason: Mainly Bug Fixes"
  2821.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2822.             changelog[#changelog+1] = ""
  2823.     changelog[#changelog+1] = "--Added sv_scrimmode"
  2824.             changelog[#changelog+1] = ""
  2825.     changelog[#changelog+1] = "--Modified ipadminadd now accepts IP's"
  2826.     changelog[#changelog+1] = "--Modified 'sv_admin_add: Combined sv_admin_add and sv_admin_addh"
  2827.             changelog[#changelog+1] = ""
  2828.     changelog[#changelog+1] = "--Fixed /e bug"
  2829.     changelog[#changelog+1] = "--Fixed spam_max and spam_timeout bugs"
  2830.     changelog[#changelog+1] = "--Fixed textban bugs"
  2831.     changelog[#changelog+1] = "--Fixed superban bugs"
  2832.     changelog[#changelog+1] = "--Fixed ipban bug"
  2833.         changelog[#changelog+1] = ""
  2834.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2835.     changelog[#changelog+1] = "Commands Version 3.0.0 (released February 11th, 2013)"
  2836.     changelog[#changelog+1] = "--Update Reason: Bug Fixes and New Features"
  2837.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2838.         changelog[#changelog+1] = ""
  2839.     changelog[#changelog+1] = "--Added safe guards for the admin system."
  2840.     changelog[#changelog+1] = "--Added Ping List command. Displays the Players ID, Name and Ping level."
  2841.     changelog[#changelog+1] = "--Added System for no Hash and/or IP admins"
  2842.     changelog[#changelog+1] = "--Added a sv_login command so if you are using the System for no Hash and/or IP Admins people with rcon are able to use chat commands"
  2843.     changelog[#changelog+1] = "--Added a sv_status command. It will show the current status of defaults.txt commands."
  2844.     changelog[#changelog+1] = "--Added info shown to the sv_info command"
  2845.     changelog[#changelog+1] = "--Added 'sv_chatcommands' to enable or disable admin chat commands"
  2846.     changelog[#changelog+1] = "--Added 'sv_adminblocker' enables,disables or limits the abiliy of an admin to kick/ban another admin"
  2847.     changelog[#changelog+1] = "--Added 'sv_anticaps'  Enables or Disables the use of caps in the server"
  2848.     changelog[#changelog+1] = "--Added 'sv_antispam' Enables or Disables the antispam system of the script"
  2849.     changelog[#changelog+1] = "--Added 'sv_spammax' Changes the max amount of messages that can be sent in 1 minute"
  2850.     changelog[#changelog+1] = "--Added 'sv_spamtimeout' Changes the time you are muted for spamming"
  2851.     changelog[#changelog+1] = "--Added a time amount that a playerId can be textbanned 'sv_textban [playerId] {time}'. if no time is set then the default is -1 which is forever."
  2852.     changelog[#changelog+1] = "--Added a way to use any command without the 'sv_' Ex: 'sv_admin_add' can be written as 'admin_add' "
  2853.     changelog[#changelog+1] = "--Added a time amount that a playerId can be ipbanned 'sv_ipban [playerId] {time} {message}'. if no time is set then the default is -1 which is forever."
  2854.     changelog[#changelog+1] = "--Added 'sv_bosplayers' to see the available players that can be banned on sight."
  2855.         changelog[#changelog+1] = ""
  2856.     changelog[#changelog+1] = "--Modified how defaults.txt works. If a command is not specified in the defaults.txt file it is set to default by the script so no errors occur during game."
  2857.     changelog[#changelog+1] = "--Modified Tbag function"
  2858.     changelog[#changelog+1] = "--Modified ban, you are now able to send reason(s) for the ban which will be written a file."
  2859.     changelog[#changelog+1] = "--Modified kick, you are now able to send reason(s) for the kick which will be written a file."
  2860.     changelog[#changelog+1] = "--Modified Ipban, you are now able to send reason(s) for the ipban which will be written a file."
  2861.     changelog[#changelog+1] = "--Modified Superban, you are now able to send reason(s) for the superban which will be written a file."
  2862.     changelog[#changelog+1] = "--Modified Votekick. You can only votekick again after 1 minute has passed since last votekick."
  2863.     changelog[#changelog+1] = "--Modified ChangeLevel. The coding for this command has been improved."
  2864.     changelog[#changelog+1] = "--Modified GetHelp"
  2865.         changelog[#changelog+1] = ""
  2866.     changelog[#changelog+1] = "--Fixed Ipban bug"
  2867.     changelog[#changelog+1] = "--Fixed the '/e' command."
  2868.     changelog[#changelog+1] = "--Fixed the 'sv_unmute' command."
  2869.         changelog[#changelog+1] = ""
  2870.     changelog[#changelog+1] = "--Removed sv_command_type and all content related to it"
  2871.     changelog[#changelog+1] = "--Removed redundant code."
  2872.     changelog[#changelog+1] = "--Renamed 'sv_sa_message' to 'sv_serveradmin_message'"
  2873.     changelog[#changelog+1] = "--Renamed 'sv_fj_message' to 'sv_firstjoin_message'"
  2874.     changelog[#changelog+1] = "--Renamed 'sv_wb_message' to 'sv_welcomeback_message'"
  2875.         changelog[#changelog+1] = ""
  2876.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2877.     changelog[#changelog+1] = "Commands Version 2.4.3 (released September 23rd,2012"
  2878.     changelog[#changelog+1] = "--Update Reason: Fixed issues with ServerChat Function."
  2879.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2880.         changelog[#changelog+1] = ""
  2881.     changelog[#changelog+1] = "--Fixed OnServerChat local function error caused Chat Commands to fail."
  2882.         changelog[#changelog+1] = ""
  2883.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2884.     changelog[#changelog+1] = "Commands Version 2.4.2 (released August 29th,2012"
  2885.     changelog[#changelog+1] = "--Update Reason: Fixed issues from version 2.4.1 and new commands."
  2886.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2887.         changelog[#changelog+1] = ""
  2888.     changelog[#changelog+1] = "--Added a change admin level command. You can now change the level of an IP and/or Hash admin  level. 'sv_change_level'"
  2889.     changelog[#changelog+1] = "--Added a Command Type command. You can now change between the way Wizard setup his chat commands, and my way. 'sv_command_type'"
  2890.     changelog[#changelog+1] = "--Added a Command Type command to the default.txt"
  2891.         changelog[#changelog+1] = ""
  2892.     changelog[#changelog+1] = "--ReAdded Private say command"
  2893.     changelog[#changelog+1] = "--ReAdded '/e' command."
  2894.     changelog[#changelog+1] = "--ReAdded Nuke Command."
  2895.     changelog[#changelog+1] = "--ReAdded SetName Command."
  2896.         changelog[#changelog+1] = ""
  2897.     changelog[#changelog+1] = "--Modified Tbag function"
  2898.         changelog[#changelog+1] = ""
  2899.     changelog[#changelog+1] = "--Fixed 'sv_info' command error"
  2900.     changelog[#changelog+1] = "--Fixed OnServerChat, now you wont get 'You are not allowed to use this command' every time you type."
  2901.         changelog[#changelog+1] = ""
  2902.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2903.     changelog[#changelog+1] = "Commands Version 2.4.1 (released August 22nd,2012"
  2904.     changelog[#changelog+1] = "--Update Reason: Fixed issues from version 2.4"
  2905.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2906.         changelog[#changelog+1] = ""
  2907.     changelog[#changelog+1] = "--Fixed 'sv_players_more' issue."
  2908.     changelog[#changelog+1] = "--Fixed 'sv_players' issue."
  2909.     changelog[#changelog+1] = "--Fixed Chat Command issue. If you were admin, then you could do any In-Chat in the script. Check Manual for info on how to add new commands."
  2910.     changelog[#changelog+1] = "--Fixed Command issue. If you were admin, then you could do any In-Console in the script. Check Manual for info on how to add new commands."
  2911.         changelog[#changelog+1] = ""
  2912.     changelog[#changelog+1] = "--Removed Restriction of Portal Blocking. Warning: Modded Maps with portals might cause the server to crash. Hope to fix soon."
  2913.         changelog[#changelog+1] = ""
  2914.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2915.     changelog[#changelog+1] = "Commands Version 2.4 (released August 19th,2012"
  2916.     changelog[#changelog+1] = "--Update Reason: New Features, Fix minor bugs, Remove non-working commands(will be re-add later), and Organize the Script"
  2917.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2918.         changelog[#changelog+1] = ""
  2919.     changelog[#changelog+1] = "--Added Admin Add Hash. You can now add people via hash. So you are able to add people without them being in the server. 'sv_admin_addh'. This is mostly used if you have 5 or more people you want to add at the same time. Another Script is needed to succesfully use this command."
  2920.     changelog[#changelog+1] = "--Added a Portal Blocking Command. If someone is blocking a portal they will be killed. 'sv_pbdet'"
  2921.     changelog[#changelog+1] = "--Added a Private Messaging boolean for the @ in chat. 'sv_pvtmessage'"
  2922.     changelog[#changelog+1] = "--Added Private Messaging to the default.txt"
  2923.     changelog[#changelog+1] = "--Added a Tbagging function."
  2924.     changelog[#changelog+1] = "--Added a Tbagging Boolean Command. 'sv_tbagdet'"
  2925.     changelog[#changelog+1] = "--Added Tbagging Command to the default.txt"
  2926.     changelog[#changelog+1] = "--Added Killing spree Notifications"
  2927.     changelog[#changelog+1] = "--Added a Killing spree Notification command 'sv_killspree'"
  2928.     changelog[#changelog+1] = "--Added Killing spree Notification to the default.txt"
  2929.     changelog[#changelog+1] = "--Added a 'Welcome back' message in EventPlayerJoin. It will only say it if you are not an IP/Hash Admin"
  2930.     changelog[#changelog+1] = "--Added a Welcome back message command. 'sv_welcomeback_message'"
  2931.     changelog[#changelog+1] = "--Added Welcome Back Message to the default.txt"
  2932.     changelog[#changelog+1] = "--Added a 'This is the players first time joining the server' message in EventPlayerJoin"
  2933.     changelog[#changelog+1] = "--Added a Command for Server Admin Message. 'sv_sa_message'"
  2934.     changelog[#changelog+1] = "--Added Server Admin message to the default.txt"
  2935.     changelog[#changelog+1] = "--Added a Command for First Joining Message 'sv_firstjoin_message'"
  2936.     changelog[#changelog+1] = "--Added First Joining Message to the default.txt"
  2937.     changelog[#changelog+1] = "--Added a Command for Unique Counting. 'sv_uniques_enabled'"
  2938.     changelog[#changelog+1] = "--Added Unique Counting to the default.txt"
  2939.     changelog[#changelog+1] = "--Added a 'sv_players_more' Command. This does the same local function as 'sv_players' but it gives you more information on each playerId."
  2940.     changelog[#changelog+1] = "--Added IP to the info Command."
  2941.         changelog[#changelog+1] = ""
  2942.     changelog[#changelog+1] = "--Fixed RTV Enabled Command "
  2943.     changelog[#changelog+1] = "--Fixed VoteKick Enabled Command "
  2944.     changelog[#changelog+1] = "--Fixed info command. "
  2945.     changelog[#changelog+1] = "--Fixed time current command. "
  2946.     changelog[#changelog+1] = "--Fixed Set Teleport Shortcut. 'sv_st' "
  2947.     changelog[#changelog+1] = "--Fixed Teleport Delete Shortcut. 'sv_t del'"
  2948.         changelog[#changelog+1] = ""
  2949.     changelog[#changelog+1] = "--Modified 'sv_players' command. Now it only gives you playerId ID, playerId Name, and playerId Team."
  2950.     changelog[#changelog+1] = "--Modified 'sv_count' command. Now disables if 'sv_uniques_enabled' is disabled."
  2951.     changelog[#changelog+1] = "--Modified Chat Commands: all commands can now be used in chat. Note: Some shortcuts have been transfered but not all."
  2952.     changelog[#changelog+1] = "--Modified GetHelp Commnad"
  2953.     changelog[#changelog+1] = "--Modified List Command"
  2954.         changelog[#changelog+1] = ""
  2955.     changelog[#changelog+1] = "--Removed 'sv_unban' command from the script. Caused the OnSeverCommand local function to crash."
  2956.     changelog[#changelog+1] = "--Removed Private say command"
  2957.     changelog[#changelog+1] = "--Removed '/e' command."
  2958.     changelog[#changelog+1] = "--Removed Nuke Command."
  2959.     changelog[#changelog+1] = "--Removed SetName Command."
  2960.         changelog[#changelog+1] = ""
  2961.     changelog[#changelog+1] = "--Access level crash fixes and a few other features"
  2962.     changelog[#changelog+1] = "--Organized all of the Functions"
  2963.     changelog[#changelog+1] = "--Commented all Main Functions. This will only show on the Commented version of the script"
  2964.         changelog[#changelog+1] = ""
  2965.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2966.     changelog[#changelog+1] = "Commands Version 2.3 (released June 13th 2012"
  2967.     changelog[#changelog+1] = "Mainly fixed up the admin system"
  2968.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2969.         changelog[#changelog+1] = ""
  2970.     changelog[#changelog+1] = "--Added a /crash [playerId] and a sv_crash [playerId] command. Do not use it when the game is ending... you've been warned..."
  2971.     changelog[#changelog+1] = "--Added a /scorelimit and a sv_scorelimit command"
  2972.     changelog[#changelog+1] = "--Added a /a del command."
  2973.     changelog[#changelog+1] = "--Added sv_ipadminadd to the rcon"
  2974.     changelog[#changelog+1] = "--Added a patch that will allow new gametypes to be added without restarting the server"
  2975.     changelog[#changelog+1] = "--Added textbanning. It's like the mute command except it's a permanent"
  2976.         changelog[#changelog+1] = ""
  2977.     changelog[#changelog+1] = "--Modified the AdminList command. Shows a lot more now."
  2978.         changelog[#changelog+1] = ""
  2979.     changelog[#changelog+1] = "--Fixed rcon commands so that the responses show up with the /e command"
  2980.     changelog[#changelog+1] = "--Fixed the ipban command (whoops)"
  2981.     changelog[#changelog+1] = "--Fixed a very small problem with the setcolor command."
  2982.     changelog[#changelog+1] = "--Fixed up the timelimit command :)"
  2983.     changelog[#changelog+1] = "--Fixed ipadmins. They can now use the rcon."
  2984.         changelog[#changelog+1] = ""
  2985.     changelog[#changelog+1] = "--This script no longer uses Phasor admins, if it sees that you are, it will delete all of them and add them to mine, so if you see admin.txt"
  2986.     changelog[#changelog+1] = "turned into admins.txt, don't worry, it's supposed to do that."
  2987.     changelog[#changelog+1] = "--This script enables CE devmode commands (cheat_deathless_player, cheat_medusa, etc)"
  2988.     changelog[#changelog+1] = "--IP admins no longer get removed when you unload the commands script"
  2989.         changelog[#changelog+1] = ""
  2990.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2991.     changelog[#changelog+1] = "Commands Version 2.201 (released on June 5th 2012)"
  2992.     changelog[#changelog+1] = "This is mainly just a bug fix version"
  2993.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2994.         changelog[#changelog+1] = ""
  2995.     changelog[#changelog+1] = "--Added a /setscore and sv_setscore command."
  2996.     changelog[#changelog+1] = "--Added New functionality to /hax and /unhax"
  2997.         changelog[#changelog+1] = ""
  2998.     changelog[#changelog+1] = "--Modified setkills, setassists, and setdeaths to work a little cleaner"
  2999.         changelog[#changelog+1] = ""
  3000.     changelog[#changelog+1] = "--Fixed /commands to show all of the commands."
  3001.     changelog[#changelog+1] = "--Fixed a weird problem with the /enter command (when you ejected it would crash your game)"
  3002.     changelog[#changelog+1] = "--Fixed /a list (i forgot to check for the /, i was only checking for \\a list, so /a list wouldn't work)"
  3003.     changelog[#changelog+1] = "--Fixed falldamage (and also made it so longer falls don't kill you)"
  3004.     changelog[#changelog+1] = "--Fixed /hide, when you leave and another person rejoins with your playerId number, it will no longer hide them (thank you mitch... lol)"
  3005.     changelog[#changelog+1] = "--Fixed a bug when loading this script first, it wouldn't let other scripts control the weapons being assigned on spawn (can't believe i didn't see it earlier, ty nuggets + others)"
  3006.         changelog[#changelog+1] = ""
  3007.     changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  3008.     changelog[#changelog+1] = "Commands Version 2.2 (Released on June 1st 2012)"
  3009.     changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  3010.         changelog[#changelog+1] = ""
  3011.     changelog[#changelog+1] = "--Added unique player tracking. It will keep track of the number of unique players who joined the server"
  3012.     changelog[#changelog+1] = "--Added '/count' Get the number of unique players"
  3013.     changelog[#changelog+1] = "--Added /balance, it executes sv_teams_balance in console"
  3014.     changelog[#changelog+1] = "--Added sv_privatesay. Looks like i forgot the sv_command for that"
  3015.     changelog[#changelog+1] = "--Added private chat. Use @(playerId expression) to message someone"
  3016.     changelog[#changelog+1] = "--Added /setcolor. Only works in FFA gametypes."
  3017.     changelog[#changelog+1] = "--Added namebanning to superban."
  3018.     changelog[#changelog+1] = "--Added a \ameban command."
  3019.     changelog[#changelog+1] = "--Added ipadmin deleting"
  3020.         changelog[#changelog+1] = ""
  3021.     changelog[#changelog+1] = "--Modifed 'sv_map' made it so that the sv_map and /m loads the commands script by default"
  3022.     changelog[#changelog+1] = "--Modified the AdminList local function to be a lot more useful"
  3023.         changelog[#changelog+1] = ""
  3024.     changelog[#changelog+1] = "--Fixed Bugs"
  3025.     changelog[#changelog+1] = "--Fixed votekick."
  3026.     changelog[#changelog+1] = "--Fixed /privatesay. It would only let you message one word before"
  3027.     changelog[#changelog+1] = "--Fixed access levels for the script. It kind of worked, but not really."
  3028.     changelog[#changelog+1] = "--Fixed an issue with /timelimit and sv_time_cur"
  3029.     changelog[#changelog+1] = "--Fixed deathless glitch"
  3030.         changelog[#changelog+1] = ""
  3031.     changelog[#changelog+1] = "--Removed some of the spam when the script loads (it was an easy way to accomplish what i wanted at the time)"
  3032.         changelog[#changelog+1] = ""
  3033.     changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  3034.     changelog[#changelog+1] = "Commands Version 2.001"
  3035.     changelog[#changelog+1] = "--Fixed /ipadminadd "
  3036.     changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  3037.     changelog[#changelog+1] = "Commands Version 2.0(Released April 22nd, 2012)"
  3038.     changelog[#changelog+1] = "This is pretty much a rewrite of the entire script. So many new features were added. So many that I don't even want to make this changelog. Anyway, I'm forcing myself to make it. So here it is:"
  3039.     changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  3040.         changelog[#changelog+1] = ""
  3041.     changelog[#changelog+1] = "--Added hash check manipulation. You can now disable or enable hash checking (meaning that cracked versions can join your server if its disabled, but that also means everyone is unbannable if they spoof their key (which most people don't know how to do)."
  3042.     changelog[#changelog+1] = "--Added sv_revoke and /revoke. The syntax is /revoke [playerId]. This will take away someone's admin who is currently in the server."
  3043.     changelog[#changelog+1] = "--Added /os, this will give you an Overshield (syntax is /os [playerId])"
  3044.     changelog[#changelog+1] = "--Added a command to view all admins on the server, syntax is: /a list"
  3045.     changelog[#changelog+1] = "--Added a command to view the current admins in the server. Syntax is: /viewadmins"
  3046.     changelog[#changelog+1] = "--Added a command to view the server specs (processor speed, model name, manufacturer). Syntax is /specs, or sv_specs in console"
  3047.     changelog[#changelog+1] = "--Added another playerId expression. Now you are able to use 'rand' as a playerId name So like '/k rand' would kick a rand person"
  3048.     changelog[#changelog+1] = "--Added version changing. You can change to any version of Halo. Syntax is: /version {version} or sv_version {version} in console."
  3049.     changelog[#changelog+1] = "--Added version check removal. You can enable or disable version checking. Having this disabled means that any person on any version can join your server (please note that your server will only appear on the server you specify in the version command)"
  3050.     changelog[#changelog+1] = "--Added a defaults.txt. This text file gets called on server startup."
  3051.     changelog[#changelog+1] = "--Added a sv_commands and a /commands. This will show all the commands that exist for this script."
  3052.     changelog[#changelog+1] = "--Added a /hide and a /unhide command, these will make you totally hidden from everyone else in the server. It also removes you from the scoreboard, however, it only works with players that join after you execute it. People in the server at the time that you use it will still see you on the scoreboard."
  3053.     changelog[#changelog+1] = "--Added a parameter to '/spd'. Syntax is /spd [playerId] {speed}. Doing /spd [playerId] will show you their current speed."
  3054.     changelog[#changelog+1] = "--Added another parameter to '/t'. Syntax is '/t list', this will show you the list of teleports for the map."
  3055.     changelog[#changelog+1] = "--Added infinite nades to sv_infinite_ammo"
  3056.     changelog[#changelog+1] = "--Added a '/banlist' command to chat. This will show you the banlist."
  3057.     changelog[#changelog+1] = "--Added a '/alias' command to chat. This will show aliases of the playerId you pick. Kinda glitchy, oxide's fault, not mine."
  3058.     changelog[#changelog+1] = "--Added sv_rtv_needed [decimal 0 to 1]"
  3059.     changelog[#changelog+1] = "--Added sv_votekick_needed [decimal 0 to 1]"
  3060.     changelog[#changelog+1] = "--Added sv_rtv_enabled [true or false, 1 or 0]"
  3061.     changelog[#changelog+1] = "--Added sv_votekick_enabled [true or false, 1 or 0]"
  3062.     changelog[#changelog+1] = "--Added ipbanning. Syntax is sv_ipban, sv_ipbanlist, sv_ipunban, and for chat: /ipban, /ipbanlist, /ipunban."
  3063.     changelog[#changelog+1] = "--Added 'sv_launch' and '/launch'. Syntax is 'sv_launch [playerId]' or '/launch [playerId]'"
  3064.     changelog[#changelog+1] = "--Added a control command. Syntax is 'sv_control [victim] [controller]' or '/c [victim] [controller]' in chat."
  3065.     changelog[#changelog+1] = "--Added a privatesay command. Syntax is 'sv_privatesay [playerId] [message]' or '/privatesay [playerId] [message]' in chat"
  3066.     changelog[#changelog+1] = "--Added temp.txt managing, basically so values that you set the previous map won't be erased when the next map loads (like when you do sv_respawn_time 5, and it goes back to default everytime you reload the script)"
  3067.     changelog[#changelog+1] = "--Added ipadminadding. You can add admins via IP now. Syntax is sv_ipadminadd (playerId) (nickname) (level) or /ipadminadd (playerId) (nickname) (level) in chat."
  3068.     changelog[#changelog+1] = "--Added: Now includes logging. This will log directly to commands.log in the log folder"
  3069.     changelog[#changelog+1] = "--Added: If you do not have an access file, this script will make one for you."
  3070.     changelog[#changelog+1] = "--Added '/e' command."
  3071.         changelog[#changelog+1] = ""
  3072.     changelog[#changelog+1] = "--Modified /timelimit and sv_timelimit. It will change the ingame timelimit (time remaining) as well as the timelimit for every game after that. This still breaks with sv_reloadscripts."
  3073.     changelog[#changelog+1] = "--Modified sv_afk was changed to 'sv_setafk'. Thought it was a better name for the command."
  3074.         changelog[#changelog+1] = ""
  3075.     changelog[#changelog+1] = "--Fixed /setname, it will change your name, but for others to see it it requires a rejoin."
  3076.     changelog[#changelog+1] = "--Fixed the admin system, before you had to do sv_reloadscripts after you added someone, that's been fixed."
  3077.     changelog[#changelog+1] = "--Fixed access.ini not syncing with chat commands, meaning if you have sv_kick in your access level, you can now use /k in the chat."
  3078.     changelog[#changelog+1] = "--Fixed a bug with /ammo, this now works correctly. Syntax is: /ammo [playerId] [type (1 or 2)] [ammo] or sv_setammo in console."
  3079.     changelog[#changelog+1] = "--Fixed smiley's BOS commands, thanks to bvigil for telling me what it was supposed to do."
  3080.     changelog[#changelog+1] = "--Fixed a bug with /tp and sv_teleport_pl, which were crashing when the other playerId was dead."
  3081.     changelog[#changelog+1] = "--Fixed /setplasmas, thank you sanity for the notice..."
  3082.     changelog[#changelog+1] = "--Fixed a reported bug with /noweapons... I was never able to reproduce it, so I must have indirectly fixed it."
  3083.     changelog[#changelog+1] = "--Fixed /info which would crash when you used a playerId expression that was not a number."
  3084.     changelog[#changelog+1] = "--Fixed a couple of bugs with rtv and votekick (whoops)"
  3085.     changelog[#changelog+1] = "--Fixed a bug with 'sv_mute' and '/mute'. You can no longer mute admins."
  3086.     changelog[#changelog+1] = "--Fixed /st. This will set a teleport location to wherever you are standing. Syntax is: /st [teleport name]"
  3087.     changelog[#changelog+1] = "--Fixed the spawngun. Syntax is /setmode (playerId) spawngun (object)"
  3088.     changelog[#changelog+1] = "--Fixed Smiley's BoS (Ban On Sight) system. I had to rewrite 80% of it to work with the new Phasor. It now also bans the person's IP."
  3089.         changelog[#changelog+1] = ""
  3090.     changelog[#changelog+1] = "--Sorry this took so long, it took a while to rewrite the whole script. Technically it's been done for a while, i was just waiting for Oxide to release phasor 059. But that won't happen until after june, and there's no way i'm keeping you all waiting. Hope you enjoy it."
  3091.         changelog[#changelog+1] = ""
  3092.     changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  3093.     changelog[#changelog+1] = "Commands Version 1.0"
  3094.     changelog[#changelog+1] = "First Official Release (January or something 2012)"
  3095.     changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  3096.         changelog[#changelog+1] = ""
  3097.     changelog[#changelog+1] = "--Script Created"
  3098.     file:write(concat(changelog, "\n"))
  3099.     file:close()
  3100. end
  3101.  
  3102. function tempBanPlayer(playerIndex)
  3103.     halo_svcmd("sv_ban " .. playerIndex .. " 1s")
  3104.     return false
  3105. end
  3106.  
  3107. local function addBan(player_name, player_hash, player_ip, ban_time, ban_type, ban_reason)
  3108.  
  3109.     local banid, ban_entry, bancount, name, reason
  3110.     local args = defaults.remote_bansystem
  3111.     -- check if they've already been banned before
  3112.     for id = 1,#ban_table do ban_entry = ban_table[id]
  3113.         if not args or (ban_entry.remote and args.mode >= 1 or not ban_entry.remote and args.mode ~= 2) then
  3114.             if ban_type == ban_entry.type then
  3115.                 if player_hash and player_hash == ban_entry.hash then
  3116.                     banid = id
  3117.                     break
  3118.                 elseif player_ip and ban_entry.ip and netMatch(ban_entry.ip, player_ip) then
  3119.                     banid = id
  3120.                     break
  3121.                 end
  3122.             end
  3123.         end
  3124.     end
  3125.  
  3126.     if banid then
  3127.         bancount = ban_entry.count + 1
  3128.         name = ban_entry.name
  3129.         reason = ban_entry.reason
  3130.     else
  3131.         bancount = 1
  3132.         banid = #ban_table+1
  3133.         ban_entry = {}--TM.New()
  3134.     end
  3135.  
  3136.     ban_entry.count = bancount
  3137.     ban_entry.name = (name and not find(name, player_name) and (name .. " / ") or "") .. player_name
  3138.     ban_entry.hash = player_hash
  3139.     ban_entry.ip = player_ip
  3140.     ban_entry.time = ban_time > 0 and ban_time + os.time() or ban_time == -1 and -1 or ban_penalty[bancount]
  3141.     ban_entry.type = ban_type
  3142.     ban_entry.reason = (reason and not find(reason, ban_reason) and (reason .. " / ") or "") .. ban_reason
  3143.  
  3144.     ban_table[banid] = ban_entry
  3145.  
  3146.     if args and args.mode >= 2 then
  3147.         --print("ADDING TO REMOTE BANLIST. Host: " .. tostring(args.http_source) .. " Body: " .. tostring("&bans=" .. toBanTextEntry(ban_entry)))
  3148.         print(http.request(args.http_source, "&bans=" .. toBanTextEntry(ban_entry)) .. ",&unban=false")
  3149.     end
  3150.  
  3151.     updateBanFiles(bantype)
  3152. end
  3153.  
  3154. local function checkaccess(command, access)
  3155.     command = Commands[command] or command
  3156.     local access_entry = access_table[access]
  3157.     return access_entry and (access_entry.allcommands or access_entry[command]) or false
  3158. end
  3159.  
  3160. -- Returns true if equal, false if both not admin, or the playerId more powerful.
  3161. -- It's important to note that if the Server is being compared as a playerId, it's value is nil.
  3162. local function getMorePowerfulPlayer(playerId1, playerId2)
  3163.     -- the Server is the most powerful admin.
  3164.     if not playerId1 then
  3165.         return not playerId2 or playerId1
  3166.     elseif not playerId2 then
  3167.         return not playerId1 or playerId2
  3168.     end
  3169.  
  3170.     local access1 = access_table[getaccess(playerId1)]
  3171.     access1 = access1 and #access1 or -1
  3172.     local access2 = access_table[getaccess(playerId2)]
  3173.     access2 = access2 and #access2 or -1
  3174.     return access1 > access2 and playerId1 or access1 < access2 and playerId2 or access1 > 0
  3175. end
  3176.  
  3177. local function checkAdminBlockerAccess(executorPlayerId, playerId)
  3178.     local allowed = getMorePowerfulPlayer(executorPlayerId, playerId)
  3179.     return defaults.adminblocker == "Unsafe" or defaults.adminblocker == "Lenient" and (allowed == executorPlayerId or allowed == true) or defaults.adminblocker == "Moderate" and allowed == executorPlayerId or access_table[getaccess(executorPlayerId)] == -1
  3180. end
  3181.  
  3182. local function Say(message)
  3183.     for playerId = 0,15 do
  3184.         if getplayer(playerId) then
  3185.             sendconsoletext(playerId, message)
  3186.         end
  3187.     end
  3188. end
  3189.  
  3190. local function capitalizeWords(str, amount)
  3191.     return gsub(str, '(%a)(%a+)', function(cap, rest) return ('%1'):upper() .. '%2' end)
  3192. end
  3193.  
  3194. local function trim(str)
  3195.     return gsub(str, "^%s*(.-)%s*$", "%1")
  3196. end
  3197.  
  3198. local function tokenizecmdstring(str, tblToReuse)
  3199.     local strParts = --[[type(tblToReuse) == "table" and tblToReuse:deleteEntries() and tblToReuse or--]] {}--TM.New()
  3200.  
  3201.     --remove spaces at beginning and end
  3202.     str = trim(str) .. " "
  3203.  
  3204.     -- return if no delims found
  3205.     if not find(str, '[%s"]') then strParts[1] = str return strParts end
  3206.  
  3207.     local strPart, newPos, pos
  3208.     repeat
  3209.         strPart,newPos = match(str, '^"(.-)"%s+()', pos)
  3210.         if not strPart then
  3211.             strPart,newPos = match(str, '([^%s]+)%s+()', pos)
  3212.         elseif find(strPart, " ") then
  3213.             strPart = '"' .. strPart .. '"' -- keep quotes around em
  3214.         end
  3215.         pos = newPos
  3216.         strParts[#strParts+1] = strPart
  3217.     until not strPart
  3218.  
  3219.     ::returnSplits::
  3220.  
  3221.     return strParts
  3222. end
  3223.  
  3224. local function tokenizestring(str, ...)
  3225.  
  3226.     local tblToReuse = select(-1, ...)
  3227.     tblToReuse = not tblToReuse and error("bad argument #2 to 'tokenizestring' (delimeter string expected, got nil)") or type(tblToReuse) == "table" and TM.deleteEntries(tblToReuse) and tblToReuse or nil
  3228.  
  3229.     local subs = type(tblToReuse) == "table" and tblToReuse or {}--TM.New()
  3230.     if (...) == "" then
  3231.         for i = 1,#str do
  3232.             subs[#subs+1] = sub(str, i, i)
  3233.         end
  3234.         return subs
  3235.     end
  3236.  
  3237.     local strPart = ""
  3238.     local char, iter, delim
  3239.     for i = 1,#str do
  3240.         char = sub(str, i, i)
  3241.         iter = 1
  3242.         delim = select(iter, ...)
  3243.         repeat
  3244.             if delim == char then
  3245.                 strPart = sub(strPart, 1, -1)
  3246.                 if strPart ~= "" then
  3247.                     subs[#subs+1] = strPart
  3248.                     strPart = ""
  3249.                     goto continue
  3250.                 end
  3251.             end
  3252.             iter = iter + 1
  3253.             delim = select(iter, ...)
  3254.         until not delim or delim == select(-1, ...)
  3255.         strPart = strPart .. char
  3256.         ::continue::
  3257.     end
  3258.  
  3259.     if strPart ~= "" then
  3260.         subs[#subs+1] = strPart
  3261.     end
  3262.  
  3263.     return subs
  3264. end
  3265.  
  3266. -- This function is responsible for creating a command.
  3267. -- I am using table functions in this manner because it is easier to parse commands in groups, it saves me from copying and pasting already existing code.
  3268. -- It also allows me to check to see if the command was coded correctly (before LUA sends an unhelpful error message)
  3269. -- This also allows me to use command aliases, merge help info. It basically keeps all information about a command in one place.
  3270. -- To an average joe reading this script, it may be harder to use this method if you aren't familiar with table structures, but it's better in the end because it is more organized.
  3271. -- Arguements are the name of the command, the commandInfo (as a table, containing aliases, help, and boolean information like scrimMode usage, and each function called for different command arguments (for example, /enter (player) (player2) (seat) vs /enter (vehicleName))
  3272. function Commands.Create(cmdName, commandInfo, ...)
  3273.  
  3274.     -- Display errors if a command was created incorrectly.
  3275.     if not commandInfo.help then error("NO HELP INFO IN COMMAND CREATION: " .. cmdName) end
  3276.     local thisCmdFunc
  3277.     for i = 1,select("#", ...) do
  3278.         thisCmdFunc = select(i, ...)
  3279.         assert(thisCmdFunc.arguments, "NO ARGUMENTS IN COMMAND CREATION: " .. cmdName)
  3280.         assert(thisCmdFunc.arguments.minArgs, "NO MINIMUM ARGUMENTS IN COMMAND CREATION: " .. cmdName)
  3281.         assert(thisCmdFunc.arguments.maxArgs, "NO MAXIMUM ARGUMENTS IN COMMAND CREATION: " .. cmdName)
  3282.         assert(type(thisCmdFunc.func) == "function", "BAD FUNCTION IN COMMAND CREATION: " .. type(thisCmdFunc.func) .. ": " .. cmdName)
  3283.     end
  3284.  
  3285.     --stupid tabs...
  3286.     commandInfo.help = gsub(commandInfo.help, "\t", "")
  3287.  
  3288.     -- Create this command with properties from the Commands class.
  3289.     local newCommand = {name = cmdName, info = commandInfo, ...}
  3290.     setmetatable(newCommand, Commands)
  3291.  
  3292.     -- set command aliases
  3293.     local aliases = commandInfo.aliases
  3294.     if aliases then
  3295.         local commandAliases = Commands.commandAliases
  3296.         local alias_name
  3297.         for i = 1,#aliases do alias_name = aliases[i]
  3298.             commandAliases[alias_name] = cmdName
  3299.             Commands[alias_name] = newCommand
  3300.         end
  3301.     end
  3302.  
  3303.     -- Add this command to the Command list.
  3304.     Commands[cmdName] = newCommand
  3305.     Commands[#Commands+1] = cmdName
  3306. end
  3307.  
  3308. -- This function is called whenever a command is attempting to execute.
  3309. -- Execution function is responsible for determining which overloaded command function to execute
  3310. -- In the case of the user using incorrect arguments, this function will parse an error message to respond with.
  3311. function Commands.Execute(thisCommand, arguments, command, executorPlayerId)
  3312.     local parsedArguments, newErr
  3313.     local err = ""
  3314.     -- Loop through all overloaded functions for this command.
  3315.     for i = 1,#thisCommand do
  3316.         -- Validate and parse all arguments
  3317.         parsedArguments, newErr = thisCommand:validateArguments(arguments, thisCommand[i].arguments, command, executorPlayerId)
  3318.         -- have they passed the correct arguments for this overloaded command?
  3319.         if parsedArguments == true then
  3320.             sendresponse(newErr, executorPlayerId)
  3321.             return
  3322.         elseif newErr == "" then
  3323.             -- call the command, and stop looping.
  3324.             thisCommand[i].func(executorPlayerId, thisCommand:unpackArguments(parsedArguments))
  3325.             return
  3326.         else
  3327.             err = err .. "\n" .. newErr
  3328.         end
  3329.     end
  3330.     sendresponse(err .. gsub(thisCommand.info.help, ".-Syntax: %%s(.-)", "\nInvalid Syntax: " .. command .. "%1"), executorPlayerId)
  3331. end
  3332.  
  3333. -- Needed because I need to pass a specific amount of arguments to command functions.
  3334. function Commands:unpackArguments(myTable)
  3335.     for i = 1,#myTable do
  3336.         if myTable[i] == nil then
  3337.             myTable[i] = false
  3338.         end
  3339.     end
  3340.     return table.unpack(myTable, 1, #myTable)
  3341. end
  3342.  
  3343. -- Validates and parses an argument table
  3344. -- Returns command arguments into lua arguments the Execute function can use.
  3345. -- This function alone is one of the main reasons I converted my if-elseif commands into a metatable. It saved me sooo much duplicate lines of code in the individual commands.
  3346. function Commands:validateArguments(arguments, argumentTypes, command, executorPlayerId)
  3347.     local err = ""
  3348.     local minArgs, maxArgs = argumentTypes.minArgs, argumentTypes.maxArgs
  3349.  
  3350.     -- Make sure they are actually passing a second argument.
  3351.     if not arguments[1] and minArgs > 0 then
  3352.         return true, gsub(self.info.help, "^.-Syntax:.-%%s(.-)$", "\nCorrect Syntax: " .. command .. "%1")
  3353.     end
  3354.  
  3355.     local argument, argType, length
  3356.     local parsedArguments = {}--TM.New()
  3357.  
  3358.     for i = 1,#argumentTypes do argument = arguments[i]
  3359.         argType = argumentTypes[i]
  3360.         if not argument then
  3361.             if #parsedArguments < minArgs then
  3362.                 err = err .. "\nToo few arguments passed to this command! Expected " .. minArgs  .. " - " .. maxArgs .. " got " .. #parsedArguments
  3363.                 goto ReturnArgs
  3364.             end
  3365.         else
  3366.             length = #argument
  3367.         end
  3368.         if argType == "Boolean" then
  3369.             if argument == "true" or argument == "1" then
  3370.                 argument = true
  3371.             elseif argument == "false" or argument == "0" then
  3372.                 argument = false
  3373.             elseif arguments[i] then
  3374.                 err = err .. "\n'" .. arguments[i] .. "' is not a valid Boolean!\nBooleans must be: true or 1 to Enable/Turn On, false or 0 to Disable/Turn Off"
  3375.             end
  3376.         elseif argType == "Percent" then
  3377.             argument = tonumber(argument)
  3378.             argument = argument and (argument <= 1 and argument >= 0 and argument * 100 or argument <= 100 and argument)
  3379.             err = not argument and "Invalid Percentage. Percent arguments must be between 0 and 100." or err
  3380.         elseif argType == "Player" then
  3381.             local players = getvalidplayers(argument, executorPlayerId)
  3382.             if players then
  3383.                 argument = players
  3384.             elseif argument == nil and #arguments >= minArgs and executorPlayerId then
  3385.                 argument = {executorPlayerId}
  3386.             elseif not argument then
  3387.                 err = err .. "\nYou did not specify a Player!"
  3388.             else
  3389.                 err = err .. "\n'" .. arguments[i] .. "' is not a valid Player!"
  3390.             end
  3391.         elseif argType == "Single Player" then
  3392.             local players = getvalidplayers(argument, executorPlayerId)
  3393.             if players then
  3394.                 argument = players[1]
  3395.                 err = players[2] and err .. "\n'" .. arguments[i] .. "' cannot reference more than one player in this command!" or err
  3396.            
  3397.             -- if player wasn't specified, use the executing player.
  3398.             elseif argument == nil and #arguments >= minArgs and executorPlayerId then
  3399.                 argument = executorPlayerId
  3400.             elseif not argument then
  3401.                 err = err .. "\nYou did not specify a player!"
  3402.             else
  3403.                 err = err .. "\n'" .. arguments[i] .. "' is not a valid player!"
  3404.             end
  3405.         elseif argType == "Hash" then
  3406.             argument = match(argument, "%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x+")
  3407.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid Hash!" or err
  3408.         elseif argType == "IP Address" then
  3409.             argument = validate_ipv4(argument)
  3410.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid IP Address!" or err
  3411.         elseif argType == "Team" then
  3412.             argument = team_play and ("Red" and 0 or "Blue" and 1) or tonumber(argument)
  3413.             argument = argument and argument >= 0 and argument <= 15 and argument
  3414.             err = not argument and "The '" .. arguments[i] .. "' team does not exist!" or err
  3415.         elseif argType == "Time And Reason" then
  3416.             argument, parsedArguments[i+1] = getTimeAndReason(concat(arguments, " ", i), self.usesBanCounts and (PlayerClass[parsedArguments[i-1]].bancount or 0) or nil)
  3417.         elseif argType == "Time" then
  3418.             local temp
  3419.             argument, temp = getTimeAndReason(concat(arguments, " ", i), self.usesBanCounts and (PlayerClass[parsedArguments[i-1]].bancount or 0) or nil)
  3420.             err = temp ~= "None Given" and err .. "\n'" ..  concat(arguments, " ", i) .. "' is an Incorrect Time!\nCorrect Examples: 5d 2h 3m 4s" or err
  3421.         elseif argType == "Time String" then
  3422.             local timeErr = not argument and "'" .. argument .. "' is an Incorrect Time!\nCorrect Examples: 5d 2h 3m 4s"
  3423.             if timeErr then goto TimeStringEnd end
  3424.             for j = i+1,#arguments do
  3425.                 timeErr = not arguments[j] and "'" .. arguments[j] .. "' is an Incorrect Time!\nCorrect Examples: 5d 2h 3m 4s"
  3426.                 if timeErr then break end
  3427.                 argument = argument .. " " .. arguments[j]
  3428.             end
  3429.             ::TimeStringEnd::
  3430.             err = timeErr and err .. "\n" .. timeErr or err
  3431.         elseif argType == "Remaining Arguments" then
  3432.             --hprintf(concat(arguments, " ", i))
  3433.             argument = concat(arguments, " ", i)
  3434.         elseif argType == "Access Level" then
  3435.             argument = tonumber(argument)
  3436.             argument = argument and access_table[argument] and argument
  3437.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid Access Level.\nUse 'sv_access_levels' for available levels!" or err
  3438.         elseif argType == "Whole Number" then
  3439.             argument = tonumber(argument)
  3440.             argument = argument and argument >= 0 and argument
  3441.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a Whole (Non-Negative) Number!" or err
  3442.         elseif argType == "Positive Number" then
  3443.             argument = tonumber(argument)
  3444.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a Positive Number!" or err
  3445.         elseif argType == "Number" then
  3446.             argument = tonumber(argument)
  3447.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a Number!" or err
  3448.         elseif argType == "Password" then
  3449.             argument = length and length >= 4 and length <= 8 and argument
  3450.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a Password between 4 and 8 characters!" or err
  3451.         elseif argType == "Map" then
  3452.             argument = valid_maps[argument] and argument
  3453.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid Map!" or err
  3454.         elseif argType == "Object" then
  3455.             argument = objects[argument]
  3456.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid Object!" or err
  3457.         elseif argType == "Gametype" then
  3458.             argument = valid_gametypes[argument] and argument
  3459.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid GameType!" or err
  3460.         elseif argType == "String" then
  3461.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid argument for this command!" or err
  3462.         elseif argType == "AdminBlocker Type" then
  3463.             argument = tonumber(argument) or argument
  3464.             argument = (argument == 0 or argument == "Unsafe") and 0 or (argument == 1 or argument == "Lenient") and 1 or (argument == 2 or argument == "Moderate") and 2 or (argument == 3 or argument == "Strict") and 3 or argument == false and 0
  3465.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid AdminBlocker Type!" or err
  3466.         elseif argType == "Remote Banlist Mode" then
  3467.             argument = tonumber(argument) or argument
  3468.             argument = (argument == 0 or argument == "read-only") and 0 or (argument == 1 or argument == "one-way sync") and 1 or (argument == 2 or argument == "remote-only") and 2 or (argument == 3 or argument == "sync") and 3
  3469.         elseif argType == "Datatype" then
  3470.             argument = (argument == "bit8" or argument == "bit16" or argument == "bit32" or argument == "char" or argument == "byte" or argument == "short" or argument == "word" or argument == "int" or argument == "dword" or argument == "float" or argument == "string" or argument == "widestring") and argument
  3471.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid DataType!" or err
  3472.         elseif argType == "Struct" then
  3473.             argument = (argument == "player" or argument == "object" or argument == "weapon" or argument == "vehicle") and argument
  3474.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid Struct!" or err
  3475.         elseif argType == "Bit" then
  3476.             if argument == "true" or argument == "1" then
  3477.                 argument = 1
  3478.             elseif argument == "false" or argument == "0" then
  3479.                 argument = 0
  3480.             else
  3481.                 err = err .. "\n'" .. arguments[i] .. "' is not a valid Bit!\nBits must be one of the following: true or 1, false or 0"
  3482.             end
  3483.         end
  3484.         parsedArguments[i] = argument
  3485.     end
  3486.  
  3487.     if #parsedArguments > maxArgs and #arguments > maxArgs then
  3488.         err = err .. "\nToo many Arguments passed to this command! Expected " .. minArgs  .. " - " .. maxArgs .. " got " .. #parsedArguments
  3489.     end
  3490.  
  3491.     ::ReturnArgs::
  3492.     return parsedArguments, err
  3493. end
  3494.  
  3495. function Commands:AliasToCommand(cmd)
  3496.     return self.realname
  3497. end
  3498.  
  3499. local function getOperatingSystem()
  3500.     local slash_ident = package.config:sub(1,1)
  3501.     if slash_ident == "\\" then
  3502.         return "Windows"
  3503.     elseif slash_ident == "/" then
  3504.         return "Unix"
  3505.     end
  3506. end
  3507.  
  3508. -- I don't remember why I didn't want to use LFS, maybe I was worried it wouldn't work with SAPP.
  3509. local function lookupFiles(dir)
  3510.     local files = {}
  3511.    
  3512.     local OS = getOperatingSystem()
  3513.     local p
  3514.     if OS == "Windows" then
  3515.         p = io.popen("dir " .. dir .. " /B /O:gn")
  3516.     elseif OS == "Unix" then
  3517.         p = io.popen('find "' .. dir .. '" -type f')
  3518.     end
  3519.     for file in p:lines() do
  3520.         insert(files, file)
  3521.     end
  3522. end
  3523.  
  3524. -- Script Validation
  3525. function Commands:validscripts(...)
  3526.    
  3527.     local dir = getprofilepath() .. "\\scripts\\"
  3528.     local scripts = {}
  3529.    
  3530.     --LuaFileSystem Method.
  3531.     --[[
  3532.     require "lfs"
  3533.     for f in lfs.dir(dir) do
  3534.         if string.find(f, ".lua") then
  3535.             local file = io.open(dir .. f, "r")
  3536.             local str = file:read("*all")
  3537.             if string.find(str, "function GetRequiredVersion()") then
  3538.                 if f ~= "gametypes.lua" then
  3539.                     local script = string.gsub(f, ".lua", "")
  3540.                     if not table.find(scripts, script) then
  3541.                         table.insert(scripts, script)
  3542.                     end
  3543.                 end
  3544.             end
  3545.         end
  3546.     end--]]
  3547.     local bool
  3548.     local files = lookupFiles(dir)
  3549.     local scriptname = ""
  3550.     for i = 1,select("#", ...) do
  3551.         bool = false
  3552.         for i = 1,files do
  3553.             if files[i] == select(1, ...) then
  3554.                 bool = true
  3555.                 break
  3556.             end
  3557.         end
  3558.         if not bool then
  3559.             break
  3560.         end
  3561.     end
  3562. end
  3563.  
  3564. Commands.Create(
  3565.     "rconadd",
  3566.     {
  3567.         aliases = {"addrcon"},
  3568.         help = [[-- Add Rcon Password
  3569.         -- Syntax: %s [Password] {Level}
  3570.         -- Adds a global Rcon password to the list.
  3571.         -- These RCon passwords are different from the normal sv_rcon_password
  3572.         -- The difference is non-admins can use these, while sv_rcon_password only admins can use]]
  3573.     },
  3574.     {
  3575.         arguments = {"Password", "Access Level", minArgs = 1, maxArgs = 2},
  3576.         func = function(executorPlayerId, password, level)
  3577.  
  3578.             if rcon_passwords[password] then
  3579.                 sendresponse(password .. " is already a rcon password", executorPlayerId)
  3580.                 return
  3581.             end
  3582.  
  3583.             rcon_passwords[password] = level or 0
  3584.             sendresponse(password .. " has been added as a rcon password", executorPlayerId)
  3585.         end
  3586.     }
  3587. )
  3588.  
  3589. Commands.Create(
  3590.     "adminadd",
  3591.     {
  3592.         aliases = {"a", "addadmin"},
  3593.         help = [[-- Admin Add
  3594.         -- Syntax: %s [Player or Hash or IP Address] [Nickname] {Level} {Admin Type 'Hash' or 'IP'}
  3595.         -- Adds a person to the admin list.
  3596.         -- This command can take a Hash, IP, or Player as an argument.
  3597.         -- If you do not pass a level, they will automatically be added as a level 0 admin.
  3598.         -- The default for Admin Type is 'hash'. This argument is also case insensitive.]]
  3599.     },
  3600.     {
  3601.         arguments = {"Single Player", "String", "Access Level", "String", minArgs = 2, maxArgs = 4},
  3602.         func = function(executorPlayerId, playerId, nickname, level, admin_type)
  3603.  
  3604.             admin_type = admin_type and lower(admin_type) or "hash"
  3605.             if admin_type ~= "hash" and admin_type ~= "ip" then
  3606.                 sendresponse("'" .. admin_type .. "' is not a valid Admin Type!", executorPlayerId)
  3607.                 return
  3608.             end
  3609.  
  3610.             if not match(nickname, "[%l%u]+") then
  3611.                 sendresponse("Admin nicknames must only contain letters.", executorPlayerId)
  3612.                 return
  3613.             end
  3614.  
  3615.             if PlayerClass[playerId].admin_entry then
  3616.                 sendresponse(getname(playerId) .. " is already a " .. admin_type .. " admin", executorPlayerId)
  3617.                 return
  3618.             end
  3619.  
  3620.             -- Create a new admin entry
  3621.             local newAdmin = {}--TM.New()
  3622.             newAdmin.name = nickname
  3623.             newAdmin.level = level or 0
  3624.             newAdmin.type = admin_type
  3625.  
  3626.             -- Add the admin entry to the admin table.
  3627.             admin_table[admin_type == "hash" and gethash(playerId) or (getip(playerId) .. "/24")] = newAdmin
  3628.             PlayerClass[playerId].admin_entry = newAdmin
  3629.             updateAdminFiles()
  3630.             sendresponse(getname(playerId) .. " is now a " .. admin_type .. " admin!", executorPlayerId)
  3631.         end
  3632.     },
  3633.     {
  3634.         arguments = {"Hash", "String", "Access Level", minArgs = 2, maxArgs = 3},
  3635.         func = function(executorPlayerId, hash, nickname, level)
  3636.  
  3637.             if not match(nickname, "%l+") then
  3638.                 sendresponse("Admin nicknames must only contain letters.", executorPlayerId)
  3639.                 return
  3640.             end
  3641.  
  3642.             for i = 1,#sharedhashes do
  3643.                 if hash == sharedhashes[i] then
  3644.                     sendresponse("This is a shared hash, and therefore cannot become an admin.", executorPlayerId)
  3645.                     return
  3646.                 end
  3647.             end
  3648.  
  3649.             if admin_table[hash] then
  3650.                 sendresponse("That Hash is already an admin.", executorPlayerId)
  3651.                 return
  3652.             end
  3653.  
  3654.             -- Create a new admin entry
  3655.             local newAdmin = {}--TM.New()
  3656.             newAdmin.name = nickname
  3657.             newAdmin.level = level or 0
  3658.             newAdmin.type = "hash"
  3659.  
  3660.             -- Add the admin entry to the admin table.
  3661.             admin_table[hash] = newAdmin
  3662.             for playerId = 0,15 do
  3663.                 if gethash(playerId) == hash then
  3664.                     PlayerClass[playerId].admin_entry = newAdmin
  3665.                 end
  3666.             end
  3667.             updateAdminFiles()
  3668.             sendresponse("That hash has been successfully added to the admin list.", executorPlayerId)
  3669.         end
  3670.     },
  3671.     {
  3672.         arguments = {"IP Address", "String", "Access Level", minArgs = 2, maxArgs = 3},
  3673.         func = function(executorPlayerId, ip_address, nickname, level)
  3674.  
  3675.             if not match(nickname, "%l+") then
  3676.                 sendresponse("Admin nicknames must only contain letters.", executorPlayerId)
  3677.                 return
  3678.             end
  3679.  
  3680.             for index,thisAdmin in next,admin_table do
  3681.                 if thisAdmin.type == "ip" and netMatch(index, ip_address) then
  3682.                     sendresponse("That IP Address is already an admin.", executorPlayerId)
  3683.                     return
  3684.                 end
  3685.             end
  3686.  
  3687.             -- Create a new admin entry
  3688.             local newAdmin = {}--TM.New()
  3689.             newAdmin.name = nickname
  3690.             newAdmin.level = level or 0
  3691.             newAdmin.type = "ip"
  3692.  
  3693.             -- Add the admin entry to the admin table.
  3694.             admin_table[ip_address] = newAdmin
  3695.             for playerId = 0,15 do
  3696.                 if getplayer(playerId) then
  3697.                     if netMatch(ip_address, getip(playerId)) then
  3698.                         PlayerClass[playerId].admin_entry = newAdmin
  3699.                     end
  3700.                 end
  3701.             end
  3702.             updateAdminFiles()
  3703.  
  3704.             sendresponse("That IP Address has been successfully added to the admin list.", executorPlayerId)
  3705.         end
  3706.     }
  3707. )
  3708.  
  3709. Commands.Create(
  3710.     "admindel",
  3711.     {
  3712.         aliases = {"deladmin", "revoke", "a del", "adminrevoke", "revokeadmin"},
  3713.         help = [[-- Admin Delete
  3714.         -- Syntax: %s [Player or Admin Nickname]
  3715.         -- Removes an admin from the admin list by nickname or playerIndex.
  3716.         -- Use 'sv_admin_list' to get a list of admins for their nickname.
  3717.         -- You can also pass a player to this command.]]
  3718.     },
  3719.     {
  3720.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  3721.         func = function(executorPlayerId, players)
  3722.             local playerId, ip
  3723.             for i = 1,#players do playerId = players[i]
  3724.  
  3725.                 if not PlayerClass[playerId].admin_entry then
  3726.                     cmdreply[cmdreply()] = getname(playerId) .. " was never an admin"
  3727.                     goto continue
  3728.                 end
  3729.  
  3730.                 admin_table[gethash(playerId)] = nil
  3731.                 ip = getip(playerId)
  3732.  
  3733.                 for index,thisAdmin in next,admin_table do
  3734.                     if thisAdmin.type == "ip" and netMatch(index, ip) then
  3735.                         admin_table[index] = nil
  3736.                     end
  3737.                 end
  3738.  
  3739.                 PlayerClass[playerId].admin_entry = false
  3740.  
  3741.                 updateAdminFiles()
  3742.                 cmdreply[cmdreply()] = getname(playerId) .. " is no longer an admin"
  3743.  
  3744.                 ::continue::
  3745.             end
  3746.  
  3747.             sendresponse(cmdreply, playerId)
  3748.         end
  3749.     },
  3750.     {
  3751.         arguments = {"String", minArgs = 1, maxArgs = 1},
  3752.         func = function(executorPlayerId, nickname)
  3753.  
  3754.             if not next(admin_table) then
  3755.                 sendresponse("There are no admins on this server.", executorPlayerId)
  3756.                 return
  3757.             end
  3758.  
  3759.             for k,thisAdmin in next,admin_table do
  3760.                 if thisAdmin.name == nickname then
  3761.                     admin_table[k] = nil
  3762.                     sendresponse(nickname .. " is no longer an admin", executorPlayerId)
  3763.                     updateAdminFiles()
  3764.  
  3765.                     local player
  3766.                     for playerId = 0,15 do player = PlayerClass[playerId]
  3767.                         if getplayer(playerId) and player and player.admin_entry == thisAdmin then
  3768.                             player.admin_entry = false
  3769.                         end
  3770.                     end
  3771.  
  3772.                     return
  3773.                 end
  3774.             end
  3775.  
  3776.             sendresponse("There are no admins with a nickname of '" .. nickname .. "'", executorPlayerId)
  3777.         end
  3778.     }
  3779. )
  3780.  
  3781. Commands.Create(
  3782.     "setafk",
  3783.     {
  3784.         aliases = {"afk"},
  3785.         help = [[-- Set AFK Player
  3786.         -- Syntax: %s [Player]
  3787.         -- Sets the specified player to the AFK status.]]
  3788.     },
  3789.     {
  3790.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  3791.         func = function(executorPlayerId, players)
  3792.  
  3793.             local playerId
  3794.             for i = 1,#players do playerId = players[i]
  3795.                 PlayerClass[playerId].afk = true
  3796.                 cmdreply[cmdreply()] = getname(playerId) .. " is now afk"
  3797.             end
  3798.  
  3799.             sendresponse(cmdreply, executorPlayerId)
  3800.         end
  3801.     }
  3802. )
  3803.  
  3804. local function check_in_circle(x,y, X, Y, R)
  3805.     return (X - x)^2 + (Y - y)^2 <= R
  3806. end
  3807.  
  3808. -- Not finished
  3809. Commands.Create(
  3810.     "bubble",
  3811.     {
  3812.         help = [[-- Bubble
  3813.         -- Syntax: %s [Player] {Radius}
  3814.         -- Puts a bubble around the player, so people cannot enter it.]]
  3815.     },
  3816.     {
  3817.         arguments = {"Player", minArgs = 1, maxArgs = 2},
  3818.         func = function(executorPlayerId, players, radius)
  3819.             radius = radius or 5
  3820.             local playerId
  3821.             for i = 1,#players do playerId = players[i]
  3822.                 PlayerClass[playerId].bubble = true
  3823.                 cmdreply[cmdreply()] = getname(playerId) .. " is now in a bubble with radius of " .. radius
  3824.             end
  3825.            
  3826.             sendresponse(cmdreply, executorPlayerId)
  3827.         end
  3828.     }
  3829. )
  3830.  
  3831. Commands.Create(
  3832.     "adminlist",
  3833.     {
  3834.         aliases = {"admins", "listadmins", "alist"},
  3835.         help = [[-- Admin List
  3836.         -- Syntax: %s {Type}
  3837.         -- Shows a list of all Admins
  3838.         -- Type can be either 'IP', 'Hash', or 'Temp' for filtering.]]
  3839.     },
  3840.     {
  3841.         arguments = {"String", minArgs = 0, maxArgs = 1},
  3842.         func = function(executorPlayerId, admin_type)
  3843.             cmdreply.header = "[Name | Level | Admin Type]"
  3844.             cmdreply.align = true
  3845.             cmdreply.delim = "|"
  3846.             local hash_admin, ip_admin
  3847.             for index,thisAdmin in next,admin_table do
  3848.                 cmdreply[cmdreply()] = thisAdmin.name .. " | " .. thisAdmin.level .. " | " .. thisAdmin.type .. " Admin"
  3849.             end
  3850.  
  3851.             sendresponse(cmdreply, executorPlayerId)
  3852.         end
  3853.     }
  3854. )
  3855.  
  3856. Commands.Create(
  3857.     "aliasold",
  3858.     {
  3859.         aliases = {"oldalias"},
  3860.         help = [[-- Alias
  3861.         -- Syntax: %s [player]
  3862.         -- Shows all names used with the hash]]
  3863.     },
  3864.     {
  3865.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  3866.         func = function(executorPlayerId, players)
  3867.             local playerId
  3868.             for i = 1,#players do playerId = players[i]
  3869.                 halo_svcmdplayer("sv_alias_hash " .. resolveplayer(playerId), executorPlayerId)
  3870.             end
  3871.         end
  3872.     }
  3873. )
  3874.  
  3875. -- whatever local function that calls this one will set the reference of 'boolCheck' to whatever newBool is, or will do nothing if newBool is nil.
  3876. local function ReturnScriptBooleanCheck(boolName, boolCheck, argBool)
  3877.     local are_is = sub(boolName, -1, -1) == "s" and "are" or "is" -- lol
  3878.     if argBool == nil then
  3879.         return nil, boolName .. " is currently " .. (boolCheck == true and "On" or boolCheck == false and "Off" or tostring(boolCheck))
  3880.     end
  3881.  
  3882.     local response
  3883.  
  3884.     if argBool then
  3885.         if not boolCheck then
  3886.             response = boolName .. " " .. are_is .. " now on"
  3887.         else
  3888.             argBool = nil
  3889.             response = "(*) " .. boolName .. " " .. are_is .. " already enabled"
  3890.         end
  3891.     elseif not argBool then
  3892.         if boolCheck then
  3893.             response = boolName .. " " .. are_is .. " now off"
  3894.         else
  3895.             argBool = nil
  3896.             response = "(*) " .. boolName .. " " .. are_is .. " already off"
  3897.         end
  3898.     end
  3899.  
  3900.     return argBool, response
  3901. end
  3902.  
  3903. -- Scripted Game Boolean Commands
  3904.  
  3905. Commands.Create(
  3906.     "remotecontrol",
  3907.     {
  3908.         help = [[-- Remote Control
  3909.             -- Syntax: %s {Port or Boolean}
  3910.             -- Starts or shuts down the remote control feature.
  3911.             -- Use a telnet client like Putty to connect
  3912.             -- This command REQUIRES using global rcons (sv_rcon_add). This may be changed later.]],
  3913.     },
  3914.     {
  3915.         arguments = {"Positive Number", minArgs = 0, maxArgs = 1},
  3916.         func = function(executorPlayerId, port)
  3917.             if not socket then
  3918.                 socket = require"socket"
  3919.                 http = require"socket.http"
  3920.                 http.TIMEOUT = 1
  3921.             end
  3922.             port = port <= 65535 and port > 800 and port or error("Ports must be between 65535 and 800. 2303 is recommended.")
  3923.             if port then
  3924.                 server = socket.tcp()
  3925.                
  3926.                 assert(server:bind("*", port))
  3927.                 assert(server:listen(9001))
  3928.  
  3929.                 server:settimeout(0)
  3930.                 sendresponse("The Remote Control server has been opened on port " .. tostring(port))
  3931.                 defaults.remotecontrol = registertimer(500, "remoteTimer")
  3932.             else
  3933.                 sendresponse("Remote Control is enabled and currently has " .. #clients .. " clients connected.", executorPlayerId)
  3934.             end
  3935.         end
  3936.     },
  3937.     {
  3938.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3939.         func = function(executorPlayerId, strBool)
  3940.             local newBool = ReturnScriptBooleanCheck("Remote Control", defaults.remotecontrol, strBool)
  3941.             if newBool then
  3942.                
  3943.                 if not socket then
  3944.                     socket = require"socket"
  3945.                     http = require"socket.http"
  3946.                     http.TIMEOUT = 1
  3947.                 end
  3948.                
  3949.                 server = socket.tcp()
  3950.                
  3951.                 assert(server:bind("*", 2303))
  3952.                 assert(server:listen(9001))
  3953.  
  3954.                 server:settimeout(0)
  3955.                 sendresponse("The Remote Control server has been opened on port 2303", executorPlayerId)
  3956.                 defaults.remotecontrol = registertimer(500, "remoteTimer")
  3957.             elseif newBool == false then
  3958.                 for i = 1,#clients do
  3959.                     clients[i].socket:close()
  3960.                 end
  3961.                 server:close()
  3962.                 server = nil
  3963.             end
  3964.         end
  3965.     }
  3966. )
  3967.  
  3968. Commands.Create(
  3969.     "anticaps",
  3970.     {
  3971.         aliases = {"disablecaps", "nocaps"},
  3972.         help = [[-- AntiCaps
  3973.         -- Syntax: %s {Boolean}
  3974.         -- Enables or Disables the use of caps in the server]]
  3975.     },
  3976.     {
  3977.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3978.         func = function(executorPlayerId, strBool)
  3979.             local newBool, response = ReturnScriptBooleanCheck("Anticaps", defaults.anticaps, strBool)
  3980.  
  3981.             if newBool ~= nil then
  3982.                 defaults.anticaps = newBool
  3983.             end
  3984.  
  3985.             sendresponse(response, executorPlayerId)
  3986.  
  3987.         end
  3988.     }
  3989. )
  3990.  
  3991. Commands.Create(
  3992.     "chatcommands",
  3993.     {
  3994.         help = [[-- ChatCommands
  3995.         -- Syntax: %s {Boolean}
  3996.         -- Enable/Disable Chat Commands for Admins]]
  3997.     },
  3998.     {
  3999.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4000.         func = function(executorPlayerId, strBool)
  4001.             local newBool, response = ReturnScriptBooleanCheck("Chat Commands", defaults.chatcommands, strBool)
  4002.  
  4003.             if newBool ~= nil then
  4004.                 defaults.chatcommands = newBool
  4005.             end
  4006.  
  4007.             sendresponse(response, executorPlayerId)
  4008.  
  4009.         end
  4010.     }
  4011. )
  4012.  
  4013. Commands.Create(
  4014.     "chatids",
  4015.     {
  4016.         aliases = {"chatid", "showplayernumbers"},
  4017.         help = [[-- Show Player IDs In Chat
  4018.         -- Syntax: %s {Boolean}
  4019.         -- Enable/Disable the showing of Player IDs in the chat.]]
  4020.     },
  4021.     {
  4022.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4023.         func = function(executorPlayerId, strBool)
  4024.             local newBool, response = ReturnScriptBooleanCheck("Chat IDs", defaults.chatids, strBool)
  4025.             if newBool ~= nil then
  4026.                 defaults.chatids = newBool
  4027.             end
  4028.  
  4029.             sendresponse(response, executorPlayerId)
  4030.  
  4031.         end
  4032.     }
  4033. )
  4034.  
  4035. function invisCrouch(id, count)
  4036.     if not defaults.crouch_camo then return false end
  4037.     for playerId = 0,15 do
  4038.         local m_playerObj = getplayerobject(playerId)
  4039.         if m_playerObj and readbyte(m_playerObj + 0x2A0) == 3 then
  4040.             applycamo(playerId, 1)
  4041.         end
  4042.     end
  4043.     return true
  4044. end
  4045.  
  4046. Commands.Create(
  4047.     "crouchcamo",
  4048.     {
  4049.         aliases = {"tigermode", "ninja", "ninjamode"},
  4050.         help = [[--Enable or Disable Crouch Camo
  4051.         -- Syntax: %s {Boolean}
  4052.         -- Enables or Disables the use of crouch camo]],
  4053.     },
  4054.     {
  4055.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4056.         func = function(executorPlayerId, players, strBool)
  4057.             local newBool, response = ReturnScriptBooleanCheck("Crouch Camo", defaults.crouch_camo, strBool)
  4058.             if newBool then
  4059.                 registertimer(200, "invisCrouch")
  4060.                 defaults.crouch_camo = true
  4061.             elseif newBool ~= nil then
  4062.                 defaults.crouch_camo = false
  4063.             end
  4064.  
  4065.             sendresponse(response, executorPlayerId)
  4066.         end
  4067.     }
  4068. )
  4069.  
  4070. --REM possibly rehaul this later, to include output to server consoles, to change the verbosity level of info, etc
  4071. -- Currently, this function enables certain debug messages I've deemed important enough to display.
  4072. -- Will output to the server's console, and to the player's in-game console.
  4073. Commands.Create(
  4074.     "debug",
  4075.     {
  4076.         aliases = {"debugmode", "toggledebug", "enabledebug", "verbose"},
  4077.         help = [[--Debug Mode
  4078.         -- Syntax: %s {Boolean} {Player}
  4079.         -- Turns on this scripts Debug messages, to help identify an issue with the script.
  4080.         -- Note: Will enable debug mode for executing player even if a player is specified]]
  4081.     },
  4082.     {
  4083.         arguments = {"Boolean", "Player", minArgs = 0, maxArgs = 2},
  4084.         func = function(executorPlayerId, strBool, players)
  4085.             local newBool, response = ReturnScriptBooleanCheck("Debug Mode", defaults.debug_mode, strBool)
  4086.             if newBool ~= nil then
  4087.                 defaults.debug_mode = newBool
  4088.                 if players then
  4089.                     local playerId
  4090.                     for i = 1,#players do playerId = players[i]
  4091.                         debug_players[playerId] = newBool
  4092.                     end
  4093.                 elseif executorPlayerId ~= nil then
  4094.                     debug_players[executorPlayerId] = newBool
  4095.                 end
  4096.             end
  4097.            
  4098.             sendresponse(response, executorPlayerId)
  4099.         end
  4100.     }
  4101. )
  4102.  
  4103. Commands.Create(
  4104.     "uniquesenabled",
  4105.     {
  4106.         aliases = {"uniqueplayercounting"},
  4107.         help = [[-- Unique Player Counting
  4108.         -- Syntax: %s {Boolean}
  4109.         -- Enables/Disables the Unique Player Counting feature.]]
  4110.     },
  4111.     {
  4112.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4113.         func = function(executorPlayerId, strBool)
  4114.             local newBool, response = ReturnScriptBooleanCheck("Unique Player Counting", defaults.uniques_enabled, strBool)
  4115.  
  4116.             if newBool then
  4117.  
  4118.                 local file = io.open(profilepath .. "uniques.txt")
  4119.                 if not file then
  4120.                     return
  4121.                 end
  4122.  
  4123.                 local index,ip,joincount,names
  4124.                 for line in file:lines() do
  4125.                     -- ignore blank lines
  4126.                     if match(line, "%g%g%g+") then
  4127.                         unique_table.total = unique_table.total + 1
  4128.                         index,joincount,names = match(line, "^(.+),(%d+),(.-)$")
  4129.                         if index then
  4130.                             names = tokenizestring(names, ",")
  4131.                             unique_table[index] = {joincount = joincount, names = names}
  4132.                         else
  4133.                             names,index,ip = match(line, "^(.-),(%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x+),(.-)$")
  4134.                             if names and validate_ipv4(ip) then
  4135.                                 joincount = 1
  4136.                                 unique_table[ip] = {joincount = 1, names = {names}}
  4137.                                 unique_table[match(ip, "%d+%.%d+%.%d+%.")] = {joincount = 1, names = {names}}
  4138.                             end
  4139.                         end
  4140.                     end
  4141.                 end
  4142.                 file:close()
  4143.             elseif newBool ~= nil then
  4144.                 defaults.uniques_enabled = false
  4145.             end
  4146.  
  4147.             sendresponse(response, executorPlayerId)
  4148.  
  4149.         end
  4150.     }
  4151. )
  4152.  
  4153. Commands.Create(
  4154.     "deathless",
  4155.     {
  4156.         aliases = {"d", "deathlessplayer", "deathlessmode"},
  4157.         scrimBlock = true,
  4158.         help = [[-- Deathless Players
  4159.         -- Syntax: %s {Boolean}
  4160.         -- Enables/Disables the Deathless Players mode.
  4161.         -- Players cannot die while this mode is enabled (obviously).
  4162.         -- The default for this command is (obviously) Off]]
  4163.     },
  4164.     {
  4165.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4166.         func = function(executorPlayerId, strBool)
  4167.             local newBool, response = ReturnScriptBooleanCheck("Deathless Player", defaults.deathless, strBool)
  4168.  
  4169.             if newBool ~= nil then
  4170.                 defaults.deathless = newBool
  4171.             end
  4172.  
  4173.             sendresponse(response, executorPlayerId)
  4174.  
  4175.         end
  4176.     }
  4177. )
  4178.  
  4179. Commands.Create(
  4180.     "falldamage",
  4181.     {
  4182.         scrimBlock = true,
  4183.         help = [[-- Fall Damage
  4184.         -- Syntax: %s [Boolean]
  4185.         -- Enable/Disable the damage players receive from falling.
  4186.         -- The default for this command is: Enabled]]
  4187.     },
  4188.     {
  4189.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4190.         func = function(executorPlayerId, strBool)
  4191.             local newBool, response = ReturnScriptBooleanCheck("Falldamage", defaults.falldamage, strBool)
  4192.  
  4193.             if newBool ~= nil then
  4194.                 defaults.falldamage = newBool
  4195.             end
  4196.  
  4197.             sendresponse(response, executorPlayerId)
  4198.  
  4199.         end
  4200.     }
  4201. )
  4202.  
  4203. Commands.Create(
  4204.     "firstjoinmessage",
  4205.     {
  4206.         help = [[-- First Join Message
  4207.         -- Syntax: %s [Boolean]
  4208.         -- Enable/Disable the First Join Message.
  4209.         -- The default for this command is: Enabled.]]
  4210.     },
  4211.     {
  4212.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4213.         func = function(executorPlayerId, strBool)
  4214.             local newBool, response = ReturnScriptBooleanCheck("First Join Message", defaults.firstjoin_message, strBool)
  4215.  
  4216.             if newBool ~= nil then
  4217.                 defaults.firstjoin_message = newBool
  4218.             end
  4219.  
  4220.             sendresponse(response, executorPlayerId)
  4221.  
  4222.         end
  4223.     }
  4224. )
  4225.  
  4226. Commands.Create(
  4227.     "centralbanlist",
  4228.     {
  4229.         aliases = {"centralbansystem", "remotebansystem", "remotebanlist", "globalbansystem", "globalbanlist", "masterbansystem", "masterbanlist"},
  4230.         help = [[-- Remote Ban System
  4231.         -- Syntax: %s [Host or Boolean] {PHP Script} {Ban File} {Method}
  4232.         -- Changes how the remote ban system works
  4233.         -- Check out the manual for information on this feature.
  4234.         -- This feature is off by default.]]
  4235.     },
  4236.     {
  4237.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4238.         func = function(executorPlayerId, strBool)
  4239.             local newBool, response = ReturnScriptBooleanCheck("Remote Ban System", not not defaults.remote_bansystem, strBool)
  4240.  
  4241.             if newBool == false then
  4242.                 defaults.remote_bansystem = newBool
  4243.             elseif newBool then
  4244.                 sendresponse("This feature cannot simply be enabled. You must pass a hostname, file, mode, etc.\nCheck out the manual for more information", executorPlayerId)
  4245.                 return
  4246.             end
  4247.  
  4248.             sendresponse(response, executorPlayerId)
  4249.         end
  4250.     },
  4251.     {
  4252.         arguments = {"String", "String", "String", "Remote Banlist Mode", "Positive Number", minArgs = 4, maxArgs = 5},
  4253.         func = function(executorPlayerId, host, phpscript, banfile, mode, port)
  4254.             if not socket then
  4255.                 socket = require"socket"
  4256.                 http = require"socket.http"
  4257.                 http.TIMEOUT = 1
  4258.             end
  4259.             defaults.remote_bansystem = {
  4260.                 host = host,
  4261.                 phpscript = phpscript,
  4262.                 banfile = banfile,
  4263.                 mode = mode,
  4264.                 http_source = "http://" .. host .. "/" .. phpscript,
  4265.                 port = port or 80
  4266.             }
  4267.             if mode == 0 then -- read-only
  4268.             elseif mode == 1 then -- one way (read-only) sync
  4269.             elseif mode == 2 then -- remote-only
  4270.             elseif mode == 3 then -- sync
  4271.             end
  4272.             reloadRemoteBanlist()
  4273.             updateBanFiles()
  4274.             sendresponse("The Remote Ban System is now enabled!", executorPlayerId)
  4275.         end
  4276.     }
  4277. )
  4278.  
  4279. Commands.Create(
  4280.     "firefist",
  4281.     {
  4282.         aliases = {'arsonist', 'firefister'},
  4283.         help = [[-- Firefist
  4284.         -- Syntax: %s [Player] {Boolean}
  4285.         -- Enable/Disable Firefist for a player.
  4286.         ]],
  4287.     },
  4288.     {
  4289.         arguments = {"Player", "Boolean", minArgs = 1, maxArgs = 2},
  4290.         func = function(executorPlayerId, players, bool)
  4291.             local player
  4292.             for i = 1,#players do playerId = players[i]
  4293.                 player = PlayerClass[playerId]
  4294.                 if bool then
  4295.                     player.firefist = bool
  4296.                     sendresponse("Fire fist " .. tostring(bool) .. " for " .. tostring(getname(playerId)), executorPlayerId)
  4297.                     registertimer(300, "FireFistTimer")
  4298.                 else
  4299.                     sendresponse("Fire fist for player " .. tostring(getname(playerId)) .. " is currently " .. tostring(bool), executorPlayerId)
  4300.                 end
  4301.             end
  4302.         end
  4303.     }
  4304. )
  4305.  
  4306. -- apply flame to receiving player.
  4307. function ApplyFlame(receiverPlayerId, firefisterObjId)
  4308.     local playerObjId = getplayerobjectid(receiverPlayerId)
  4309.     local x,y,z = getobjectcoords(playerObjId)
  4310.     local flame = createobject(flameid, firefisterObjId, 5, true, x, y, z+0.65)
  4311.     local xflame = createobject(flameid, firefisterObjId, 5, true, x-0.08, y, z+0.43)
  4312.     local gflamefx = createobject(flameid, firefisterObjId, 5, true, x-0.12, y, z+0.04)
  4313.     local flameobject = getobject(flame)
  4314.     writefloat(flameobject + 0x68, 0)
  4315.     writefloat(flameobject + 0x6C, 0)
  4316.     writefloat(flameobject + 0x70, -0.2)
  4317. end
  4318.  
  4319. function getBodyPartLocation(m_object, offset)
  4320.     --m_object = m_object + (offset or 0x0)
  4321.     --unkFloats[10] (???) Probably rotations.
  4322.     bipd_bodypart_x = readfloat(m_object, offset + 0x28)
  4323.     bipd_bodypart_y = readfloat(m_object, offset + 0x2C)
  4324.     bipd_bodypart_z = readfloat(m_object, offset + 0x30)
  4325.     return bipd_bodypart_x,bipd_bodypart_y,bipd_bodypart_z
  4326. end
  4327.  
  4328. -- apply flame damage to fist of firefister
  4329. function FireFistTimer(id, cc)
  4330.     local playerObjId, m_playerObj, hx, hy, hz, fistflame, ffobject
  4331.     local firefisterfound = false
  4332.     for playerId = 0,15 do
  4333.         if not getplayer(playerId) or not PlayerClass[playerId].firefist then goto nextIter end
  4334.         firefisterfound = true
  4335.         playerObjId = getplayerobjectid(playerId)
  4336.         m_playerObj = getobject(playerObjId)
  4337.         if not m_playerObj then goto nextIter end
  4338.         hx,hy,hz  = getBodyPartLocation(m_playerObj, 0x8C4)
  4339.         fistflame = createobject(flameid, 0, 5, true, hx, hy, hz+0.08)
  4340.         fistflame2 = createobject(flameid, 0, 5, true, hx, hy, hz+0.1)
  4341.         ffobject = getobject(fistflame)
  4342.         ffobject2 = getobject(fistflame2)
  4343.         writefloat(ffobject + 0x68, 0)
  4344.         writefloat(ffobject + 0x6C, 0)
  4345.         writefloat(ffobject + 0x70, -0.2)
  4346.         writefloat(ffobject2 + 0x68, 0)
  4347.         writefloat(ffobject2 + 0x6C, 0)
  4348.         writefloat(ffobject2 + 0x70, -0.2)
  4349.         ::nextIter::
  4350.     end
  4351.     if not firefisterfound then
  4352.         return false
  4353.     end
  4354.     return true
  4355. end
  4356.  
  4357.  
  4358. Commands.Create(
  4359.     "hashduplicates",
  4360.     {
  4361.         aliases = {'duplicates', 'allowduplicates'},
  4362.         help = [[-- Allow Hash Duplicates
  4363.         -- Syntax: %s {Boolean}
  4364.         -- Allows/Deny's multiple players with the same hash to join the server
  4365.         -- The default for this command is: Enabled.]]
  4366.     },
  4367.     {
  4368.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4369.         func = function(executorPlayerId, strBool)
  4370.             local newBool, response = ReturnScriptBooleanCheck("Hash Duplicate Checking", defaults.hash_duplicates, strBool)
  4371.  
  4372.             if newBool then
  4373.                 writebyte(addresses.hash_duplicate_patch, 0x74)
  4374.                 defaults.hash_duplicates = true
  4375.             elseif newBool ~= nil then
  4376.                 writebyte(addresses.hash_duplicate_patch, 0xEB)
  4377.                 defaults.hash_duplicates = false
  4378.             end
  4379.             sendresponse(response, executorPlayerId)
  4380.         end
  4381.     }
  4382. )
  4383.  
  4384. Commands.Create(
  4385.     "infiniteammo",
  4386.     {
  4387.         aliases = {"infammo"},
  4388.         scrimBlock = true,
  4389.         help = [[-- Infinite Ammo
  4390.         -- Syntax: %s [Boolean]
  4391.         -- Enable or disable infinite ammo"]]
  4392.     },
  4393.     {
  4394.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4395.         func = function(executorPlayerId, strBool)
  4396.             local newBool, response = ReturnScriptBooleanCheck("Infinite Ammo", defaults.infinite_ammo, strBool)
  4397.  
  4398.             if newBool then
  4399.                 defaults.infinite_ammo = true
  4400.                 local player, m_playerObj, playerObjId, m_weaponObj, weaponObjId
  4401.                 infammo_timer = registertimer(500, "playerWeaponCheckTimer")
  4402.                 for playerId = 0,15 do
  4403.                     if not getplayer(playerId) then
  4404.                         goto continue
  4405.                     end
  4406.  
  4407.                     m_playerObj, playerObjId = getplayerobject(playerId)
  4408.                     if not m_playerObj then
  4409.                         goto continue
  4410.                     end
  4411.  
  4412.                     player = PlayerClass[playerId]
  4413.                     for slot = 0,3 do
  4414.                         weaponObjId = player.weapons[slot]
  4415.                         m_weaponObj = getobject(weaponObjId)
  4416.                         if m_weaponObj then
  4417.                             writeshort(m_weaponObj + 0x2B6, 0x7CFF)
  4418.                             writeshort(m_weaponObj + 0x2B8, 0x7CFF)
  4419.                             updateammo(weaponObjId)
  4420.                             player.weapons[slot] = weaponObjId
  4421.                         end
  4422.                     end
  4423.                     ::continue::
  4424.                 end
  4425.             elseif newBool ~= nil then
  4426.                 local m_playerObj, m_weaponObj, weaponObjId, mapId, tag_address, tag_data_address, address_magazines, rounds_total_initial, rounds_loaded_maximum
  4427.                 for i = 0,15 do
  4428.  
  4429.                     m_playerObj = getplayerobject(i)
  4430.                     if not m_playerObj then
  4431.                         goto continue
  4432.                     end
  4433.  
  4434.                     for x = 0,3 do
  4435.                         m_weaponObj, weaponObjId = getplayerweapon(i, x)
  4436.                         if not m_weaponObj then
  4437.                             goto continue2
  4438.                         end
  4439.  
  4440.                         mapId = readdword(m_weaponObj)
  4441.                         tag_address = gettagaddress(mapId)
  4442.                         tag_data_address = readdword(tag_address + 0x14)
  4443.                         address_magazines = readdword(tag_data_address + 0x4F0 + 0x4)
  4444.                         if not address_magazines or address_magazines == 0 then
  4445.                             goto continue2
  4446.                         end
  4447.                        
  4448.                         rounds_total_initial = readshort(address_magazines + 0x8)
  4449.                         rounds_loaded_maximum = readshort(address_magazines + 0xA)
  4450.  
  4451.                         writeshort(m_weaponObj + 0x2B6, rounds_total_initial or 0)
  4452.                         writeshort(m_weaponObj + 0x2B8, rounds_loaded_maximum or 0)
  4453.                         updateammo(weaponObjId)
  4454.  
  4455.                         ::continue2::
  4456.                     end
  4457.  
  4458.                     ::continue::
  4459.                 end
  4460.                 if infammo_timer then removetimer(infammo_timer) end
  4461.                 defaults.infinite_ammo = false
  4462.             end
  4463.  
  4464.             sendresponse(response, executorPlayerId)
  4465.  
  4466.         end
  4467.     }
  4468. )
  4469.  
  4470. Commands.Create(
  4471.     "killspree",
  4472.     {
  4473.         aliases = {"killingspree"},
  4474.         help = [[-- Killing Spree Detection
  4475.         -- Syntax: %s [Boolean]
  4476.         -- Enable/Disable Killing Spree Notifications]]
  4477.     },
  4478.     {
  4479.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4480.         func = function(executorPlayerId, strBool)
  4481.             local newBool, response = ReturnScriptBooleanCheck("Killing Spree Notifications", defaults.killing_spree, strBool)
  4482.  
  4483.             if newBool ~= nil then
  4484.                 defaults.killing_spree = newBool
  4485.             end
  4486.  
  4487.             sendresponse(response, executorPlayerId)
  4488.  
  4489.         end
  4490.     }
  4491. )
  4492. -- TODO: Use gametype scorelimit per-player or per-team instead of hardcoded values
  4493. Commands.Create(
  4494.     "multiteamvehicles",
  4495.     {
  4496.         aliases = {"mtvehicles", "mtv"},
  4497.         help = [[-- Multi Team Vehicles
  4498.         -- Syntax: %s {Boolean}
  4499.         -- Allows/Deny's players to enter enemy vehicles.
  4500.         -- Note: This command only works on Free-For-All GameTypes.
  4501.         -- The default for this command is: Disabled.]]
  4502.     },
  4503.     {
  4504.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4505.         func = function(executorPlayerId, strBool)
  4506.             local newBool, response = ReturnScriptBooleanCheck("Multi-Team Vehicles", defaults.multiteam_vehicles, strBool)
  4507.             if not team_play then
  4508.                 local m_player
  4509.                 if newBool then
  4510.                     --[[if not team_play_temp then
  4511.                         team_play_temp = team_play
  4512.                     end
  4513.                     team_play = true--]]
  4514.                     for playerId = 0,15 do
  4515.                         m_player = getplayer(playerId)
  4516.                         if m_player then
  4517.                             team_scores[playerId] = player_scores[playerId]
  4518.                             writebyte(m_player + 0x20, 0)
  4519.                         end
  4520.                     end
  4521.                     writebyte(addresses.gametype_base + 0x58, 255)
  4522.                     defaults.multiteam_vehicles = true
  4523.                 elseif newBool ~= nil then
  4524.                     --team_play = team_play_temp or team_play
  4525.                     for playerId = 0,15 do
  4526.                         m_player = getplayer(playerId)
  4527.                         if m_player then
  4528.                             writebyte(m_player + 0x20, readbyte(m_player + 0x66))
  4529.                         end
  4530.                     end
  4531.                     writebyte(addresses.gametype_base + 0x58, scorelimit)
  4532.                     defaults.multiteam_vehicles = false
  4533.                 end
  4534.             else
  4535.                 sendresponse("Cannot be applied to team games.", executorPlayerId)
  4536.             end
  4537.             sendresponse(response, executorPlayerId)
  4538.         end
  4539.     }
  4540. )
  4541.  
  4542. Commands.Create(
  4543.     "noweapons",
  4544.     {
  4545.         help = [[-- No Weapons
  4546.         -- Syntax: %s {Boolean}
  4547.         -- Enables/Disables the use of weapons in a server.]]
  4548.     },
  4549.     {
  4550.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4551.         func = function(executorPlayerId, strBool)
  4552.             local newBool, response = ReturnScriptBooleanCheck("No-Weapons mode", defaults.noweapons, strBool)
  4553.  
  4554.             if newBool then
  4555.                 local m_playerObj, m_weaponObj, weaponObjId
  4556.                 for playerId = 0,15 do
  4557.                     m_playerObj = getplayerobject(playerId)
  4558.                     if m_playerObj then
  4559.                         for j = 0,3 do
  4560.                             m_weaponObj, weaponObjId = getplayerweapon(playerId, j)
  4561.                             if m_weaponObj then
  4562.                                 destroyobject(weaponObjId)
  4563.                             end
  4564.                         end
  4565.                     end
  4566.                 end
  4567.                 defaults.noweapons = true
  4568.             elseif newBool ~= nil then
  4569.                 for playerId = 0,15 do
  4570.                     if getplayer(playerId) then
  4571.                         resetweapons(playerId)
  4572.                     end
  4573.                 end
  4574.                 defaults.noweapons = false
  4575.             end
  4576.  
  4577.             sendresponse(response, executorPlayerId)
  4578.  
  4579.         end
  4580.     }
  4581. )
  4582.  
  4583. Commands.Create(
  4584.     "pmenabled",
  4585.     {
  4586.         aliases = {"pvtmessage", "privatemessage", "privatemessageenabled"},
  4587.         help = [[-- Private Messaging
  4588.         -- Syntax: %s {Boolean}
  4589.         -- Enable/Disable Private Messaging
  4590.         -- To use private messaging, type @(playerIndex) (message) in the chat, without the ( )]]
  4591.     },
  4592.     {
  4593.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4594.         func = function(executorPlayerId, strBool)
  4595.             local newBool, response = ReturnScriptBooleanCheck("Private Messaging", defaults.pm_enabled, strBool)
  4596.  
  4597.             if newBool ~= nil then
  4598.                 defaults.pm_enabled = newBool
  4599.             end
  4600.  
  4601.             sendresponse(response, executorPlayerId)
  4602.  
  4603.         end
  4604.     }
  4605. )
  4606.  
  4607. Commands.Create(
  4608.     "rtvenabled",
  4609.     {
  4610.         help = [[-- RockTheVote
  4611.         -- Syntax: %s {Boolean}
  4612.         -- Enables or disables the use of RockTheVote in the server
  4613.         -- To initiate a rtv, type 'skip' or 'rtv' in the chat.]]
  4614.     },
  4615.     {
  4616.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4617.         func = function(executorPlayerId, strBool)
  4618.             local newBool, response = ReturnScriptBooleanCheck("RockTheVote", defaults.rtv_enabled, strBool)
  4619.  
  4620.             if newBool ~= nil then
  4621.                 defaults.rtv_enabled = newBool
  4622.             end
  4623.  
  4624.             sendresponse(response, executorPlayerId)
  4625.  
  4626.         end
  4627.     }
  4628. )
  4629.  
  4630. Commands.Create(
  4631.     "serveradminmessage",
  4632.     {
  4633.         aliases = {"samessage"},
  4634.         help = [[-- Server Admin Message
  4635.         -- Syntax: %s {Boolean}
  4636.         -- Enable/Disable Server Admin join notification.]]
  4637.     },
  4638.     {
  4639.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4640.         func = function(executorPlayerId, strBool)
  4641.             local newBool, response = ReturnScriptBooleanCheck("Server Admin Message", defaults.sa_message, strBool)
  4642.  
  4643.             if newBool ~= nil then
  4644.                 defaults.sa_message = newBool
  4645.             end
  4646.  
  4647.             sendresponse(response, executorPlayerId)
  4648.  
  4649.         end
  4650.     }
  4651. )
  4652.  
  4653. Commands.Create(
  4654.     "scrimmode",
  4655.     {
  4656.         help = [[-- Scrim mode
  4657.         -- Syntax: %s {Boolean}
  4658.         -- Enables/Disables Scrim Mode
  4659.         -- This mode will disable certain commands, so people can't cheat during scrims.]]
  4660.     },
  4661.     {
  4662.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4663.         func = function(executorPlayerId, strBool)
  4664.             local newBool, response = ReturnScriptBooleanCheck("Scrim mode", defaults.scrim_mode, strBool)
  4665.  
  4666.             if newBool then
  4667.                 for i = 0,15 do
  4668.                     ResetPlayer(i)
  4669.                 end
  4670.  
  4671.                 --controllers:deleteEntries()
  4672.                 --slaving:deleteEntries()
  4673.  
  4674.                 defaults.falldamage = true
  4675.                 defaults.deathless = false
  4676.                 defaults.infinite_ammo = false
  4677.  
  4678.                 defaults.scrim_mode = true
  4679.             elseif newBool ~= nil then
  4680.                 defaults.scrim_mode = false
  4681.             end
  4682.  
  4683.             sendresponse(response, executorPlayerId)
  4684.  
  4685.         end
  4686.     }
  4687. )
  4688.  
  4689. Commands.Create(
  4690.     "tbagdet",
  4691.     {
  4692.         aliases = {"tbagdetection"},
  4693.         help = [[-- Tbag Detection
  4694.         -- Syntax: %s [Boolean]
  4695.         -- Enable/Disable Tbag announcement]]
  4696.     },
  4697.     {
  4698.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4699.         func = function(executorPlayerId, strBool)
  4700.             local newBool, response = ReturnScriptBooleanCheck("Tbag Detection", defaults.tbag_detection, strBool)
  4701.  
  4702.             if newBool ~= nil then
  4703.                 defaults.tbag_detection = newBool
  4704.             end
  4705.  
  4706.             sendresponse(response, executorPlayerId)
  4707.  
  4708.         end
  4709.     }
  4710. )
  4711.  
  4712. Commands.Create(
  4713.     "votekickenabled",
  4714.     {
  4715.         help = [[-- VoteKick
  4716.         -- Syntax: %s [Boolean]
  4717.         -- Enables/Disables the use of VoteKick in a server
  4718.         -- Once enabled, people can type 'votekick [player]' in the chat to start a votekick on that player.]]
  4719.     },
  4720.     {
  4721.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4722.         func = function(executorPlayerId, strBool)
  4723.             local newBool, response = ReturnScriptBooleanCheck("VoteKick", defaults.votekick_enabled, strBool)
  4724.  
  4725.             if newBool ~= nil then
  4726.                 defaults.votekick_enabled = newBool
  4727.             end
  4728.  
  4729.             sendresponse(response, executorPlayerId)
  4730.  
  4731.         end
  4732.     }
  4733. )
  4734.  
  4735. Commands.Create(
  4736.     "defaultspawnweapons",
  4737.     {
  4738.         aliases = {"spawnweapons", "weaponsonspawn", "chooseweapons", "selectweapons", "poontang"},
  4739.         help = [[-- Choose Default Spawn Weapons
  4740.         -- Syntax: %s {Primary Weapon or 'Default'} {Secondary Weapon} {Tertiary Weapon} {Quaternary Weapon}
  4741.         -- Will allow you to change the default weapons that you spawn with.
  4742.         -- Not sending arguments will show the current setting of this command.
  4743.         -- Sending a single argument 'Default' to this command will use the default weapon spawning.]]
  4744.     },
  4745.     {
  4746.         arguments = {"Object", "Object", "Object", "Object", minArgs = 0, maxArgs = 4},
  4747.         func = function(executorPlayerId, primary_weap_tagname, secondary_weap_tagname, tertiary_weap_tagname, quaternary_weap_tagname)
  4748.             if primary_weap_tagname then
  4749.                 spawnWeapons[1] = primary_weap_tagname
  4750.                 spawnWeapons[2] = secondary_weap_tagname
  4751.                 spawnWeapons[3] = tertiary_weap_tagname
  4752.                 spawnWeapons[4] = quaternary_weap_tagname
  4753.             else
  4754.                 sendresponse("The current default spawn weapons are displayed below", executorPlayerId)
  4755.                 local weap
  4756.                 for i = 0,3 do weap = spawnWeapons[i]
  4757.                     if weap then
  4758.                         sendresponse("Spawn Weapon #" .. i .. ": " .. weap)
  4759.                     end
  4760.                 end
  4761.             end
  4762.         end
  4763.     }
  4764. )
  4765.  
  4766. Commands.Create(
  4767.     "welcomebackmessage",
  4768.     {
  4769.         aliases = {"wbmessage"},
  4770.         help = [[-- Welcome Back Message
  4771.         -- Syntax: %s [Boolean]
  4772.         -- Enable/Disable Welcome Back Message]]
  4773.     },
  4774.     {
  4775.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  4776.         func = function(executorPlayerId, strBool)
  4777.             local newBool, response = ReturnScriptBooleanCheck("Welcome Back Message", defaults.wb_message, strBool)
  4778.  
  4779.             sendresponse(response, executorPlayerId)
  4780.  
  4781.             if newBool ~= nil then
  4782.                 defaults.wb_message = newBool
  4783.             end
  4784.         end
  4785.     }
  4786. )
  4787.  
  4788. -- Scripted Game non-boolean Commands
  4789.  
  4790. Commands.Create(
  4791.     "adminblocker",
  4792.     {
  4793.         help = [[-- Admin Blocker
  4794.         -- Syntax: %s {Type}
  4795.         -- Enables, disables or limits the abiliy of an admin to kick/ban
  4796.         -- Type 0: Admins can kick/ban another admin.
  4797.         -- Type 1: Admins can't kick/ban other admins with higher level.
  4798.         -- Type 2: Admins can't kick/ban other admins with higher or equal level.
  4799.         -- Type 3: Admins can't kick/ban other admins unless they can do all commands.]]
  4800.     },
  4801.     {
  4802.         arguments = {"AdminBlocker Type", minArgs = 0, maxArgs = 1},
  4803.         func = function(executorPlayerId, abtype)
  4804.  
  4805.             if abtype == 0 then
  4806.                 defaults.adminblocker = "Unsafe"
  4807.                 sendresponse("Admins now can kick/ban other admins", executorPlayerId)
  4808.             elseif abtype == 1 then
  4809.                 defaults.adminblocker = "Lenient"
  4810.                 sendresponse("Admins now cannot kick/ban other admins with higher levels.", executorPlayerId)
  4811.             elseif abtype == 2 then
  4812.                 defaults.adminblocker = "Moderate"
  4813.                 sendresponse("Admins now cannot kick/ban other admins with higher or equal levels.", executorPlayerId)
  4814.             elseif abtype == 3 then
  4815.                 defaults.adminblocker = "Strict"
  4816.                 sendresponse("Admins now cannot kick/ban other admins unless they can do all commands.", executorPlayerId)
  4817.             elseif defaults.adminblocker == "Unsafe" then
  4818.                 sendresponse("Admins currently can kick/ban other admins", executorPlayerId)
  4819.             elseif defaults.adminblocker == "Lenient" then
  4820.                 sendresponse("Admins currently cannot kick/ban other admins with higher levels.", executorPlayerId)
  4821.             elseif defaults.adminblocker == "Moderate" then
  4822.                 sendresponse("Admins currently cannot kick/ban other admins with higher or equal levels.", executorPlayerId)
  4823.             elseif defaults.adminblocker == "Strict" then
  4824.                 sendresponse("Admins currently cannot kick/ban another admins unless they have full access.", executorPlayerId)
  4825.             end
  4826.         end
  4827.     }
  4828. )
  4829.  
  4830. Commands.Create(
  4831.     "antispam",
  4832.     {
  4833.         help = [[-- AntiSpam
  4834.         -- Syntax: %s {all | players | off}
  4835.         -- All = All Players cannot spam in the chat.
  4836.         -- Players = All Players EXCEPT Admins cannot spam in the chat.
  4837.         -- Off = Disables AntiSpam functionality]]
  4838.     },
  4839.     {
  4840.         arguments = {"String", minArgs = 0, maxArgs = 1},
  4841.         func = function(executorPlayerId, mode)
  4842.             if mode and mode ~= "all" and mode ~= "players" and mode ~= "off" then
  4843.                 sendresponse("Invalid mode. Valid modes are 'all', 'players', and 'off'", executorPlayerId)
  4844.                 return
  4845.             end
  4846.  
  4847.             if mode then
  4848.                 defaults.antispam = mode
  4849.                 sendresponse("AntiSpam now set to " .. defaults.antispam, executorPlayerId)
  4850.             else
  4851.                 sendresponse("AntiSpam is set to " .. defaults.antispam, executorPlayerId)
  4852.             end
  4853.         end
  4854.     }
  4855. )
  4856.  
  4857. Commands.Create(
  4858.     "balance",
  4859.     {
  4860.         help = [[-- Balance Teams
  4861.         -- Syntax: %s
  4862.         -- Balances the number of players on each team.
  4863.         -- This command can ONLY be executed on Teamplay GameTypes like CTF.]]
  4864.     },
  4865.     {
  4866.         arguments = {minArgs = 0, maxArgs = 0},
  4867.         func = function(executorPlayerId)
  4868.             if not team_play then
  4869.                 sendresponse("This command is disabled since it is not a team based game.", executorPlayerId)
  4870.                 return
  4871.             end
  4872.  
  4873.             local redsize = getteamsize(0)
  4874.             local bluesize = getteamsize(1)
  4875.             if math.abs(redsize - bluesize) > 1 then
  4876.                 local randPlayerId = SelectRandomPlayer(bluesize > redsize and 1 or 0)
  4877.                 if randPlayerId then
  4878.                     changeteam(randPlayerId, true)
  4879.                     say("Balancing Teams")
  4880.                     sendresponse("The teams have been balanced", executorPlayerId)
  4881.                 else
  4882.                     sendresponse("There was no one found on the other team.")
  4883.                 end
  4884.             else
  4885.                 sendresponse("Teams are already balanced.", executorPlayerId)
  4886.             end
  4887.         end
  4888.     }
  4889. )
  4890.  
  4891. Commands.Create(
  4892.     "banpenalty",
  4893.     {
  4894.         help = [[-- Ban Penalty
  4895.         -- Syntax: %s {1st Bantime} {2nd Bantime} {3rd Bantime} etc..
  4896.         -- Determines how much time a player can be banned when the time argument '0' is used in a ban command.]]
  4897.     },
  4898.     {
  4899.         arguments = {"Time String", minArgs = 0, maxArgs = 1},
  4900.         func = function(executorPlayerId, times)
  4901.             if not times then
  4902.                 for i = 1,#ban_penalty do
  4903.                     cmdreply[cmdreply()] = "Ban Penalty #" .. i .. ": " .. ban_penalty[i]
  4904.                 end
  4905.  
  4906.                 sendresponse(cmdreply, executorPlayerId)
  4907.             else
  4908.                 local i = 1
  4909.                 local length = #ban_penalty
  4910.                 for time in string.gmatch(times, "%d+[cywdhms]") do time = wordtotime(time)
  4911.                     ban_penalty[i] = time
  4912.                     i = i + 1
  4913.                 end
  4914.                 while length >= i do
  4915.                     ban_penalty[i] = nil
  4916.                     i = i + 1
  4917.                 end
  4918.                 sendresponse("The Ban Penalties have been changed to: " .. times, executorPlayerId)
  4919.             end
  4920.         end
  4921.     }
  4922. )
  4923. Commands.Create(
  4924.     "ban",
  4925.     {
  4926.         aliases = {"b", "hashban", "playerban", "banplayer"},
  4927.         usesBanCounts = true,
  4928.         help = [[-- Ban
  4929.         -- Syntax: %s [Player, Hash, or IP Address] {Time} {Reason}
  4930.         -- Bans the Player/Hash/IP Address from the server with a reason written to the BanReasons log file]]
  4931.     },
  4932.     {
  4933.         arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3},
  4934.         func = function(executorPlayerId, players, time, reason)
  4935.             local exname = executorPlayerId and getname(executorPlayerId) or "the Server"
  4936.             local playerId, name, hash
  4937.             for i = 1,#players do playerId = players[i]
  4938.  
  4939.                 name = getname(playerId)
  4940.                 if not checkAdminBlockerAccess(executorPlayerId, playerId) then
  4941.                     sendresponse("You cannot use this command on " .. name, executorPlayerId)
  4942.                     privatesay(playerId, exname .. " attempted to Ban you!")
  4943.                     goto continue
  4944.                 end
  4945.  
  4946.                 hash = gethash(playerId)
  4947.                 if hash == sharedhashes[hash] then
  4948.                     cmdreply[cmdreply()] = name .. " has a shared hash, and therefore cannot be hashbanned. Try an IP Ban instead."
  4949.                     goto continue
  4950.                 end
  4951.  
  4952.                 tempBanPlayer(resolveplayer(playerId))
  4953.                 if time ~= 1 then
  4954.                     addBan(name, hash, nil, time, "hash", reason)
  4955.                     WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was banned by " .. exname .. " Reason: " .. reason .. " Type: Hash Ban")
  4956.                     say(name .. " has been banned by " .. exname .. " Reason: " .. reason)
  4957.                     cmdreply[cmdreply()] = name .. " has been banned from the server"
  4958.                 end
  4959.  
  4960.                 ::continue::
  4961.             end
  4962.  
  4963.             sendresponse(cmdreply, executorPlayerId)
  4964.         end
  4965.     },
  4966.     {
  4967.         arguments = {"Hash", "Time And Reason", minArgs = 1, maxArgs = 3},
  4968.         func = function(executorPlayerId, hash, time, reason)
  4969.             local exname = executorPlayerId and getname(executorPlayerId) or "the Server"
  4970.  
  4971.             for i = 1,#sharedhashes do
  4972.                 if hash == sharedhashes[i] then
  4973.                     sendresponse("That is a shared hash, and therefore cannot be hashbanned. Try an IP Ban instead.", executorPlayerId)
  4974.                     return
  4975.                 end
  4976.             end
  4977.  
  4978.             -- Check if a person in this server has this hash.
  4979.             for playerId = 0,15 do
  4980.                 if getplayer(playerId) and gethash(playerId) == hash then
  4981.                     tempBanPlayer(resolveplayer(playerId))
  4982.                 end
  4983.             end
  4984.             addBan("manual_ban" .. #ban_table, hash, nil, time, "hash", reason)
  4985.             WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", "Hash '" .. hash .. "' was banned by " .. exname .. " Reason: " .. reason .. " Type: Hash Ban")
  4986.             sendresponse("That hash has been banned from the server successfully", executorPlayerId)
  4987.         end
  4988.     },
  4989.     {
  4990.         arguments = {"IP Address", "Time And Reason", minArgs = 1, maxArgs = 3},
  4991.         func = function(executorPlayerId, ip_address, time, reason)
  4992.             local exname = executorPlayerId and getname(executorPlayerId) or "the Server"
  4993.  
  4994.             -- Check if a person in this server has this IP Address.
  4995.             for playerId = 0,15 do
  4996.                 if getplayer(playerId) and netMatch(ip_address, getip(playerId)) then
  4997.                     tempBanPlayer(resolveplayer(playerId))
  4998.                 end
  4999.             end
  5000.             addBan("manual_ban" .. #ban_table, nil, ip_address, time, "ip", reason)
  5001.             WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", "IP Address '" .. ip_address .. "' was banned by " .. exname .. " Reason: " .. reason .. " Type: IP Ban")
  5002.             sendresponse("That IP Address has been banned from the server successfully", executorPlayerId)
  5003.         end
  5004.     }
  5005. )
  5006.  
  5007. Commands.Create(
  5008.     "bos",
  5009.     {
  5010.         help = [[Ban on Sight
  5011.         -- Syntax: %s [Bosplayer Index] {Bantype 'Hash' or 'IP'}
  5012.         -- Add the specified player to the Ban On Sight (BOS) list.
  5013.         -- The next time this person joins the server, they will be banned.
  5014.         -- This command explicitly requires a number for an index.
  5015.         -- This index must be the player index of a player who has left the server.
  5016.         -- Use 'sv_bosplayers' to get a list of players to add to the BOS list.]]
  5017.     },
  5018.     {
  5019.         arguments = {"Positive Number", minArgs = 1, maxArgs = 2},
  5020.         func = function(executorPlayerId, playerId)
  5021.  
  5022.             local leave_entry = leave_table[playerId]
  5023.             if not leave_entry then
  5024.                 sendresponse("Invalid BoS ID! Use sv_bosplayers to get a list of bosable players.", executorPlayerId)
  5025.                 return
  5026.             end
  5027.  
  5028.             local bos_entry
  5029.             for i = 1,#bos_table do bos_entry = bos_table[i]
  5030.                 if bos_entry.hash == leave_entry.hash or netMatch(bos_entry.ip, leave_entry.ip) then
  5031.                     sendresponse(leave_entry.name .. " is already on the BoS", executorPlayerId)
  5032.                     return
  5033.                 end
  5034.             end
  5035.             cmdreply[cmdreply()] = "Adding " .. leave_entry.name .. " to BoS."
  5036.             cmdreply[cmdreply()] = "Entry: " .. leave_entry.name .. " - " .. leave_entry.hash .. " - " .. leave_entry.ip
  5037.             sendresponse(cmdreply, executorPlayerId)
  5038.             bos_table[#bos_table+1] = leave_entry
  5039.            
  5040.             -- check if they are already in the server
  5041.             for playerId = 0,15 do
  5042.                 if getplayer(playerId) then
  5043.                     if not sharedhashes[leave_entry.hash] and leave_entry.hash == gethash(playerId) or netMatch(leave_entry.ip, getip(playerId)) then
  5044.                         tempBanPlayer(playerId)
  5045.                         privateSayAdmins(bos_entry.name .. " banned from BoS.\nEntry: " .. bos_entry.name .. "- " .. bos_entry.hash)
  5046.                         hprintf(bos_entry.name .. " banned from BoS.\nEntry: " .. bos_entry.name .. "- " .. bos_entry.ip)
  5047.                         WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", bos_entry.name .. " was Banned on Sight")
  5048.                         addBan(bos_entry.name, nil, ip, -1, "ip", "Ban on Sight")
  5049.                     end
  5050.                 end
  5051.             end
  5052.         end
  5053.     }
  5054. )
  5055.  
  5056. Commands.Create(
  5057.     "kickbansfile",
  5058.     {
  5059.         help = [[-- Kicks and Bans Log File Name
  5060.         -- Syntax: %s {Filename}
  5061.         -- Allows the executor to view and change the name of the 'BanReasons.log' file.]],
  5062.     },
  5063.     {
  5064.         arguments = {"String", minArgs = 0, maxArgs = 1},
  5065.         func = function(executorPlayerId, filename)
  5066.             if not filename then
  5067.                 sendresponse("The current KickBans file name is " .. defaults.kickbans_file .. ".log", executorPlayerId)
  5068.             elseif match(filename, "%w+") then
  5069.                 defaults.kickbans_file = filename
  5070.                 sendresponse("The KickBans file has been changed to " .. defaults.kickbans_file .. ".log", executorPlayerId)
  5071.             else
  5072.                 sendresponse("File names must contain alphanumerical characters only!", executorPlayerId)
  5073.             end
  5074.         end
  5075.     }
  5076. )
  5077.  
  5078. Commands.Create(
  5079.     "commandsfile",
  5080.     {
  5081.         help = [[-- Commands Log File Name
  5082.         -- Syntax: %s {Filename}
  5083.         -- Allows the executor to view and change the name of the 'commands.log' file.]],
  5084.     },
  5085.     {
  5086.         arguments = {"String", minArgs = 0, maxArgs = 1},
  5087.         func = function(executorPlayerId, filename)
  5088.             if not filename then
  5089.                 sendresponse("The current KickBans file name is " .. defaults.commands_file .. ".log", executorPlayerId)
  5090.             elseif match(filename, "%w+") then
  5091.                 defaults.commands_file = filename
  5092.                 sendresponse("The KickBans file has been changed to " .. defaults.commands_file .. ".log", executorPlayerId)
  5093.             else
  5094.                 sendresponse("File names must contain alphanumerical characters only!", executorPlayerId)
  5095.             end
  5096.         end
  5097.     }
  5098. )
  5099.  
  5100. Commands.Create(
  5101.     "adminfile",
  5102.     {
  5103.         help = [[-- Admins Text File Name
  5104.         -- Syntax: %s {Filename}
  5105.         -- Allows the executor to view and change the name of the 'admins.txt' file.]],
  5106.     },
  5107.     {
  5108.         arguments = {"String", minArgs = 0, maxArgs = 1},
  5109.         func = function(executorPlayerId, filename)
  5110.             if not filename then
  5111.                 sendresponse("The current Admins file name is " .. defaults.admin_file .. ".txt", executorPlayerId)
  5112.             elseif match(filename, "%w+") then
  5113.                 defaults.admin_file = filename
  5114.                 sendresponse("The Admins file has been changed to " .. defaults.admin_file .. ".txt", executorPlayerId)
  5115.             else
  5116.                 sendresponse("File names must contain alphanumerical characters only!", executorPlayerId)
  5117.             end
  5118.         end
  5119.     }
  5120. )
  5121.  
  5122. Commands.Create(
  5123.     "sharedhashfile",
  5124.     {
  5125.         help = [[-- Shared Hashes Text File Name
  5126.         -- Syntax: %s {Filename}
  5127.         -- Allows the executor to view and change the name of the 'sharedhashes.txt' file.
  5128.         -- The Shared Hashes file contain hashes that cannot be banned, because they are used by lots of different players.]],
  5129.     },
  5130.     {
  5131.         arguments = {"String", minArgs = 0, maxArgs = 1},
  5132.         func = function(executorPlayerId, filename)
  5133.             if not filename then
  5134.                 sendresponse("The current Shared Hashes file name is " .. defaults.sharedhash_file .. ".txt", executorPlayerId)
  5135.             elseif match(filename, "%w+") then
  5136.                 defaults.sharedhash_file = filename
  5137.                 sendresponse("The Shared Hashes file has been changed to " .. defaults.sharedhash_file .. ".txt", executorPlayerId)
  5138.             else
  5139.                 sendresponse("File names must contain alphanumerical characters only!", executorPlayerId)
  5140.             end
  5141.         end
  5142.     }
  5143. )
  5144.  
  5145. Commands.Create(
  5146.     "banlistfile",
  5147.     {
  5148.         help = [[-- Kicks and Bans Log File Name
  5149.         -- Syntax: %s {Filename}
  5150.         -- Allows the executor to view and change the name of the 'banned.txt' file.]],
  5151.     },
  5152.     {
  5153.         arguments = {"String", minArgs = 0, maxArgs = 1},
  5154.         func = function(executorPlayerId, filename)
  5155.             if not filename then
  5156.                 sendresponse("The current Banlist File Name is " .. defaults.banlist_file .. ".txt", executorPlayerId)
  5157.             elseif match(filename, "%w+") then
  5158.                 defaults.banlist_file = filename
  5159.                 sendresponse("The Banlist file has been changed to " .. defaults.banlist_file .. ".txt", executorPlayerId)
  5160.             else
  5161.                 sendresponse("File names must contain alphanumerical characters only!", executorPlayerId)
  5162.             end
  5163.         end
  5164.     }
  5165. )
  5166.  
  5167. Commands.Create(
  5168.     "hashbanlist",
  5169.     {
  5170.         help = [[-- Hash Ban List
  5171.         -- Syntax: %s
  5172.         -- Displays all players currently hash banned from the server.]]
  5173.     },
  5174.     {
  5175.         arguments = {minArgs = 0, maxArgs = 0},
  5176.         func = function(executorPlayerId)
  5177.             Commands.banlist[1].func(executorPlayerId, "hash")
  5178.         end
  5179.     }
  5180. )
  5181.  
  5182. Commands.Create(
  5183.     "ipbanlist",
  5184.     {
  5185.         help = [[-- IP Ban List
  5186.         -- Syntax: %s
  5187.         -- Displays all players currently IP banned from the server.]]
  5188.     },
  5189.     {
  5190.         arguments = {minArgs = 0, maxArgs = 0},
  5191.         func = function(executorPlayerId)
  5192.             Commands.banlist[1].func(executorPlayerId, "ip")
  5193.         end
  5194.     }
  5195. )
  5196.  
  5197. Commands.Create(
  5198.     "namebanlist",
  5199.     {
  5200.         help = [[-- Name Ban List
  5201.         -- Syntax: %s
  5202.         -- Displays all players currently name banned from the server.]]
  5203.     },
  5204.     {
  5205.         arguments = {minArgs = 0, maxArgs = 0},
  5206.         func = function(executorPlayerId)
  5207.             Commands.banlist[1].func(executorPlayerId, "name")
  5208.         end
  5209.     }
  5210. )
  5211.  
  5212. Commands.Create(
  5213.     "textbanlist",
  5214.     {
  5215.         help = [[-- Text Ban List
  5216.         -- Syntax: %s
  5217.         -- Displays all players currently chat banned from the server.]]
  5218.     },
  5219.     {
  5220.         arguments = {minArgs = 0, maxArgs = 0},
  5221.         func = function(executorPlayerId)
  5222.             Commands.banlist[1].func(executorPlayerId, "text")
  5223.         end
  5224.     }
  5225. )
  5226.  
  5227. local function getBanlist(banlists, bantype)
  5228.     if banlists ~= "local" then
  5229.         --reloadRemoteBanlist()
  5230.     end
  5231.  
  5232.     local output = {}--TM.New()
  5233.     local cur_time = os.time()
  5234.     local ban_entry, time
  5235.     for id = 1,#ban_table do ban_entry = ban_table[id]
  5236.         if banlists == "both" or ban_entry.remote and banlists == "remote" or not ban_entry.remote and banlists == "local" then
  5237.             time = ban_entry.time
  5238.             if bantype == "all" or (time == -1 or ((time - cur_time) > 0)) and (not bantype or bantype == ban_entry.type) then
  5239.                 output[#output+1] = format("[%u | %s | %s | %s | %s | %s]", id, ban_entry.name, ban_entry.count or "N/A", ban_entry.type, time ~= -1 and formatTime(timeleft) or "Never", ban_entry.reason or "None")
  5240.             end
  5241.         end
  5242.     end
  5243.     return output
  5244. end
  5245.  
  5246. Commands.Create(
  5247.     "banlist",
  5248.     {
  5249.         aliases = {"listbans", "bans", "showbans", "viewbans"},
  5250.         help = [[-- Ban List
  5251.         -- Syntax: %s {ip | hash | chat | name | all}
  5252.         -- Displays all players banned from the server.
  5253.         -- Specifying a second argument will filter the list by the specified bantype.
  5254.         -- Specifying "all" will show everyone who has ever been banned on this server.]]
  5255.     },
  5256.     {
  5257.         arguments = {"String", minArgs = 0, maxArgs = 1},
  5258.         func = function(executorPlayerId, bantype)
  5259.             bantype = bantype and lower(bantype)
  5260.             if bantype and bantype ~= "name" and bantype ~= "chat" and bantype ~= "hash" and bantype ~= "ip" and bantype ~= "all" then
  5261.                 sendresponse("Invalid Bantype. Valid bantypes are IP, Hash, Name, Chat, and All", executorPlayerId)
  5262.                 return
  5263.             end
  5264.  
  5265.             cmdreply.header = "[ID | Name | Bans | Type | Expires | Reason]"
  5266.             cmdreply.delim = "|"
  5267.             cmdreply.align = true
  5268.  
  5269.             local args = defaults.remote_bansystem
  5270.             local output = getBanlist(not args and "local" or args.mode == 1 and "remote" or "both", bantype)
  5271.             for i = 1,#output do
  5272.                 cmdreply[cmdreply()] = output[i]
  5273.             end
  5274.  
  5275.             sendresponse(cmdreply, executorPlayerId)
  5276.         end
  5277.     }
  5278. )
  5279.  
  5280. Commands.Create(
  5281.     "unban",
  5282.     {
  5283.         aliases = {"ipunban", "hashunban", "textunban", "nameunban"},
  5284.         help = [[-- Unban
  5285.         -- Syntax: %s [ID]
  5286.         -- Unbans the specified ban entry and allows the person to rejoin the server.
  5287.         -- Note: This command will NOT remove people COMPLETELY off the banlist, but will allow the banned player to rejoin.
  5288.         -- Use removeban to completely remove someone off the banlist.]]
  5289.     },
  5290.     {
  5291.         arguments = {"Positive Number", minArgs = 1, maxArgs = 1},
  5292.         func = function(executorPlayerId, ID)
  5293.             local entry = ban_table[ID]
  5294.             local cur_time = os.time()
  5295.             local args = defaults.remote_bansystem
  5296.             if not entry or (args and args.mode == 2 and not entry.remote) or (entry.time ~= -1 and entry.time <= cur_time) then
  5297.                 sendresponse("Invalid ID", executorPlayerId)
  5298.                 return
  5299.             end
  5300.  
  5301.             local index = (entry.ip or "") .. ":" .. (entry.hash or "") .. ":" .. entry.name
  5302.             if entry.type == "chat" then
  5303.                 -- unmute them if they are currently in the game.
  5304.                 for playerId = 0,15 do
  5305.                     if getplayer(playerId) and netMatch(entry.ip, getip(playerId)) then
  5306.                         PlayerClass[playerId].muted = false
  5307.                     end
  5308.                 end
  5309.             end
  5310.             local bantype = entry.type
  5311.             entry.time = cur_time -- set the ban expire time to the present.
  5312.            
  5313.             local name = executorPlayerId and PlayerClass[executorPlayerId].admin_entry and PlayerClass[executorPlayerId].admin_entry.name or getname(executorPlayerId)
  5314.             if entry.reason then
  5315.                 if find(entry.reason, "| Unbanned by '") then
  5316.                     entry.reason = gsub(entry.reason, " | Unbanned by '[^\']'", " | Unbanned by '" .. name .. "'")
  5317.                 else
  5318.                     entry.reason = entry.reason .. " | Unbanned by '" .. name .. "'"
  5319.                 end
  5320.             else
  5321.                 entry.reason = "None Given | Unbanned by '" .. name .. "'"
  5322.             end
  5323.  
  5324.             if args and args.mode >= 2 then
  5325.                 http.request(args.http_source, "&bans=" .. toBanTextEntry(entry) .. "&unban=true")
  5326.             end
  5327.  
  5328.             updateBanFiles(bantype) -- update banlist file.
  5329.             sendresponse(bantype .. " ban '" .. index .. "' has been unbanned from the banlist!", executorPlayerId)
  5330.         end
  5331.     }
  5332. )
  5333.  
  5334. Commands.Create(
  5335.     "removeban",
  5336.     {
  5337.         aliases = {"banremove", "deleteban", "bandelete", "wipeban", "banwipe"},
  5338.         help = [[-- Remove Ban
  5339.         -- Syntax: %s [ID]
  5340.         -- Similar to unban but will completely remove the ban entry from the banlist
  5341.         -- Note: this will NOT remove bans on a central remote banlist, but instead will unban them!]]
  5342.     },
  5343.     {
  5344.         arguments = {"Positive Number", minArgs = 1, maxArgs = 1},
  5345.         func = function(executorPlayerId, ID)
  5346.             local entry = ban_table[ID]
  5347.             local cur_time = os.time()
  5348.             local args = defaults.remote_bansystem
  5349.             if not entry or (args and args.mode == 2 and not entry.remote) or (entry.time ~= -1 and entry.time <= cur_time) then
  5350.                 sendresponse("Invalid ID", executorPlayerId)
  5351.                 return
  5352.             end
  5353.  
  5354.             local index = (entry.ip or "") .. ":" .. (entry.hash or "") .. ":" .. entry.name
  5355.             if entry.type == "chat" then
  5356.                 -- unmute them if they are currently in the game.
  5357.                 for playerId = 0,15 do
  5358.                     if getplayer(playerId) and netMatch(entry.ip, getip(playerId)) then
  5359.                         PlayerClass[playerId].muted = false
  5360.                     end
  5361.                 end
  5362.             end
  5363.            
  5364.             -- remove the ban entry from the banlist completely
  5365.             remove(ban_table, ID)
  5366.  
  5367.             if args and args.mode >= 2 then
  5368.                 http.request(args.http_source, "&bans=" .. toBanTextEntry(entry) .. "&unban=true")
  5369.             end
  5370.  
  5371.             updateBanFiles(bantype) -- update banlist file.
  5372.             sendresponse(bantype .. " ban '" .. index .. "' has been unbanned from the banlist!", executorPlayerId)
  5373.         end
  5374.     }
  5375. )
  5376.  
  5377. Commands.Create(
  5378.     "boslist",
  5379.     {
  5380.         help = [[-- Ban on Sight List
  5381.         -- Syntax: %s
  5382.         -- Displays the Ban On Sight list
  5383.         -- These people will be automatically added to the banlist when they join the server.
  5384.         -- Use unbos to remove from this list.]]
  5385.     },
  5386.     {
  5387.         arguments = {minArgs = 0, maxArgs = 0},
  5388.         func = function(executorPlayerId)
  5389.  
  5390.             if not bos_table[1] then
  5391.                 sendresponse("The Ban on Sight list is empty!", executorPlayerId)
  5392.                 return
  5393.             end
  5394.  
  5395.             cmdreply.header = "[ID | Name | Hash | IP]"
  5396.             cmdreply.delim = "|"
  5397.             cmdreply.align = true
  5398.             local bos_entry
  5399.             for id = 1,#bos_table do bos_entry = bos_table[id]
  5400.                 cmdreply[cmdreply()] = format("[%u | %s | %s | %s]", id, bos_entry.name, bos_entry.hash, bos_entry.ip)
  5401.             end
  5402.  
  5403.             sendresponse(cmdreply, executorPlayerId)
  5404.         end
  5405.     }
  5406. )
  5407.  
  5408.  
  5409. Commands.Create(
  5410.     "bosplayers",
  5411.     {
  5412.         aliases = {"bosableplayers"},
  5413.         help = [[-- Bosable Players List
  5414.         -- Syntax: %s
  5415.         -- Shows the available players that can be banned on sight.
  5416.         -- This list is constructed from people who leave the server.]]
  5417.     },
  5418.     {
  5419.         arguments = {minArgs = 0, maxArgs = 0},
  5420.         func = function(executorPlayerId)
  5421.  
  5422.             if not next(leave_table) then
  5423.                 sendresponse("There are no players that can be added as a BOS right now", executorPlayerId)
  5424.                 return
  5425.             end
  5426.  
  5427.             cmdreply.header = "[ID | Name]"
  5428.             cmdreply.delim = "|"
  5429.             cmdreply.align = true
  5430.             local leave_entry
  5431.             for i = 1,16 do leave_entry = leave_table[i]
  5432.                 if leave_entry then
  5433.                     cmdreply[cmdreply()] = "[" .. i .. " | " .. leave_entry.name .. " | " .. leave_entry.ip .. "]"
  5434.                 end
  5435.             end
  5436.  
  5437.             sendresponse(cmdreply, executorPlayerId)
  5438.  
  5439.         end
  5440.     }
  5441. )
  5442.  
  5443. Commands.Create(
  5444.     "changelevel",
  5445.     {
  5446.         aliases = {"adminlevel", "levelchange", "changelevel", "level", "modifylevel", "changeadminlevel", "modifyadminlevel", "setadminlevel"},
  5447.         help = [[-- Change Level Command
  5448.         -- Syntax: %s [Nickname] {Level}
  5449.         -- Change the specified admins' level]]
  5450.     },
  5451.     {
  5452.         arguments = {"String", "Access Level", minArgs = 1, maxArgs = 2},
  5453.         func = function(executorPlayerId, nickname, level)
  5454.  
  5455.             if not next(admin_table) then
  5456.                 sendresponse("There are no admins on this server" , executorPlayerId)
  5457.                 return
  5458.             end
  5459.  
  5460.             for k,thisAdmin in next,admin_table do
  5461.                 if thisAdmin.name == nickname then
  5462.                     if level then
  5463.                         thisAdmin.level = level
  5464.                         sendresponse(nickname .. " is now a level " .. level .. (thisAdmin.type == "ip" and " IP Admin" or " Hash Admin"), executorPlayerId)
  5465.                         updateAdminFiles()
  5466.                     else
  5467.                         sendresponse(nickname .. " is currently a level " .. thisAdmin.level .. (thisAdmin.type == "ip" and " IP Admin" or " Hash Admin"), executorPlayerId)
  5468.                     end
  5469.                     return
  5470.                 end
  5471.             end
  5472.  
  5473.             sendresponse("Invalid Nickname", executorPlayerId)
  5474.  
  5475.         end
  5476.     }
  5477. )
  5478.  
  5479. Commands.Create(
  5480.     "changeteam",
  5481.     {
  5482.         aliases = {"ts", "teamchange", "swapteam", "teamswap"},
  5483.         help = [[-- Change team Command
  5484.         -- Syntax: %s [Player]
  5485.         -- Change the specified players team]]
  5486.     },
  5487.     {
  5488.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5489.         func = function(executorPlayerId, players)
  5490.             if team_play then
  5491.                 local playerId
  5492.                 for i = 1,#players do playerId = players[i]
  5493.                     changeteam(playerId, true)
  5494.                     sendresponse(getname(playerId) .. " has been forced to change teams", executorPlayerId)
  5495.                 end
  5496.             else
  5497.                 sendresponse("Can only be applied to team games.", executorPlayerId)
  5498.             end
  5499.         end
  5500.     }
  5501. )
  5502.  
  5503. Commands.Create(
  5504.     "disconnect",
  5505.     {
  5506.         aliases = {"losenetworkconnection", "loseconnection", "dc"},
  5507.         help = [[-- Disconnect Player
  5508.         -- Syntax: %s [Player]
  5509.         -- Will forcibly cause the player to lose connection to the server,
  5510.         -- This will not affect the server]]
  5511.     },
  5512.     {
  5513.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5514.         func = function(executorPlayerId, players)
  5515.  
  5516.             local machine_base = readdword(addresses.network_pointer) -- Confirmed.
  5517.             local machine_table = machine_base + 0xAA0 -- Confirmed. Player machine table
  5518.             local playerId, m_player, player_machine_index, machine_struct, machine_network
  5519.             for i = 1,#players do playerId = players[i]
  5520.                 m_player = getplayer(playerId)
  5521.                 player_machine_index = readbyte(m_player + 0x64)
  5522.                 machine_struct = readdword(machine_table + player_machine_index*4)
  5523.                 machine_network = readdword(readdword(machine_struct))
  5524.                 writebyte(machine_network, 0)
  5525.                 halo_svcmd("sv_kick " .. resolveplayer(playerId)) -- just because it takes ages for the server to figure out they quit
  5526.                 cmdreply[cmdreply()] = getname(playerId) .. " has lost connection successfully."
  5527.             end
  5528.  
  5529.             sendresponse(cmdreply, executorPlayerId)
  5530.  
  5531.         end
  5532.     }
  5533. )
  5534.  
  5535. Commands.Create(
  5536.     "count",
  5537.     {
  5538.         aliases = {"uniques", "uniqueplayers"},
  5539.         help = [[-- Count
  5540.         -- Syntax: %s
  5541.         -- It will display the number of unique users.]]
  5542.     },
  5543.     {
  5544.         arguments = {minArgs = 0, maxArgs = 0},
  5545.         func = function(executorPlayerId)
  5546.  
  5547.             if not defaults.uniques_enabled then
  5548.                 sendresponse("'sv_uniques_enabled' is currently disabled.", executorPlayerId)
  5549.                 return
  5550.             end
  5551.  
  5552.             sendresponse("There are " .. unique_table.total .. " unique users that have been to this server", executorPlayerId)
  5553.         end
  5554.     }
  5555. )
  5556.  
  5557. Commands.Create(
  5558.     "commands",
  5559.     {
  5560.         aliases = {"cmds", "commandlist", "list", "listcommands", "showcommands", "allcommands", "getcommands", "viewcommands"},
  5561.         help = [[-- Commands
  5562.         --Syntax %s
  5563.         -- Lists the commands you are allowed to executed]]
  5564.     },
  5565.     {
  5566.         arguments = {minArgs = 0, maxArgs = 0},
  5567.         func = function(executorPlayerId)
  5568.  
  5569.             if not executorPlayerId then
  5570.                 sendresponse("All Commands: " .. concat(Commands, ", "), executorPlayerId)
  5571.                 return
  5572.             end
  5573.             local admin_entry = PlayerClass[executorPlayerId].admin_entry
  5574.             if admin_entry and admin_entry ~= true then
  5575.                 sendresponse(concat(access_table[admin_entry.level or 0], " | "), executorPlayerId)
  5576.             end
  5577.         end
  5578.     }
  5579. )
  5580.  
  5581. Commands.Create(
  5582.     "crash",
  5583.     {
  5584.         scrimBlock = true,
  5585.         help = [[-- Crash Player's Game
  5586.         -- Syntax: %s [Player]
  5587.         -- This command will crash the players game,
  5588.         -- This will not affect the server
  5589.         -- Use this command sparingly. It has been known to crash servers (ironic right?) on abuse]]
  5590.     },
  5591.     {
  5592.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5593.         func = function(executorPlayerId, players)
  5594.  
  5595.             if gameend then
  5596.                 sendresponse("You cannot crash a player while the game is ended. Wait until next game.", executorPlayerId)
  5597.                 return
  5598.             end
  5599.  
  5600.             local exname = getname(executorPlayerId)
  5601.  
  5602.             local playerId, objectId, name
  5603.             for i = 1,#players do playerId = players[i]
  5604.  
  5605.                 name = getname(playerId)
  5606.                 if not checkAdminBlockerAccess(executorPlayerId, playerId) then
  5607.                     sendresponse("You cannot use this command on " .. name, executorPlayerId)
  5608.                     privatesay(playerId, exname .. " attempted to Crash you!")
  5609.                     goto continue
  5610.                 end
  5611.                
  5612.                 local mapId = gettag("vehi", "vehicles\\warthog\\mp_warthog")
  5613.                 if mapId then
  5614.                     objectId = createobject(mapId, 0, 1, false, 0, 1, 2)
  5615.                     if not objectId then break end
  5616.                 end
  5617.                 entervehicle(playerId, objectId, 5)
  5618.                 destroyobject(objectId)
  5619.                 cmdreply[cmdreply()] = name .. " had their game crashed by an admin"
  5620.  
  5621.                 ::continue::
  5622.             end
  5623.  
  5624.             sendresponse(cmdreply, executorPlayerId)
  5625.         end
  5626.     }
  5627. )
  5628.  
  5629. Commands.Create(
  5630.     "damage",
  5631.     {
  5632.         aliases = {"dmg", "setdmg", "setdmgmulti", "setdamage"},
  5633.         scrimBlock = true,
  5634.         help = [[-- Damage Multiplier
  5635.         -- Syntax: %s [Player] [Damage Multiplier]
  5636.         -- Increases the amount of damage the player does.]]
  5637.     },
  5638.     {
  5639.         arguments = {"Player", "Number", minArgs = 2, maxArgs = 2},
  5640.         func = function(executorPlayerId, players, value)
  5641.             local playerId
  5642.             for i = 1,#players do playerId = players[i]
  5643.                 if value then
  5644.                     PlayerClass[playerId].dmgmultiplier = value
  5645.                     cmdreply[cmdreply()] = getname(playerId) .. " now has a damage multiplier of " .. value
  5646.                 else
  5647.                     cmdreply[cmdreply()] = getname(playerId) .. " has a damage multiplier of " .. PlayerClass[playerId].dmgmultiplier
  5648.                 end
  5649.             end
  5650.  
  5651.             sendresponse(cmdreply, executorPlayerId)
  5652.         end
  5653.     }
  5654. )
  5655.  
  5656. Commands.Create(
  5657.     "delrcon",
  5658.     {
  5659.         aliases = {"rcondel"},
  5660.         help = [[-- Delete Rcon Password
  5661.         -- Syntax: %s {Password}
  5662.         -- Deletes the rcon password.]]
  5663.     },
  5664.     {
  5665.         arguments = {"String", minArgs = 1, maxArgs = 1},
  5666.         func = function(executorPlayerId, password)
  5667.  
  5668.             if not rcon_passwords[password] then
  5669.                 sendresponse(password .. " is not a rcon password", executorPlayerId)
  5670.                 return
  5671.             end
  5672.  
  5673.             rcon_passwords[password] = nil
  5674.             sendresponse(password .. " is no longer a rcon password", executorPlayerId)
  5675.         end
  5676.     }
  5677. )
  5678.  
  5679. Commands.Create(
  5680.     "eject",
  5681.     {
  5682.         aliases = {"playereject", "ejectplayer"},
  5683.         scrimBlock = true,
  5684.         help = [[-- Eject
  5685.         -- Syntax: %s [Player]
  5686.         -- Force the specified players to exit their vehicle]]
  5687.     },
  5688.     {
  5689.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5690.         func = function(executorPlayerId, players)
  5691.  
  5692.             local playerId, m_playerObj
  5693.             for i = 1,#players do playerId = players[i]
  5694.                 m_playerObj = getplayerobject(playerId)
  5695.                 if m_playerObj and isinvehicle(playerId) then
  5696.                     exitvehicle(playerId)
  5697.                     cmdreply[cmdreply()] = "Ejecting " .. getname(playerId) .. " from their vehicle"
  5698.                 else
  5699.                     cmdreply[cmdreply()] = getname(playerId) .. " is not in a vehicle"
  5700.                 end
  5701.             end
  5702.  
  5703.             sendresponse(cmdreply, executorPlayerId)
  5704.         end
  5705.     }
  5706. )
  5707.  
  5708. Commands.Create(
  5709.     "gethash",
  5710.     {
  5711.         aliases = {"hash", "gethash"},
  5712.         help = [[-- Get Player Hash
  5713.         -- Syntax: %s [Player]
  5714.         -- Gets the specified player's hash]]
  5715.     },
  5716.     {
  5717.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5718.         func = function(executorPlayerId, players)
  5719.  
  5720.             local playerId
  5721.             for i = 1,#players do playerId = players[i]
  5722.                 cmdreply[cmdreply()] = getname(playerId) .. ": " .. gethash(playerId)
  5723.             end
  5724.  
  5725.             sendresponse(cmdreply, executorPlayerId)
  5726.         end
  5727.     }
  5728. )
  5729.  
  5730. Commands.Create(
  5731.     "getip",
  5732.     {
  5733.         help = [[-- Get IP
  5734.         -- Syntax: %s [Player]
  5735.         -- Get the specified playersIP address]]
  5736.     },
  5737.     {
  5738.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5739.         func = function(executorPlayerId, players)
  5740.  
  5741.             local playerId
  5742.             for i = 1,#players do playerId = players[i]
  5743.                 cmdreply[cmdreply()] = getname(playerId) .. ": " .. getip(playerId)
  5744.             end
  5745.  
  5746.             sendresponse(cmdreply, executorPlayerId)
  5747.         end
  5748.     }
  5749. )
  5750.  
  5751. Commands.Create(
  5752.     "getloc",
  5753.     {
  5754.         aliases = {"getplayerlocation", "getplayerloc", "getplayercoords", "getcoords", "coords", "playerloc", "playercoords"},
  5755.         help = [[-- Get Location
  5756.         -- Syntax: %s [Player]
  5757.         -- Get the specified players' world coordinates in the server]]
  5758.     },
  5759.     {
  5760.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5761.         func = function(executorPlayerId, players)
  5762.  
  5763.             local playerId
  5764.             for i = 1,#players do playerId = players[i]
  5765.                 local m_playerObj, playerObjId = getplayerobject(playerId)
  5766.                 if m_playerObj then
  5767.                     local x,y,z = getobjectcoords(playerObjId, m_playerObj)
  5768.                     x,y,z = round(x, 2),round(y, 2),round(z, 2)
  5769.                     cmdreply[cmdreply()] = getname(playerId) .. "'s coords are: X: " .. x .. "  Y: " .. y .. "  Z: " .. z
  5770.                 else
  5771.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  5772.                 end
  5773.             end
  5774.  
  5775.             sendresponse(cmdreply, executorPlayerId)
  5776.         end
  5777.     }
  5778. )
  5779.  
  5780. Commands.Create(
  5781.     "setgod",
  5782.     {
  5783.         aliases = {"g", "god", "godmode", "godset", "cheatgod", "cheatsetgod", "cheatgodmode", "cheatinvincible", "invincible"},
  5784.         scrimBlock = true,
  5785.         help = [[-- Set God
  5786.         -- Syntax: %s [Player]
  5787.         -- Gives you lots of health]]
  5788.     },
  5789.     {
  5790.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5791.         func = function(executorPlayerId, players)
  5792.  
  5793.             if defaults.deathless then
  5794.                 sendresponse("Deathless is enabled. You cannot give out godmode", executorPlayerId)
  5795.                 return
  5796.             end
  5797.  
  5798.             local playerId, player, m_playerObj
  5799.             for i = 1,#players do playerId = players[i]
  5800.                 m_playerObj = getplayerobject(playerId)
  5801.                 if m_playerObj then
  5802.                     player = PlayerClass[playerId]
  5803.                     if not player.godmode then
  5804.                         cmdreply[cmdreply()] = getname(playerId) .. " has been given godmode"
  5805.                         player.godmode = true
  5806.                     else
  5807.                         cmdreply[cmdreply()] = getname(playerId) .. " is already in godmode"
  5808.                     end
  5809.                 else
  5810.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  5811.                 end
  5812.             end
  5813.  
  5814.             sendresponse(cmdreply, executorPlayerId)
  5815.         end
  5816.     }
  5817. )
  5818.  
  5819. Commands.Create(
  5820.     "cheathax",
  5821.     {
  5822.         aliases = {"hax", "haxolu", "haxor", "1337"},
  5823.         scrimBlock = true,
  5824.         help = [[-- Cheat Hax
  5825.         -- Syntax: %s [Player]
  5826.         -- I will never tell]]
  5827.     },
  5828.     {
  5829.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5830.         func = function(executorPlayerId, players)
  5831.  
  5832.             local playerId, m_player
  5833.             for i = 1,#players do playerId = players[i]
  5834.                 m_player = getplayer(playerId)
  5835.                 setscore(playerId, 9999)
  5836.                 writeshort(m_player + 0x9C, 9999)
  5837.                 writeshort(m_player + 0xA4, 9999)
  5838.                 writeshort(m_player + 0xAC, 9999)
  5839.                 writeshort(m_player + 0xAE, 9999)
  5840.                 writeshort(m_player + 0xB0, 9999)
  5841.                 cmdreply[cmdreply()] = getname(playerId) .. " has been haxed"
  5842.             end
  5843.  
  5844.             sendresponse(cmdreply, executorPlayerId)
  5845.         end
  5846.     }
  5847. )
  5848.  
  5849. Commands.Create(
  5850.     "heal",
  5851.     {
  5852.         aliases = {"healplayer", "playerheal", "cheatheal", "restorehealth", "cheatrestorehealth", "cheatheal"},
  5853.         scrimBlock = true,
  5854.         help = [[-- Heal
  5855.         -- Syntax: %s [Player]
  5856.         -- Heal the specified players]]
  5857.     },
  5858.     {
  5859.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5860.         func = function(executorPlayerId, players)
  5861.  
  5862.             local playerId, m_playerObj, playerObjId, mapId, obj_health, m_vehicleObj, x, y, z, healthpack
  5863.             for i = 1,#players do playerId = players[i]
  5864.                 m_playerObj, playerObjId = getplayerobject(playerId)
  5865.                 if m_playerObj then
  5866.                     obj_health = readfloat(m_playerObj + 0xE0)
  5867.                     if obj_health < 1 then
  5868.                         m_vehicleObj = getplayervehicle(playerId)
  5869.                         if not m_vehicleObj then
  5870.                             x,y,z = getobjectcoords(playerObjId)
  5871.                             mapId = gettag("eqip", "powerups\\health pack")
  5872.                             if mapId then
  5873.                                 healthpack = getobject(createobject(mapId, 0, 0, false, x, y, z+0.5))
  5874.                             else
  5875.                                 cmdreply[cmdreply()] = "Health Pack could not be spawned!"
  5876.                             end
  5877.                             if healthpack then writefloat(healthpack + 0x70, -2) end
  5878.                         else
  5879.                             writefloat(m_playerObj + 0xE0, 1)
  5880.                         end
  5881.                         cmdreply[cmdreply()] = getname(playerId) .. " has been healed"
  5882.                     else
  5883.                         cmdreply[cmdreply()] = getname(playerId) .. " is already at full health"
  5884.                     end
  5885.                 else
  5886.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  5887.                 end
  5888.             end
  5889.  
  5890.             sendresponse(cmdreply, executorPlayerId)
  5891.         end
  5892.     }
  5893. )
  5894.  
  5895. Commands.Create(
  5896.     "hide",
  5897.     {
  5898.         aliases = {"hideplayer", "playerhide", "cheathide"},
  5899.         scrimBlock = true,
  5900.         help = [[-- Hide
  5901.         -- Syntax: %s [Player]
  5902.         -- You are invisible. Not Camo.]]
  5903.     },
  5904.     {
  5905.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5906.         func = function(executorPlayerId, players)
  5907.  
  5908.             local playerId, player
  5909.             for i = 1,#players do playerId = players[i]
  5910.                 player = PlayerClass[playerId]
  5911.                 if not player.hidden then
  5912.                     cmdreply[cmdreply()] = getname(playerId) .. " is now hidden"
  5913.                     player.hidden = true
  5914.                 else
  5915.                     cmdreply[cmdreply()] = getname(playerId) .. " is already hidden"
  5916.                 end
  5917.             end
  5918.  
  5919.             sendresponse(cmdreply, executorPlayerId)
  5920.         end
  5921.     }
  5922. )
  5923.  
  5924. Commands.Create(
  5925.     "info",
  5926.     {
  5927.         aliases = {"i", "playerinfo", "infoplayer", "getplayerinfo", "getinfo"},
  5928.         help = [[-- Info
  5929.         Syntax: %s [Player]
  5930.         -- Returns a lot of info of the specified player]]
  5931.     },
  5932.     {
  5933.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5934.         func = function(executorPlayerId, players)
  5935.  
  5936.             local gametype_maximum_health = readfloat(addresses.gametype_base + 0x54)
  5937.            
  5938.             local playerId
  5939.             local invis_info,crouch,health_info,objective_mode,flashlight_mode,flashlight_level
  5940.             local x,y,z
  5941.             local primary_weap_heat, primary_weap_age, primary_weap_ammo, primary_weap_clip, primary_weap_info
  5942.             local secondary_weap_heat, secondary_weap_age, secondary_weap_ammo, secondary_weap_clip, secondary_weap_info
  5943.             for i = 1,#players do playerId = players[i]
  5944.                 local m_player = getplayer(playerId)
  5945.                 local ip = getip(playerId)
  5946.                 local player = PlayerClass[playerId]
  5947.  
  5948.                 local team = getteam(playerId)
  5949.                 local teamsize = getteamsize(team)
  5950.                 team = team_play and (team == 0 and "Red" or team == 1 or "Blue" or "Hidden") or "FFA " .. team
  5951.  
  5952.  
  5953.                 local respawntime = round(readdword(m_player + 0x2C) * 0.033, 2)
  5954.                 local invis_time = round(readword(m_player + 0x68) * 0.033, 2)
  5955.                 local speed = readfloat(m_player + 0x6C)
  5956.                 local objective_mode = readbyte(m_player + 0x74)
  5957.                 local objective_mode2 = readbyte(m_player + 0x7A)
  5958.                 local killstreak = readword(m_player + 0x96)
  5959.                 local kills = readshort(m_player + 0x9C)
  5960.                 local assists = readshort(m_player + 0xA4)
  5961.                 local suicides = readshort(m_player + 0xB0)
  5962.                 local betrays = readshort(m_player + 0xAC) + suicides
  5963.                 local deaths = readshort(m_player + 0xAE)
  5964.                 local ping = readword(m_player + 0xDC)
  5965.  
  5966.                 local m_playerObj, playerObjId = getplayerobject(playerId)
  5967.  
  5968.                 local primary_weap_info = "Primary: Empty"
  5969.                 local secondary_weap_info = "Secondary: Empty"
  5970.                 local weap_slot, nade_info
  5971.                 if m_playerObj then
  5972.                     local m_vehicleObj = getplayervehicle(playerId)
  5973.                     x,y,z = getobjectcoords(playerObjId)
  5974.                     x,y,z = round(x, 2),round(y, 2),round(z, 2)
  5975.  
  5976.                     local health = round(readfloat(m_playerObj + 0xE0) * 100)
  5977.                     local shields = round(readfloat(m_playerObj + 0xE4) * 100)
  5978.                     local max_health = round(health * readfloat(m_playerObj + 0xD8) / 100)
  5979.                     local max_shields = round(shields * readfloat(m_playerObj + 0xDC) / 100)
  5980.                     flashlight_mode = readbit(m_playerObj + 0x204, 19) and "On" or "Off"
  5981.                     crouch = readbyte(m_playerObj + 0x2A0)
  5982.                     weap_slot = readbyte(m_playerObj + 0x2F2)
  5983.                     local nade_type = readbyte(m_playerObj + 0x31C)
  5984.                     local primary_nades = readbyte(m_playerObj + 0x31E)
  5985.                     local secondary_nades = readbyte(m_playerObj + 0x31F)
  5986.                     flashlight_level = round(readfloat(m_playerObj + 0x344) * 100)
  5987.  
  5988.                     local invis_scale = round(readfloat(m_playerObj + 0x37C) * 100, 2)
  5989.                     invis_scale = invis_scale == 0 and "No" or invis_scale .. "%"
  5990.                     invis_info = invis_scale ~= "No" and "Invis: " .. invis_scale .. " (" .. invis_time .. " secs)" or "Invis: " .. invis_scale
  5991.  
  5992.                     local m_primaryWeapObj, m_secondaryWeapObj
  5993.                     if m_vehicleObj then
  5994.                         m_primaryWeapObj = getobject(readdword(m_vehicleObj + 0x2F8))
  5995.                     elseif weap_slot == 1 then
  5996.                         m_primaryWeapObj = getobject(readdword(m_playerObj + 0x2FC))
  5997.                         m_secondaryWeapObj = getobject(readdword(m_playerObj + 0x2F8))
  5998.                     else
  5999.                         m_primaryWeapObj = getobject(readdword(m_playerObj + 0x2F8))
  6000.                         m_secondaryWeapObj = getobject(readdword(m_playerObj + 0x2FC))
  6001.                     end
  6002.  
  6003.                     if m_primaryWeapObj then
  6004.                         local primary_weap_heat = round(readfloat(m_primaryWeapObj + 0x23C) * 100)
  6005.                         local primary_weap_age = round((1 - readfloat(m_primaryWeapObj + 0x240)) * 100)
  6006.                         local primary_weap_ammo = readword(m_primaryWeapObj + 0x2B6)
  6007.                         local primary_weap_clip = readword(m_primaryWeapObj + 0x2B8)
  6008.                         primary_weap_info = primary_weap_age ~= 100 and "Primary Battery: " .. primary_weap_heat .. "% / " .. primary_weap_age .. "%" or primary_weap_ammo == 0 and primary_weap_clip == 0 and "Primary: Infinite" or "Primary Ammo: " .. primary_weap_clip .. " / " .. primary_weap_ammo
  6009.                     end
  6010.                     if m_secondaryWeapObj then
  6011.                         local secondary_weap_heat = round(readfloat(m_secondaryWeapObj + 0x23C) * 100)
  6012.                         local secondary_weap_age = round((1 - readfloat(m_secondaryWeapObj + 0x240)) * 100)
  6013.                         local secondary_weap_ammo = readword(m_secondaryWeapObj + 0x2B6)
  6014.                         local secondary_weap_clip = readword(m_secondaryWeapObj + 0x2B8)
  6015.                         secondary_weap_info = secondary_weap_age ~= 100 and "Secondary Battery: " .. secondary_weap_heat .. "% / " .. secondary_weap_age .. "%" or secondary_weap_ammo == 0 and secondary_weap_clip == 0 and "Secondary: Infinite" or "Secondary Ammo: " .. secondary_weap_clip .. " / " .. secondary_weap_ammo
  6016.                     end
  6017.  
  6018.                     if crouch == 0 then
  6019.                         crouch = "Warthog: Driver"
  6020.                     elseif crouch == 1 then
  6021.                         crouch = "Warthog: Gunner"
  6022.                     elseif crouch == 2 then
  6023.                         crouch = "Warthog: Passenger"
  6024.                     elseif crouch == 3 then
  6025.                         crouch = "Stance: Crouching"
  6026.                     elseif crouch == 4 then
  6027.                         crouch = "Stance: Standing"
  6028.                     elseif crouch == 5 then
  6029.                         crouch = "Ghost: Driver"
  6030.                     elseif crouch == 6 then
  6031.                         crouch = "Banshee: Pilot"
  6032.                     elseif crouch == 13 then
  6033.                         crouch = "Scorpion: Driver"
  6034.                     elseif crouch == 17 then
  6035.                         crouch = "Shade: Gunner"
  6036.                     elseif crouch == 20 or crouch == 21 or crouch == 22 or crouch == 23 then
  6037.                         crouch = "Scorpion: Passenger"
  6038.                     end
  6039.  
  6040.                     nade_info = "Frag Grenades: " .. primary_nades .. " | " .. "Plasma Grenades: " .. secondary_nades
  6041.                     nade_info = nade_type == 1 and "Plasma Grenades: " .. secondary_nades .. " | " .. "Frag Grenades: " .. primary_nades or nade_info
  6042.  
  6043.                     if crouch == "Stance: Crouching" or crouch == "Stance: Standing" then
  6044.                         if readbyte(m_playerObj + 0x4CC) == 1 then
  6045.                             crouch = "Stance: Airborne"
  6046.                         end
  6047.                     end
  6048.                     if player.suspended then
  6049.                         health_info = "Respawn: Player is Suspended"
  6050.                     else
  6051.                         health_info = format("Health: %s%% (%s) | Shields: %s%% (%s)", health, max_health, shields, max_shields)
  6052.                     end
  6053.                 else
  6054.                     crouch = "Stance: Dead"
  6055.                     health_info = respawntime == 1 and "Respawn: " .. respawntime .. " sec" or "Respawn: " .. respawntime .. " secs"
  6056.                 end
  6057.  
  6058.                 if objective_mode == 0x22 and objective_mode2 == 0x71 then
  6059.                     objective_mode = "Hill"
  6060.                 elseif objective_mode == 0x23 and objective_mode2 == 0x71 then
  6061.                     objective_mode = "Juggernaut"
  6062.                 elseif objective_mode == 0x23 and objective_mode2 == 0x72 then
  6063.                     objective_mode = "It"
  6064.                 elseif objective_mode == 0x29 and objective_mode2 == 0x70 then
  6065.                     objective_mode = "Ball"
  6066.                 elseif weap_slot == 2 then
  6067.                     objective_mode = "Flag"
  6068.                 else
  6069.                     objective_mode = "None"
  6070.                 end
  6071.  
  6072.                 cmdreply.delim = "|"
  6073.                 cmdreply[cmdreply()] = "----------"
  6074.                 cmdreply[cmdreply()] = format("Name: %s ( %u ) | Team: %s (%s) | Speed: %s | Location: (%s, %s, %s)", getname(playerId), resolveplayer(playerId), team, teamsize, round(speed, 2), x, y, z)
  6075.                 cmdreply[cmdreply()] = format("Hash: %s | IP: %s", gethash(playerId), ip)
  6076.                 cmdreply[cmdreply()] = format("Admin: %s | Ping: %s | %s", player.admin_entry and "YES" or "NO", ping, crouch)
  6077.                 cmdreply[cmdreply()] = format("Kills: %s (%s) | Assists: %s | Betrays %s | Suicides %s | Deaths %s", kills, killstreak, assists, betrays, suicides, deaths)
  6078.                 cmdreply[cmdreply()] = format("%s | %s | Light: %s (%s%%)", health_info, invis_info, flashlight_mode, flashlight_level)
  6079.                 cmdreply[cmdreply()] = format("%s | %s | Objective: %s", primary_weap_info, secondary_weap_info, objective_mode)
  6080.                 cmdreply[cmdreply()] = nade_info
  6081.                 cmdreply[cmdreply()] = format("Hidden: %s | God: %s | AFK: %s", player.hidden, player.godmode, player.afk)
  6082.                 cmdreply[cmdreply()] = "----------"
  6083.  
  6084.             end
  6085.  
  6086.             sendresponse(cmdreply, executorPlayerId)
  6087.         end
  6088.     }
  6089. )
  6090.  
  6091. Commands.Create(
  6092.     "ipban",
  6093.     {
  6094.         aliases = {"banip", "ipbanplayer"},
  6095.         help = [[-- IP Ban
  6096.         -- Syntax: %s [Player or IP] {Time} {Reason}
  6097.         -- Will ban a player/ip from the server.]],
  6098.         usesBanCounts = true,
  6099.     },
  6100.     {
  6101.         arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3},
  6102.         func = function(executorPlayerId, players, time, reason)
  6103.  
  6104.             local exname = getname(executorPlayerId)
  6105.             local playerId, name
  6106.             for i = 1,#players do playerId = players[i]
  6107.  
  6108.                 name = getname(playerId)
  6109.                 if not checkAdminBlockerAccess(executorPlayerId, playerId) then
  6110.                     sendresponse("You cannot use this command on " .. name, executorPlayerId)
  6111.                     privatesay(playerId, exname .. " attempted to IPBan you!")
  6112.                     goto continue
  6113.                 end
  6114.                 tempBanPlayer(resolveplayer(playerId))
  6115.                 addBan(name, nil, getip(playerId) .. "/24", time, "ip", reason)
  6116.  
  6117.                 WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was banned by " .. exname .. " Reason: " .. reason .. " Type: IP Ban")
  6118.  
  6119.                 say(name .. " was IP banned! Reason: " .. reason)
  6120.                 cmdreply[cmdreply()] = name .. " has been IP banned"
  6121.                 sendresponse(cmdreply, executorPlayerId)
  6122.  
  6123.                 ::continue::
  6124.             end
  6125.         end
  6126.     },
  6127.     {
  6128.         arguments = {"IP Address", "Time And Reason", minArgs = 1, maxArgs = 3},
  6129.         func = function(executorPlayerId, ip_address, time, reason)
  6130.             local exname = getname(executorPlayerId)
  6131.             addBan("manual_ban", nil, ip_address, time, "ip", reason)
  6132.             WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", "The IP: " .. ip_address .. " was banned by " .. exname .. " Reason: " .. reason .. " Type: IP Ban")
  6133.             sendresponse(ip_address .. " has been IP banned successfully.", executorPlayerId)
  6134.         end
  6135.     }
  6136. )
  6137.  
  6138. Commands.Create(
  6139.     "invis",
  6140.     {
  6141.         aliases = {"camo", "camouflage", "setcamo", "cheatsetcamo", "cheatcamo", "cheatgivecamo", "givecamo"},
  6142.         help = [[-- Invis
  6143.         -- Syntax: %s [Player] {Time}
  6144.         -- Will camo the specified player.]]
  6145.     },
  6146.     {
  6147.         arguments = {"Player", "Time", minArgs = 1, maxArgs = 2},
  6148.         func = function(executorPlayerId, players, time)
  6149.  
  6150.             local playerId, m_playerObj, playerObjId, player
  6151.             for i = 1,#players do playerId = players[i]
  6152.                 m_playerObj, playerObjId = getplayerobject(playerId)
  6153.                 if not m_playerObj then
  6154.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  6155.                     goto continue
  6156.                 end
  6157.  
  6158.                 player = PlayerClass[playerId]
  6159.                 if player.invisible then
  6160.                     cmdreply[cmdreply()] = getname(playerId) .. " is already invisible"
  6161.                     goto continue
  6162.                 end
  6163.  
  6164.                 player.invisible = time
  6165.                 cmdreply[cmdreply()] = getname(playerId) .. " is now invisible"
  6166.  
  6167.                 ::continue::
  6168.             end
  6169.  
  6170.             sendresponse(cmdreply, executorPlayerId)
  6171.         end
  6172.     }
  6173. )
  6174.  
  6175. Commands.Create(
  6176.     "kick",
  6177.     {
  6178.         aliases = {"k", "kickplayer", "playerkick"},
  6179.         help = [[-- Kick
  6180.         -- Syntax: %s [Player] {Reason}
  6181.         -- Kicks the player out of the server with a reason written to the KicksAndBans.log]]
  6182.     },
  6183.     {
  6184.         arguments = {"Player", "Remaining Arguments", minArgs = 1, maxArgs = 2},
  6185.         func = function(executorPlayerId, players, reason)
  6186.             reason = reason or "None Given"
  6187.             local exname = getname(executorPlayerId)
  6188.             local playerId, name
  6189.             for i = 1,#players do playerId = players[i]
  6190.  
  6191.                 name = getname(playerId)
  6192.                 if not checkAdminBlockerAccess(executorPlayerId, playerId) then
  6193.                     sendresponse("You cannot use this command on " .. name, executorPlayerId)
  6194.                     privatesay(playerId, exname .. " attempted to Kick you!")
  6195.                     goto continue
  6196.                 end
  6197.  
  6198.                 WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was kicked by " .. exname .. " Reason: " .. reason)
  6199.                 say(name .. " has been kicked! Reason: " .. reason)
  6200.                 sendresponse(name .. " has been kicked from the server", executorPlayerId)
  6201.                 halo_svcmd("sv_kick " .. resolveplayer(playerId))
  6202.  
  6203.                 ::continue::
  6204.             end
  6205.         end
  6206.     }
  6207. )
  6208.  
  6209. Commands.Create(
  6210.     "kill",
  6211.     {
  6212.         aliases = {"killplayer", "playerkill", "cheatkill", "cheatkillplayer"},
  6213.         scrimBlock = true,
  6214.         help = [[-- Kill Player
  6215.         -- Syntax: %s [Player]
  6216.         -- Kills the specified player, and forces them to respawn.]]
  6217.     },
  6218.     {
  6219.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  6220.         func = function(executorPlayerId, players)
  6221.  
  6222.             local playerId
  6223.             for i = 1,#players do playerId = players[i]
  6224.                 if not getplayerobject(playerId) then
  6225.                     sendresponse(getname(playerId) .. " is already dead!", executorPlayerId)
  6226.                     goto continue
  6227.                 end
  6228.  
  6229.                 kill(playerId)
  6230.                 sendresponse(getname(playerId) .. " has been killed", executorPlayerId)
  6231.  
  6232.                 ::continue::
  6233.             end
  6234.         end
  6235.     }
  6236. )
  6237.  
  6238. Commands.Create(
  6239.     "launch",
  6240.     {
  6241.         help = [[-- Launch
  6242.         -- Syntax: %s [Player]
  6243.         -- Launches the person in a random direction.]]
  6244.     },
  6245.     {
  6246.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  6247.         func = function(executorPlayerId, players)
  6248.  
  6249.             local playerId, m_vehicleObj, vehicleObjId
  6250.             for i = 1,#players do playerId = players[i]
  6251.                 m_vehicleObj, vehicleObjId = getplayervehicle(playerId)
  6252.                 if not m_vehicleObj then
  6253.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead/not in a vehicle"
  6254.                     goto continue
  6255.                 end
  6256.  
  6257.                 local x_or_y = rand(1, 3)
  6258.                 if x_or_y == 1 then
  6259.                     local x_rand_vel = rand(6, 11)
  6260.                     writefloat(m_vehicleObj + 0x94, x_rand_vel)
  6261.                     writefloat(m_vehicleObj + 0x90, 0)
  6262.                     writefloat(m_vehicleObj + 0x8C, 0)
  6263.                 elseif x_or_y == 2 then
  6264.                     local y_rand_vel = rand(6, 11)
  6265.                     writefloat(m_vehicleObj + 0x8C, y_rand_vel)
  6266.                     writefloat(m_vehicleObj + 0x90, 0)
  6267.                     writefloat(m_vehicleObj + 0x94, 0)
  6268.                 else
  6269.                     local z_rand_vel = rand(6, 11)
  6270.                     writefloat(m_vehicleObj + 0x90, z_rand_vel)
  6271.                     writefloat(m_vehicleObj + 0x94, 0)
  6272.                     writefloat(m_vehicleObj + 0x8C, 0)
  6273.                 end
  6274.  
  6275.                 writefloat(m_vehicleObj + 0x70, 0.1)
  6276.                 cmdreply[cmdreply()] = getname(playerId) .. " has been launched!"
  6277.  
  6278.                 -- update object physics
  6279.                 writefloat(m_vehicleObj + 0x70, 0.4)
  6280.                 writebit(m_vehicleObj + 0x10, 0, 0) -- Unset noCollisions bit32.
  6281.                 writebit(m_vehicleObj + 0x10, 5, 0) -- Unset ignorePhysics.
  6282.  
  6283.                 ::continue::
  6284.             end
  6285.  
  6286.             sendresponse(cmdreply, executorPlayerId)
  6287.  
  6288.         end
  6289.     }
  6290. )
  6291.  
  6292. function lo3Timer(id, count)
  6293.     if gameend then return false end
  6294.     if count >= 3 then
  6295.         if not defaults.scrim_mode then say "WARNING! Scrim mode is NOT on!" end
  6296.         say "Start your match"
  6297.         halo_svcmd "sv_map_reset"
  6298.         lo3_timer = nil
  6299.         return false
  6300.     else
  6301.         halo_svcmd "sv_map_reset"
  6302.         return true
  6303.     end
  6304. end
  6305.  
  6306. Commands.Create(
  6307.     "lo3",
  6308.     {
  6309.         aliases = {"scrim", "startscrim"},
  6310.         help = [[-- Live on Three
  6311.         -- Syntax: %s
  6312.         -- This command will reset the map 3 times]]
  6313.     },
  6314.     {
  6315.         arguments = {minArgs = 0, maxArgs = 0},
  6316.         func = function(executorPlayerId)
  6317.  
  6318.             if lo3_timer then
  6319.                 sendresponse("Live on three is already in progress! Please wait!", executorPlayerId)
  6320.             else
  6321.                 sendresponse("Live on three.", executorPlayerId)
  6322.                 lo3_timer = registertimer(500, "lo3Timer")
  6323.             end
  6324.  
  6325.             sendresponse("Live on three.", executorPlayerId)
  6326.         end
  6327.     }
  6328. )
  6329.  
  6330. Commands.Create(
  6331.     "login",
  6332.     {
  6333.         aliases = {"l"},
  6334.         help = [[-- Login
  6335.         -- Syntax: %s [Username] [Password]
  6336.         -- If there are no admins in the admin_table then you will be able to login with this command
  6337.         -- so you are able to use Chat commands even without being a hash or IP admin, it is only temporary.]]
  6338.     },
  6339.     {
  6340.         arguments = {"String", "String", minArgs = 2, maxArgs = 2},
  6341.         func = function(executorPlayerId, username, password)
  6342.             if not executorPlayerId then
  6343.                 sendresponse("the Server is always logged in.", executorPlayerId)
  6344.                 return
  6345.             end
  6346.  
  6347.             if PlayerClass[executorPlayerId].tempadmin then
  6348.                 sendresponse("You are already logged in", executorPlayerId)
  6349.                 return
  6350.             end
  6351.  
  6352.             if PlayerClass[executorPlayerId].admin_entry then
  6353.                 sendresponse("You are already an admin!", executorPlayerId)
  6354.                 return
  6355.             end
  6356.  
  6357.             if admin_logins[username] == password then
  6358.                 PlayerClass[executorPlayerId].tempadmin = true
  6359.                 sendresponse("You have successfully logged in, you are now able to use chat commands.", executorPlayerId)
  6360.             else
  6361.                 sendresponse("Bad username/password combo.", executorPlayerId)
  6362.             end
  6363.         end
  6364.     }
  6365. )
  6366.  
  6367. Commands.Create(
  6368.     "mnext",
  6369.     {
  6370.         aliases = {"mapnext"},
  6371.         is_alias = true,
  6372.         help = [[-- Map Next
  6373.         -- Syntax: %s
  6374.         -- Shortcut for sv_map_next]]
  6375.     },
  6376.     {
  6377.         arguments = {minArgs = 0, maxArgs = 0},
  6378.         func = function(executorPlayerId)
  6379.             halo_svcmd"sv_map_next"
  6380.             sendresponse("The next map will start shortly", executorPlayerId)
  6381.         end
  6382.     }
  6383. )
  6384.  
  6385. Commands.Create(
  6386.     "reset",
  6387.     {
  6388.         aliases = {"mapreset", "resetmap"},
  6389.         is_alias = true,
  6390.         help = [[-- Map Reset
  6391.         -- Syntax: %s
  6392.         -- Shortcut for sv_map_reset]]
  6393.     },
  6394.     {
  6395.         arguments = {minArgs = 0, maxArgs = 0},
  6396.         func = function(executorPlayerId)
  6397.             halo_svcmd"sv_map_reset"
  6398.             sendresponse("The map has been reset", executorPlayerId)
  6399.         end
  6400.     }
  6401. )
  6402.  
  6403. Commands.Create(
  6404.     "move",
  6405.     {
  6406.         aliases = {"j", "mv"},
  6407.         scrimBlock = true,
  6408.         help = [[-- Move Player
  6409.         -- Syntax: %s [player] [x] [y] [z]
  6410.         -- Move the player by the set number of coords.]]
  6411.     },
  6412.     {
  6413.         arguments = {"Player", "Number", "Number", "Number", minArgs = 4, maxArgs = 4},
  6414.         func = function(executorPlayerId, players, X, Y, Z)
  6415.             local playerId, m_playerObj, playerObjId, x, y, z
  6416.             for i = 1,#players do playerId = players[i]
  6417.                 m_playerObj, playerObjId = getplayerobject(playerId)
  6418.                 if m_playerObj then
  6419.                     x,y,z = getobjectcoords(playerObjId)
  6420.                     movobjectcoords(playerObjId, x+X, y+Y, z+Z)
  6421.                     local m_vehicleObj = getplayervehicle(playerId)
  6422.                     if m_vehicleObj then -- these four lines are only in here for shoo.
  6423.                         writebit(m_vehicleObj + 0x10, 5, 1)
  6424.                     end
  6425.                     cmdreply[cmdreply()] = getname(playerId) .. " has been moved"
  6426.                 else
  6427.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  6428.                 end
  6429.             end
  6430.  
  6431.             sendresponse(cmdreply, executorPlayerId)
  6432.         end
  6433.     }
  6434. )
  6435. --TODO: sv_announce_bans
  6436. Commands.Create(
  6437.     "nameban",
  6438.     {
  6439.         aliases = {"banname"},
  6440.         help = [[-- Name Ban
  6441.         -- Syntax: %s [Player]
  6442.         -- Bans a use of a name in the server]]
  6443.     },
  6444.     {
  6445.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  6446.         func = function(executorPlayerId, players)
  6447.  
  6448.             local exname = getname(executorPlayerId)
  6449.             local playerId, name, ban_entry, found, b
  6450.             for i = 1,#players do playerId = players[i]
  6451.  
  6452.                 name = getname(playerId)
  6453.                 if not checkAdminBlockerAccess(executorPlayerId, playerId) then
  6454.                     sendresponse("You cannot use this command on " .. name, executorPlayerId)
  6455.                     privatesay(playerId, exname .. " attempted to NameBan you!")
  6456.                     goto continue
  6457.                 end
  6458.  
  6459.                 if not randomNames[name] then
  6460.  
  6461.                     b = {}--TM.New()
  6462.                     b.name, b.type = name, "name"
  6463.                     local args = defaults.remote_bansystem
  6464.                     if args and args.mode == 2 then
  6465.                         b.remote = true
  6466.                     end
  6467.                     ban_table[#ban_table+1] = b
  6468.                     updateBanFiles()
  6469.  
  6470.                     cmdreply[cmdreply()] = halo_svcmd("sv_kick " .. resolveplayer(playerId), true)
  6471.                     say(name .. " has been name banned from the server")
  6472.  
  6473.                     ::found::
  6474.                 else
  6475.                     cmdreply[cmdreply()] = "You cannot ban this name because this name has been assigned automatically."
  6476.                 end
  6477.  
  6478.                 ::continue::
  6479.             end
  6480.  
  6481.             sendresponse(cmdreply, executorPlayerId)
  6482.         end
  6483.     }
  6484. )
  6485.  
  6486. Commands.Create(
  6487.     "overshield",
  6488.     {
  6489.         aliases = {"os", "giveos", "osgive", "giveovershield", "overshieldgive", "cheatgiveos", "cheatosgive", "cheatovershield", "cheatplayerovershield", "cheatgiveovershield", "cheatovershieldgive"},
  6490.         scrimBlock = true,
  6491.         help = [[-- OverShield
  6492.         -- Syntax: %s [Player]
  6493.         -- Give specified players an overshield (os)]]
  6494.     },
  6495.     {
  6496.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  6497.         func = function(executorPlayerId, players)
  6498.  
  6499.             local playerId, m_playerObj, playerObjId, mapId, m_vehicleObj, vehicleObjId, x, y, z, overshield, obj_shields
  6500.             for i = 1,#players do playerId = players[i]
  6501.                 m_playerObj, playerObjId = getplayerobject(playerId)
  6502.                 if not m_playerObj then
  6503.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  6504.                     goto continue
  6505.                 end
  6506.  
  6507.                 obj_shields = readfloat(m_playerObj + 0xE4)
  6508.                 if obj_shields > 1 then
  6509.                     cmdreply[cmdreply()] = getname(playerId) .. " already has an overshield"
  6510.                     goto continue
  6511.                 end
  6512.  
  6513.                 m_vehicleObj, vehicleObjId = getplayervehicle(playerId)
  6514.                 if m_vehicleObj then
  6515.                     writefloat(m_playerObj + 0xE4, 3)
  6516.                 else
  6517.                     x,y,z = getobjectcoords(playerObjId)
  6518.                     mapId = gettag("eqip", "powerups\\overshield")
  6519.                     if mapId then
  6520.                         overshield = getobject(createobject(mapId, 0, 0, false, x, y, z+0.5))
  6521.                     else
  6522.                         cmdreply[cmdreply()] = "Overshield could not be spawned!"
  6523.                     end
  6524.                     if overshield then writefloat(overshield + 0x70, -2) end
  6525.                 end
  6526.                 cmdreply[cmdreply()] = getname(playerId) .. " has been given an overshield"
  6527.  
  6528.                 ::continue::
  6529.             end
  6530.  
  6531.             sendresponse(cmdreply, executorPlayerId)
  6532.         end
  6533.     }
  6534. )
  6535.  
  6536. Commands.Create(
  6537.     "players",
  6538.     {
  6539.         aliases = {"pl", "playerlist", "showplayers", "listplayers"},
  6540.         help = [[-- Player List
  6541.         -- Syntax: %s
  6542.         -- Displays a list of players.
  6543.         -- Displays all Player Indicies and Names]]
  6544.     },
  6545.     {
  6546.         arguments = {minArgs = 0, maxArgs = 0},
  6547.         func = function(executorPlayerId)
  6548.  
  6549.             cmdreply.header = "[ID | Name]"
  6550.             cmdreply.delim = "|"
  6551.             cmdreply.align = true
  6552.             local playerId
  6553.             for rconId = 1,16 do playerId = rresolveplayer(rconId)
  6554.                 if getplayer(playerId) then
  6555.                     cmdreply[cmdreply()] = "[" .. rconId .. " (" .. playerId .. ") | " .. getname(playerId) .. "]"
  6556.                 end
  6557.             end
  6558.             sendresponse(cmdreply, executorPlayerId)
  6559.         end
  6560.     }
  6561. )
  6562.  
  6563. Commands.Create(
  6564.     "playersmore",
  6565.     {
  6566.         aliases = {"plmore", "moreplayers"},
  6567.         help = [[-- Extended Player List
  6568.         -- Syntax: %s
  6569.         -- Shows Player ID, Player Name, Player Team, Status(Admin/Regular), IP, and Hash]]
  6570.     },
  6571.     {
  6572.         arguments = {minArgs = 0, maxArgs = 0},
  6573.         func = function(executorPlayerId)
  6574.  
  6575.             cmdreply.header = "[ID | Name | Team | Type | IP | Hash]"
  6576.             cmdreply.delim = "|"
  6577.             cmdreply.align = true
  6578.             local playerId, team
  6579.             for i = 1,16 do playerId = rresolveplayer(i)
  6580.                 if not getplayer(playerId) then goto continue end
  6581.  
  6582.                 team = getteam(playerId)
  6583.                 team = team_play and (team == 0 and "Red" or team == 1 and "Blue" or "Hidden") or "FFA " .. team
  6584.                 cmdreply[cmdreply()] = format("[%s | %s | %s | %s | %s | %s]", i, getname(playerId), team, PlayerClass[playerId].admin_entry and "Admin" or "Regular", getip(playerId), gethash(playerId))
  6585.  
  6586.                 ::continue::
  6587.             end
  6588.  
  6589.             sendresponse(cmdreply, executorPlayerId)
  6590.         end
  6591.     }
  6592. )
  6593.  
  6594. Commands.Create(
  6595.     "privatesay",
  6596.     {
  6597.         aliases = {"pvtsay", "psay", "sayprivately"},
  6598.         help = [[-- Private Say
  6599.         --Syntax %s {player} {message}
  6600.         --Sends a private message to the specifed player]]
  6601.     },
  6602.     {
  6603.         arguments = {"Player", "Remaining Arguments", minArgs = 2, maxArgs = 2},
  6604.         func = function(executorPlayerId, players, message)
  6605.  
  6606.             for i = 1,#players do
  6607.                 sendconsoletext(players[i], message)
  6608.             end
  6609.             sendresponse("Private messages sent.", executorPlayerId)
  6610.         end
  6611.     }
  6612. )
  6613.  
  6614. Commands.Create(
  6615.     "rconlist",
  6616.     {
  6617.         aliases = {"listrcons", "rcons"},
  6618.         help = [[-- Rcon Password List
  6619.         -- Syntax: %s
  6620.         -- Lists all available rcon passwords except the main rcon password]]
  6621.     },
  6622.     {
  6623.         arguments = {minArgs = 0, maxArgs = 0},
  6624.         func = function(executorPlayerId)
  6625.  
  6626.             cmdreply.header = "[Rcon | Level]"
  6627.             cmdreply.align = true
  6628.             cmdreply.delim = "|"
  6629.             local rcon_entry
  6630.             for rcon,level in next,rcon_passwords do
  6631.                 cmdreply[cmdreply()] = "[" .. rcon .. " | " .. level .. "]"
  6632.             end
  6633.  
  6634.             sendresponse(cmdreply, executorPlayerId)
  6635.         end
  6636.     }
  6637. )
  6638.  
  6639. local function tobinary(number)
  6640.     number = tonumber(number) or error("bad argument #1 to 'tobinary' (number expected, got '" .. type(number) .. "')")
  6641.     local t = {}--TM.New()
  6642.     local rest
  6643.     while number > 0 do
  6644.         rest = number % 2
  6645.         t[#t+1] = rest
  6646.         number = (number - rest) * 0.5
  6647.     end
  6648.     return concat(t)
  6649. end
  6650.  
  6651. Commands.Create(
  6652.     "read",
  6653.     {
  6654.         help = [[-- Read Address/Struct
  6655.         -- Syntax: %s [Type] [Struct or Address] [Offset] [Value] [Player or Bit], [Player]
  6656.         -- Read the Guide for info on this command]]
  6657.     },
  6658.     {
  6659.         arguments = {"Struct", "Number", "Bit", "Player", minArgs = 3, maxArgs = 3},
  6660.         func = function(executorPlayerId, struct, offset, bit, players)
  6661.             local playerId, m_playerObj, playerObjId, value, float
  6662.             for i = 1,#players do playerId = players[i]
  6663.                 m_playerObj = getplayerobject(playerId)
  6664.                 if struct == "player" then
  6665.                     struct = getplayer(playerId)
  6666.                 elseif m_playerObj then
  6667.                     if struct == "object" then
  6668.                         struct = m_playerObj
  6669.                     elseif struct == "weapon" then
  6670.                         struct = getplayerweapon(playerId)
  6671.                         if not struct then sendresponse(getname(playerId) .. " is not holding a Weapon", executorPlayerId) return end
  6672.                     elseif struct == "vehicle" then
  6673.                         struct = getplayervehicle(playerId)
  6674.                         if not struct then sendresponse(getname(playerId) .. " is not in a Vehicle", executorPlayerId) return end
  6675.                     end
  6676.                 else
  6677.                     sendresponse("Player Object must exist to use Struct: " .. struct)
  6678.                 end
  6679.                 value = readbit(struct + offset, struct)
  6680.                 sendresponse("Reading " .. format("0x%08X", struct) ..  " at Offset " .. format("0x%X", offset) .. " was a Success", executorPlayerId)
  6681.                 sendresponse("Binary Val: " .. value, executorPlayerId)
  6682.             end
  6683.         end
  6684.     },
  6685.     {
  6686.         arguments = {"Datatype", "Struct", "Number", "Player", minArgs = 3, maxArgs = 3},
  6687.         func = function(executorPlayerId, datatype, struct, offset, players)
  6688.             local playerId, m_playerObj, playerObjId, float, value
  6689.             for i = 1,#players do playerId = players[i]
  6690.                 m_playerObj, playerObjId = getplayerobject(playerId)
  6691.                 if struct == "player" then
  6692.                     struct = getplayer(playerId)
  6693.                 elseif m_playerObj then
  6694.                     if struct == "object" then
  6695.                         struct = m_playerObj
  6696.                     elseif struct == "weapon" then
  6697.                         struct = getplayerweapon(playerId)
  6698.                         if not struct then sendresponse(getname(playerId) .. " is not holding a Weapon", executorPlayerId) end
  6699.                     elseif struct == "vehicle" then
  6700.                         struct = getplayervehicle(playerId)
  6701.                         if not struct then sendresponse(getname(playerId) .. " is not in a Vehicle", executorPlayerId) end
  6702.                     end
  6703.                 else
  6704.                     sendresponse("Player Object must exist to use Struct: " .. struct)
  6705.                 end
  6706.                 if datatype == "bit8" then
  6707.                     value = tobinary(readbyte(struct + offset))
  6708.                 elseif datatype == "bit16" then
  6709.                     value = tobinary(readword(struct + offset))
  6710.                 elseif datatype == "bit32" then
  6711.                     value = tobinary(readdword(struct + offset))
  6712.                 elseif datatype == "char" then
  6713.                     value = readchar(struct + offset)
  6714.                 elseif datatype == "byte" then
  6715.                     value = readbyte(struct + offset)
  6716.                 elseif datatype == "short" then
  6717.                     value = readshort(struct + offset)
  6718.                 elseif datatype == "word" then
  6719.                     value = readword(struct + offset)
  6720.                 elseif datatype == "int" then
  6721.                     value = readint(struct + offset)
  6722.                 elseif datatype == "dword" then
  6723.                     value = readdword(struct + offset)
  6724.                 elseif datatype == "float" then
  6725.                     float = true
  6726.                     value = readfloat(struct + offset)
  6727.                 elseif datatype == "string" then
  6728.                     value = readstring(struct + offset)
  6729.                 elseif datatype == "widestring" then
  6730.                     value = readwidestring(struct + offset)
  6731.                 end
  6732.                 sendresponse("Reading Address " .. format("0x%08X", struct) .. " was a Success", executorPlayerId)
  6733.                 if not match(datatype, "^bit%d+$") then
  6734.                     if float then
  6735.                         sendresponse("Float: " .. value, executorPlayerId)
  6736.                     elseif type(value) == "number" then
  6737.                         sendresponse("Decimal: " .. value .. (value >= 0 and (" Hex: " .. format("0x%X", value)) or ""), executorPlayerId)
  6738.                     else
  6739.                         sendresponse("Value: " .. value, executorPlayerId)
  6740.                     end
  6741.                 else
  6742.                     sendresponse("Binary Val: " .. value, executorPlayerId)
  6743.                 end
  6744.             end
  6745.         end
  6746.     },
  6747.     {
  6748.         arguments = {"Datatype", "Number", "Number", minArgs = 3, maxArgs = 3},
  6749.         func = function(executorPlayerId, datatype, address, offset)
  6750.             local float, value
  6751.             if datatype == "bit8" then
  6752.                 value = tobinary(readbyte(address + offset))
  6753.             elseif datatype == "bit16" then
  6754.                 value = tobinary(readword(address + offset))
  6755.             elseif datatype == "bit32" then
  6756.                 value = tobinary(readdword(address + offset))
  6757.             elseif datatype == "char" then
  6758.                 value = readchar(address + offset)
  6759.             elseif datatype == "byte" then
  6760.                 value = readbyte(address + offset)
  6761.             elseif datatype == "short" then
  6762.                 value = readshort(address + offset)
  6763.             elseif datatype == "word" then
  6764.                 value = readword(address + offset)
  6765.             elseif datatype == "int" then
  6766.                 value = readint(address + offset)
  6767.             elseif datatype == "dword" then
  6768.                 value = readdword(address + offset)
  6769.             elseif datatype == "float" then
  6770.                 float = true
  6771.                 value = readfloat(address + offset)
  6772.             elseif datatype == "string" then
  6773.                 value = readstring(address + offset)
  6774.             elseif datatype == "widestring" then
  6775.                 value = readwidestring(address + offset)
  6776.             end
  6777.             sendresponse("Reading Address " .. format("0x%08X", offset) .. " was a Success", executorPlayerId)
  6778.             if float then
  6779.                 sendresponse("Float: " .. value, executorPlayerId)
  6780.             elseif value >= 0 then
  6781.                 sendresponse("Decimal: " .. value .. " Hex: " .. format("0x%X", value), executorPlayerId)
  6782.             else
  6783.                 sendresponse("Value: " .. value, executorPlayerId)
  6784.             end
  6785.         end
  6786.     },
  6787.     {
  6788.         arguments = {"Number", "Number", "Bit", minArgs = 3, maxArgs = 3},
  6789.         func = function(executorPlayerId, address, offset, bit)
  6790.             sendresponse("Reading Address " .. format("0x%08X", address) .. " was a Success", executorPlayerId)
  6791.             sendresponse("Binary Val: " .. readbit(address + offset, bit) and 1 or 0, executorPlayerId)
  6792.         end
  6793.     }
  6794. )
  6795.  
  6796. Commands.Create(
  6797.     "write",
  6798.     {
  6799.         help = [[-- Write
  6800.         -- Syntax: %s [Type] [Struct] [Offset] [Value] [Player]
  6801.         -- Read the Guide for info on this command]]
  6802.     },
  6803.     {
  6804.         arguments = {"Datatype", "Struct", "Whole Number", "Number", "Player", minArgs = 3, maxArgs = 5},
  6805.         func = function(executorPlayerId, datatype, struct, offset, value, playerId)
  6806.             --[[local address
  6807.             if count >= 5 and count <= 6 then
  6808.                 if lower(sub(offset, 1, 2)) == "0x" then
  6809.                     offset = tonumber(sub(offset, 3), 16)
  6810.                 else
  6811.                     offset = tonumber(offset) or tonumber(offset, 16)
  6812.                 end
  6813.                 local players = getvalidplayers(playerId, executorPlayerId)
  6814.                 if players then
  6815.                     local playerId
  6816.                     for i = 1,#players do playerId = players[i]
  6817.                         local m_playerObj, playerObjId = getplayerobject(playerId)
  6818.                         if struct == "player" then
  6819.                             address = getplayer(playerId)
  6820.                         elseif struct ~= "object" and struct ~= "weapon" and struct ~= "vehicle" then
  6821.                             sendresponse("Invalid Struct. Valid structs are: playerId, object, weapon, and vehicle.", executorPlayerId)
  6822.                         elseif m_playerObj then
  6823.                             if struct == "object" then
  6824.                                 address = m_playerObj
  6825.                             elseif struct == "weapon" then
  6826.                                 address = getplayerweapon(playerId)
  6827.                                 if not address then sendresponse(getname(playerId) .. " is not holding a weapon", executorPlayerId) end
  6828.                             elseif struct == "vehicle" then
  6829.                                 address = getplayervehicle(playerId)
  6830.                                 if not address then sendresponse(getname(playerId) .. " is not in a vehicle", executorPlayerId) end
  6831.                             elseif not struct then
  6832.                                 sendresponse("Invalid Struct. Valid structs are: playerId, object, weapon, and vehicle", executorPlayerId)
  6833.                             end
  6834.                         elseif struct ~= "object" and struct ~= "weapon" and struct ~= "vehicle" then
  6835.                             sendresponse("Invalid Struct. Valid structs are: playerId, object, weapon, and vehicle.", executorPlayerId)
  6836.                         else
  6837.                             sendresponse("playerId object must exist to use struct: " .. struct)
  6838.                         end
  6839.                         if offset and address then
  6840.                             if lower(sub(tostring(value), 2)) == "0x" then
  6841.                                 value = tonumber(sub(tostring(value), 3), 16)
  6842.                             else
  6843.                                 value = tonumber(value) or tonumber(value, 16)
  6844.                             end
  6845.                             if value then
  6846.                                 if datatype == "char" then
  6847.                                     writechar(address + offset, value)
  6848.                                 elseif datatype == "byte" then
  6849.                                     writebyte(address + offset, value)
  6850.                                 elseif datatype == "short" then
  6851.                                     writeshort(address + offset, value)
  6852.                                 elseif datatype == "word" then
  6853.                                     writeword(address + offset, value)
  6854.                                 elseif datatype == "int" then
  6855.                                     writeint(address + offset, value)
  6856.                                 elseif datatype == "dword" then
  6857.                                     writedword(address + offset, value)
  6858.                                 elseif datatype == "float" then
  6859.                                     writefloat(address + offset, value)
  6860.                                 elseif datatype == "string" then
  6861.                                     writestring(address + offset, value)
  6862.                                 elseif datatype == "widestring" then
  6863.                                     writewidestring(address + offset, value)
  6864.                                 else
  6865.                                     sendresponse("Invalid datatype. Valid datatypes are 'char', 'byte', 'short', 'word', 'int', 'dword', 'float', 'string', and 'widestring'", executorPlayerId)
  6866.                                 end
  6867.                                 sendresponse("Writing " .. value .. " to address " .. format("0x%08X", offset) .. " was a success", executorPlayerId)
  6868.                             else
  6869.                                 sendresponse("Value must be a number", executorPlayerId)
  6870.                             end
  6871.                         elseif not offset then
  6872.                             sendresponse("Offset must be a number", executorPlayerId)
  6873.                         end
  6874.                     end
  6875.                 elseif not playerId then
  6876.                     if lower(sub(struct, 1, 2)) == "0x" then
  6877.                         address = tonumber(sub(struct, 3), 16)
  6878.                     else
  6879.                         address = tonumber(struct) or tonumber(struct, 16)
  6880.                     end
  6881.                     if address then
  6882.                         if offset then
  6883.                             if lower(sub(value, 1, 2)) == "0x" then
  6884.                                 value = tonumber(sub(value, 3), 16)
  6885.                             else
  6886.                                 value = tonumber(value) or tonumber(value, 16)
  6887.                             end
  6888.                             if value then
  6889.                                 if datatype == "char" then
  6890.                                     writechar(address + offset, value)
  6891.                                 elseif datatype == "byte" then
  6892.                                     writebyte(address + offset, value)
  6893.                                 elseif datatype == "short" then
  6894.                                     writeshort(address + offset, value)
  6895.                                 elseif datatype == "word" then
  6896.                                     writeword(address + offset, value)
  6897.                                 elseif datatype == "int" then
  6898.                                     writeint(address + offset, value)
  6899.                                 elseif datatype == "dword" then
  6900.                                     writedword(address + offset, value)
  6901.                                 elseif datatype == "float" then
  6902.                                     writefloat(address + offset, value)
  6903.                                 elseif datatype == "string" then
  6904.                                     writestring(address + offset, value)
  6905.                                 elseif datatype == "widestring" then
  6906.                                     writewidestring(address + offset, value)
  6907.                                 else
  6908.                                     sendresponse("Invalid datatype. Valid datatypes are 'char', 'byte', 'short', 'word', 'int', 'dword', 'float', 'string', and 'widestring'", executorPlayerId)
  6909.                                     return
  6910.                                 end
  6911.                                 sendresponse("Writing " .. value .. " to address " .. format("0x%08X", offset) .. " was a success", executorPlayerId)
  6912.                             else
  6913.                                 sendresponse("Value must be a number.", executorPlayerId)
  6914.                             end
  6915.                         else
  6916.                             sendresponse("Offset must be a number", executorPlayerId)
  6917.                         end
  6918.                     else
  6919.                         sendresponse("Struct must be a number", executorPlayerId)
  6920.                     end
  6921.                 else
  6922.                     sendresponse("Invalid Player", executorPlayerId)
  6923.                 end
  6924.             end]]
  6925.         end
  6926.     }
  6927. )
  6928.  
  6929. Commands.Create(
  6930.     "resetplayer",
  6931.     {
  6932.         aliases = {"playerreset", "playereset"},
  6933.         help = [[-- Reset Player
  6934.         -- Syntax: %s [Player]
  6935.         -- Removes all troll settings from specified player]]
  6936.     },
  6937.     {
  6938.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  6939.         func = function(executorPlayerId, players)
  6940.  
  6941.             local playerId
  6942.             for i = 1,#players do playerId = players[i]
  6943.                 ResetPlayer(playerId)
  6944.                 cmdreply[cmdreply()] = getname(playerId) .. " has been reset."
  6945.             end
  6946.  
  6947.             sendresponse(cmdreply, executorPlayerId)
  6948.         end
  6949.     }
  6950. )
  6951.  
  6952. Commands.Create(
  6953.     "resetweapons",
  6954.     {
  6955.         aliases = {"resetweaps", "weaponsreset", "weapsreset"},
  6956.         scrimBlock = true,
  6957.         help = [[-- Reset Weapons
  6958.         -- Syntax: %s [Player]
  6959.         -- Reset the weapons of the specified players]]
  6960.     },
  6961.     {
  6962.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  6963.         func = function(executorPlayerId, players)
  6964.  
  6965.             local playerId, player, m_playerObj
  6966.             for i = 1,#players do playerId = players[i]
  6967.                 PlayerClass[playerId].disarmed = false
  6968.                 resetweapons(playerId)
  6969.                 cmdreply[cmdreply()] = getname(playerId) .. " had their weapons reset"
  6970.             end
  6971.  
  6972.             sendresponse(cmdreply, executorPlayerId)
  6973.         end
  6974.     }
  6975. )
  6976.  
  6977. Commands.Create(
  6978.     "resp",
  6979.     {
  6980.         aliases = {"respplayer", "playerresp"},
  6981.         scrimBlock = true,
  6982.         help = [[-- Respawn Time for Player
  6983.         -- Syntax: %s [Player] {Time}
  6984.         -- Change the player's respawn time]]
  6985.     },
  6986.     {
  6987.         arguments = {"Player", "Time", minArgs = 2, maxArgs = 2},
  6988.         func = function(executorPlayerId, players, time)
  6989.  
  6990.             local playerId, m_playerObj
  6991.             for i = 1,#players do playerId = players[i]
  6992.                 m_playerObj = getplayerobject(playerId)
  6993.                 if not m_playerObj then
  6994.                     writedword(getplayer(playerId) + 0x2C, time)
  6995.                     cmdreply[cmdreply()] = "Setting " .. getname(playerId) .. "'s respawn time to " .. timetoword(time)
  6996.                 else
  6997.                     cmdreply[cmdreply()] = getname(playerId) .. " is alive. Setting their respawn time will do nothing."
  6998.                 end
  6999.             end
  7000.  
  7001.             sendresponse(cmdreply, executorPlayerId)
  7002.         end
  7003.     }
  7004. )
  7005.  
  7006. Commands.Create(
  7007.     "rtvrequired",
  7008.     {
  7009.         aliases = {"rtvneeded", "totalrtv", "rtvtotal", "rtvpercent", "rtvpercentage", "rockthevoteneeded", "rockthevotepercent", "rockthevotetotal", "totalrockthevote", "midgamevoteneeded"},
  7010.         help = [[-- RTV Needed
  7011.         -- Syntax: %s [Percent]
  7012.         -- Change the number of votes needed for RTV to change the map.]]
  7013.     },
  7014.     {
  7015.         arguments = {"Percent", minArgs = 0, maxArgs = 1},
  7016.         func = function(executorPlayerId, percent)
  7017.             if percent then
  7018.                 sendresponse("Votes required for RTV has been set to " .. percent .. "%", executorPlayerId)
  7019.                 defaults.rtv_required = percent
  7020.             else
  7021.                 sendresponse(defaults.rtv_required .. "% votes required for RTV", executorPlayerId)
  7022.             end
  7023.         end
  7024.     }
  7025. )
  7026.  
  7027. Commands.Create(
  7028.     "rtvtimeout",
  7029.     {
  7030.         aliases = {"rockthevotetimeout"},
  7031.         help = [[-- RTV Timeout
  7032.         -- Syntax: %s {Time}
  7033.         -- The amount of time between each RTV attempt.]]
  7034.     },
  7035.     {
  7036.         arguments = {"Time", minArgs = 0, maxArgs = 1},
  7037.         func = function(executorPlayerId, time)
  7038.             if time == -1 then
  7039.                 sendresponse("RTV Timeout is currently " .. timetoword(defaults.rtv_timeout), executorPlayerId)
  7040.             else
  7041.                 sendresponse("RTV Timeout has been set to " .. timetoword(time), executorPlayerId)
  7042.                 defaults.rtv_timeout = time
  7043.             end
  7044.         end
  7045.     }
  7046. )
  7047.  
  7048. Commands.Create(
  7049.     "setammo",
  7050.     {
  7051.         aliases = {"ammo", "ammoset"},
  7052.         scrimBlock = true,
  7053.         help = [[-- Set Ammo
  7054.         -- Syntax: %s [Player] [Type] [Ammo]
  7055.         -- Set the ammo of the players specified
  7056.         -- type means type of ammo, use 1 for unloaded ammo and 2 for loaded ammo]]
  7057.     },
  7058.     {
  7059.         arguments = {"Player", "String", "Whole Number", minArgs = 3, maxArgs = 3},
  7060.         func = function(executorPlayerId, players, ammotype, ammo)
  7061.  
  7062.             local playerId, m_playerObj, playerObjId, m_weaponObj, weaponObjId
  7063.             for i = 1,#players do playerId = players[i]
  7064.                 m_playerObj, playerObjId = getplayerobject(playerId)
  7065.                 if not m_playerObj then
  7066.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead and cannot have ammo"
  7067.                     goto continue
  7068.                 end
  7069.  
  7070.                 m_weaponObj, weaponObjId = getplayerweapon(playerId)
  7071.                 if not m_weaponObj then
  7072.                     cmdreply[cmdreply()] = getname(playerId) .. " is not holding any weapons"
  7073.                     goto continue
  7074.                 end
  7075.  
  7076.                 if ammotype == "unloaded" or ammotype == "1" then
  7077.                     writeword(m_weaponObj + 0x2B6, ammo)
  7078.                     cmdreply[cmdreply()] = getname(playerId) .. " had their unloaded ammo changed to " .. ammo
  7079.                 elseif ammotype == "loaded" or ammotype == "2" then
  7080.                     writeword(m_weaponObj + 0x2B8, ammo)
  7081.                     updateammo(weaponObjId)
  7082.                     cmdreply[cmdreply()] = getname(playerId) .. " had their loaded ammo changed to " .. ammo
  7083.                 else
  7084.                     cmdreply[cmdreply()] = "Invalid ammo type: 1 for unloaded, 2 for loaded ammo"
  7085.                 end
  7086.  
  7087.                 ::continue::
  7088.             end
  7089.  
  7090.             sendresponse(cmdreply, executorPlayerId)
  7091.         end
  7092.     }
  7093. )
  7094.  
  7095. Commands.Create(
  7096.     "color",
  7097.     {
  7098.         aliases = {"setcolor", "colorset", "playercolor", "cheatsetcolor", "cheatplayercolor"},
  7099.         scrimBlock = true,
  7100.         help = [[-- Set Color
  7101.         -- Syntax: %s [Player] [Color]
  7102.         -- Change the color of the selected player. Works on FFA Only]]
  7103.     },
  7104.     {
  7105.         arguments = {"Player", "String", minArgs = 1, maxArgs = 2},
  7106.         func = function(executorPlayerId, players, color)
  7107.  
  7108.             -- check if argument is correct color
  7109.             if color then
  7110.                 color = tonumber(color) or player_colors[color]
  7111.  
  7112.                 if type(color) ~= "number" then
  7113.                     sendresponse("Invalid Color", executorPlayerId)
  7114.                     return
  7115.                 end
  7116.             end
  7117.  
  7118.             local color_name = player_colors[color]
  7119.             local playerId, m_playerObj, playerObjId, player, x, y, z
  7120.             for i = 1,#players do playerId = players[i]
  7121.                
  7122.                 if not color then
  7123.                     cmdreply[cmdreply()] = getname(playerId) .. " is currently " .. (player_colors[readbyte(getplayer(playerId) + 0x60)] or "Invalid Color")
  7124.                     goto continue
  7125.                 end
  7126.                
  7127.                 setcolor(playerId, color)
  7128.                 cmdreply[cmdreply()] = getname(playerId) .. " had their color changed to '" .. color_name .. "'"
  7129.  
  7130.                 ::continue::
  7131.             end
  7132.  
  7133.             sendresponse(cmdreply, executorPlayerId)
  7134.         end
  7135.     }
  7136. )
  7137.  
  7138. Commands.Create(
  7139.     "assists",
  7140.     {
  7141.         aliases = {"setassists", "assistset"},
  7142.         scrimBlock = true,
  7143.         help = [[-- Set Assists
  7144.         -- Syntax: %s [Player] {Assists}
  7145.         -- Set the assists for the specified players]]
  7146.     },
  7147.     {
  7148.         arguments = {"Player", "Whole Number", minArgs = 1, maxArgs = 2},
  7149.         func = function(executorPlayerId, players, assists)
  7150.             local playerId
  7151.             if not assists then
  7152.                 for i = 1,#players do playerId = players[i]
  7153.                     cmdreply[cmdreply()] = getname(playerId) .. " Assists: " .. tostring(readshort(getplayer(playerId) + 0xA4, assists))
  7154.                 end
  7155.             else
  7156.                 for i = 1,#players do playerId = players[i]
  7157.                     writeshort(getplayer(playerId) + 0xA4, assists)
  7158.                     cmdreply[cmdreply()] = getname(playerId) .. " had their assists set to " .. assists
  7159.                 end
  7160.             end
  7161.             sendresponse(cmdreply, executorPlayerId)
  7162.         end
  7163.     }
  7164. )
  7165.  
  7166. Commands.Create(
  7167.     "deaths",
  7168.     {
  7169.         aliases = {"setdeaths", "deathset"},
  7170.         scrimBlock = true,
  7171.         help = [[-- Set Deaths
  7172.         -- Syntax: %s [Player] {Deaths}
  7173.         -- Set the deaths for the specified players]]
  7174.     },
  7175.     {
  7176.         arguments = {"Player", "Whole Number", minArgs = 1, maxArgs = 2},
  7177.         func = function(executorPlayerId, players, deaths)
  7178.             local playerId
  7179.             if not deaths then
  7180.                 for i = 1,#players do playerId = players[i]
  7181.                     cmdreply[cmdreply()] = getname(playerId) .. " Deaths: " .. tostring(readshort(getplayer(playerId) + 0xAE, deaths))
  7182.                 end
  7183.             else
  7184.                 for i = 1,#players do playerId = players[i]
  7185.                     writeshort(getplayer(playerId) + 0xAE, deaths)
  7186.                     cmdreply[cmdreply()] = getname(playerId) .. " had their deaths set to " .. deaths
  7187.                 end
  7188.             end
  7189.             sendresponse(cmdreply, executorPlayerId)
  7190.         end
  7191.     }
  7192. )
  7193.  
  7194. Commands.Create(
  7195.     "kills",
  7196.     {
  7197.         aliases = {"setkills", "killset"},
  7198.         scrimBlock = true,
  7199.         help = [[-- Set Kills
  7200.         -- Syntax: %s [Player] {Kills}
  7201.         -- Set the kills for the specified players]]
  7202.     },
  7203.     {
  7204.         arguments = {"Player", "Whole Number", minArgs = 1, maxArgs = 2},
  7205.         func = function(executorPlayerId, players, kills)
  7206.             local playerId
  7207.             if not kills then
  7208.                 for i = 1,#players do playerId = players[i]
  7209.                     cmdreply[cmdreply()] = getname(playerId) .. " Kills: " .. tostring(readshort(getplayer(playerId) + 0x9C, kills))
  7210.                 end
  7211.             else
  7212.                 for i = 1,#players do playerId = players[i]
  7213.                     writeshort(getplayer(playerId) + 0x9C, kills)
  7214.                     cmdreply[cmdreply()] = getname(playerId) .. " had their kills set to " .. kills
  7215.                 end
  7216.             end
  7217.             sendresponse(cmdreply, executorPlayerId)
  7218.         end
  7219.     }
  7220. )
  7221.  
  7222. Commands.Create(
  7223.     "score",
  7224.     {
  7225.         aliases = {"setscore", "scoreset"},
  7226.         scrimBlock = true,
  7227.         help = [[-- Set Score
  7228.         -- Syntax: %s [Player] {Score}
  7229.         -- Set the score for the specified players]]
  7230.     },
  7231.     {
  7232.         arguments = {"Player", "Whole Number", minArgs = 1, maxArgs = 2},
  7233.         func = function(executorPlayerId, players, score)
  7234.             local playerId
  7235.             if not score then
  7236.                 for i = 1,#players do playerId = players[i]
  7237.                     cmdreply[cmdreply()] = getname(playerId) .. ": " .. getscore(playerId)
  7238.                 end
  7239.             else
  7240.                 local playerId
  7241.                 for i = 1,#players do playerId = players[i]
  7242.                     setscore(playerId, score)
  7243.                     cmdreply[cmdreply()] = getname(playerId) .. " had their score set to " .. score
  7244.                 end
  7245.  
  7246.                 sendresponse(cmdreply, executorPlayerId)
  7247.             end
  7248.         end
  7249.     }
  7250. )
  7251.  
  7252. Commands.Create(
  7253.     "teamscore",
  7254.     {
  7255.         aliases = {"setteamscore", "seteamscore", "teamscoreset"},
  7256.         scrimBlock = true,
  7257.         help = [[-- Set Team Score
  7258.         -- Syntax: %s [Team] {Score}
  7259.         -- Set the score for the specified team]]
  7260.     },
  7261.     {
  7262.         arguments = {"Whole Number", "Whole Number", minArgs = 1, maxArgs = 2},
  7263.         func = function(executorPlayerId, team, score)
  7264.             if not score then
  7265.                 sendresponse("Team " .. team .. ": " .. getteamscore(team), executorPlayerId)
  7266.             else
  7267.                 setteamscore(team, score)
  7268.                 sendresponse("Team " .. team .. " had their score set to " .. score, executorPlayerId)
  7269.             end
  7270.         end
  7271.     }
  7272. )
  7273.  
  7274. Commands.Create(
  7275.     "scorelimit",
  7276.     {
  7277.         aliases = {"setscorelimit"},
  7278.         help = [[-- Set Score Limit
  7279.         -- Syntax: %s {Score}
  7280.         -- Set the score for the specified players]]
  7281.     },
  7282.     {
  7283.         arguments = {"Whole Number", minArgs = 0, maxArgs = 1},
  7284.         func = function(executorPlayerId, score)
  7285.             if not score then
  7286.                 sendresponse("Scorelimit: " .. getscorelimit(), executorPlayerId)
  7287.             else
  7288.                 sendresponse("Scorelimit set to " .. (setscorelimit(score) or score), executorPlayerId)
  7289.             end
  7290.         end
  7291.     }
  7292. )
  7293.  
  7294. Commands.Create(
  7295.     "frags",
  7296.     {
  7297.         aliases = {"setfrags", "fragset", "setfragnades"},
  7298.         scrimBlock = true,
  7299.         help = [[-- Set Frags
  7300.         -- Syntax: %s [Player] {Frags}
  7301.         -- Set the frags for the specified players]]
  7302.     },
  7303.     {
  7304.         arguments = {"Player", "Whole Number", minArgs = 1, maxArgs = 2},
  7305.         func = function(executorPlayerId, players, frags)
  7306.  
  7307.             frags = frags > 7 and 7 or frags
  7308.  
  7309.             local playerId, m_playerObj, playerObjId
  7310.             for i = 1,#players do playerId = players[i]
  7311.                 m_playerObj, playerObjId = getplayerobject(playerId)
  7312.                 if not m_playerObj then
  7313.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  7314.                     goto continue
  7315.                 end
  7316.                
  7317.                 if not frags then
  7318.                     cmdreply[cmdreply()] = getname(playerId) .. " Frags: " .. readbyte(m_playerObj + 0x31E)
  7319.                 else
  7320.                     writebyte(m_playerObj + 0x31E, frags)
  7321.                     cmdreply[cmdreply()] = "Setting " .. getname(playerId) .. "'s frag grenades to " .. frags
  7322.                     --privatesay(playerId, "Your frag grenades were set to " .. frags)
  7323.                 end
  7324.  
  7325.                 ::continue::
  7326.             end
  7327.  
  7328.             sendresponse(cmdreply, executorPlayerId)
  7329.         end
  7330.     }
  7331. )
  7332.  
  7333. Commands.Create(
  7334.     "plasmas",
  7335.     {
  7336.         aliases = {"setplasmas", "stickies", "plasmaset", "setplasmanades"},
  7337.         scrimBlock = true,
  7338.         help = [[-- Set Plasmas
  7339.         -- Syntax: %s [Player] {Plasmas}
  7340.         -- Set the plasmas for the specified players]]
  7341.     },
  7342.     {
  7343.         arguments = {"Player", "Whole Number", minArgs = 1, maxArgs = 2},
  7344.         func = function(executorPlayerId, players, plasmas)
  7345.  
  7346.             plasmas = plasmas > 7 and 7 or plasmas
  7347.  
  7348.             local playerId, m_playerObj, playerObjId
  7349.             for i = 1,#players do playerId = players[i]
  7350.                 m_playerObj, playerObjId = getplayerobject(playerId)
  7351.                 if not m_playerObj then
  7352.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  7353.                     goto continue
  7354.                 end
  7355.  
  7356.                 if not plasmas then
  7357.                     cmdreply[cmdreply()] = getname(playerId) .. " Plasmas: " .. readbyte(m_playerObj + 0x31E)
  7358.                 else
  7359.                     writebyte(m_playerObj + 0x31E, plasmas)
  7360.                     cmdreply[cmdreply()] = "Setting " .. getname(playerId) .. "'s plasma grenades to " .. plasmas
  7361.                     --privatesay(playerId, "Your plasma grenades were set to " .. plasmas)
  7362.                 end
  7363.  
  7364.                 ::continue::
  7365.             end
  7366.  
  7367.             sendresponse(cmdreply, executorPlayerId)
  7368.         end
  7369.     }
  7370. )
  7371.  
  7372. Commands.Create(
  7373.     "prefix",
  7374.     {
  7375.         aliases = {"setprefix", "serverprefix"},
  7376.         help = [[-- Set Server Prefix
  7377.         -- Syntax: %s [Prefix]
  7378.         -- Will set the server prefix on sv_say messages to whatever you want (e.g. **SERVER** **MYCLAN** **PHASOR**)]]
  7379.     },
  7380.     {
  7381.         arguments = {"Remaining Arguments", minArgs = 0, maxArgs = 1},
  7382.         func = function(executorPlayerId, prefix)
  7383.  
  7384.             if prefix == "default" then
  7385.                 server_prefix = nil
  7386.                 sendresponse("Prefix is now set to default **SERVER**", executorPlayerId)
  7387.             elseif prefix then
  7388.                 server_prefix = prefix
  7389.                 sendresponse(server_prefix .. " is the new prefix.", executorPlayerId)
  7390.             else
  7391.                 sendresponse(server_prefix .. " is the current prefix.", executorPlayerId)
  7392.             end
  7393.         end
  7394.     }
  7395. )
  7396.  
  7397. Commands.Create(
  7398.     "say",
  7399.     {
  7400.         help = [[-- Server Say
  7401.         -- Syntax: %s [Message]
  7402.         -- Will send a message as the Server to anyone currently in the game.]]
  7403.     },
  7404.     {
  7405.         arguments = {"String", minArgs = 1, maxArgs = 1},
  7406.         func = function(executorPlayerId, message)
  7407.             say(message)
  7408.         end
  7409.     }
  7410. )
  7411.  
  7412. Commands.Create(
  7413.     "mode",
  7414.     {
  7415.         aliases = {"setmode", "modeset"},
  7416.         scrimBlock = true,
  7417.         help = [[-- mode
  7418.         -- Syntax: %s [Player] [Mode] {Object}
  7419.         -- destroy
  7420.         -- portalgun
  7421.         -- entergun
  7422.         -- spawngun
  7423.         -- normal]]
  7424.     },
  7425.     {
  7426.         arguments = {"Player", "String", "String", minArgs = 1, maxArgs = 2},
  7427.         func = function(executorPlayerId, players, bulletmode)
  7428.             local playerId
  7429.             for i = 1,#players do playerId = players[i]
  7430.                 if bulletmode == "destroy" then
  7431.                     PlayerClass[playerId].bulletmode = "destroy"
  7432.                     cmdreply[cmdreply()] = getname(playerId) .. " is now in destroy mode"
  7433.                 elseif bulletmode == "portalgun" then
  7434.                     PlayerClass[playerId].bulletmode = "portalgun"
  7435.                     cmdreply[cmdreply()] = getname(playerId) .. " is now in portalgun mode"
  7436.                 elseif bulletmode == "entergun" then
  7437.                     PlayerClass[playerId].bulletmode = "entergun"
  7438.                     cmdreply[cmdreply()] = getname(playerId) .. " is now in entergun mode"
  7439.                 elseif bulletmode == "normal" or bulletmode == "none" or bulletmode == "regular" then
  7440.                     local player = PlayerClass[playerId]
  7441.                     player.objspawnid = false
  7442.                     player.bulletmode = false
  7443.                     cmdreply[cmdreply()] = getname(playerId) .. " is now in normal mode"
  7444.                 elseif bulletmode then
  7445.                     cmdreply[cmdreply()] = "Invalid Bullet Mode!"
  7446.                 else
  7447.                     cmdreply[cmdreply()] = getname(playerId) .. " Bulletmode: " .. PlayerClass[playerId.bulletmode]
  7448.                 end
  7449.             end
  7450.  
  7451.             sendresponse(cmdreply, executorPlayerId)
  7452.  
  7453.         end
  7454.     },
  7455.     {
  7456.         arguments = {"Player", "String", "Object", minArgs = 3, maxArgs = 3},
  7457.         func = function(executorPlayerId, players, bulletmode, object)
  7458.             if bulletmode == "spawngun" then
  7459.                 local playerId, player
  7460.                 for i = 1,#players do playerId = players[i]
  7461.                     player = PlayerClass[playerId]
  7462.                     player.bulletmode = "spawngun"
  7463.                     player.objspawnid = object.mapId
  7464.                     cmdreply[cmdreply()] = getname(playerId) .. " is now spawning " .. object.name .. ""
  7465.                 end
  7466.             else
  7467.                 sendresponse("Invalid Bullet Mode!", executorPlayerId)
  7468.             end
  7469.  
  7470.             sendresponse(cmdreply, executorPlayerId)
  7471.  
  7472.         end
  7473.     }
  7474. )
  7475.  
  7476. Commands.Create(
  7477.     "password",
  7478.     {
  7479.         aliases = {"setpass", "pass", "setpassword", "passwordset"},
  7480.         help = [[-- Set Server Password
  7481.         -- Syntax: %s {Password}
  7482.         -- Self-explanatory.]]
  7483.     },
  7484.     {
  7485.         arguments = {"Password", minArgs = 0, maxArgs = 1},
  7486.         func = function(executorPlayerId, password)
  7487.  
  7488.             if not password then
  7489.                 sendresponse("The password is currently: " .. readstring(addresses.network_server_globals + 0x8, 8), executorPlayerId)
  7490.             elseif password == "" then
  7491.                 writestring(addresses.network_server_globals + 0x8, 8, "")
  7492.                 sendresponse("Password has been taken off", executorPlayerId)
  7493.             elseif password then
  7494.                 writestring(addresses.network_server_globals + 0x8, 8, password)
  7495.                 sendresponse("The password is now " .. password, executorPlayerId)
  7496.             end
  7497.         end
  7498.     }
  7499. )
  7500.  
  7501. Commands.Create(
  7502.     "reloadadmins",
  7503.     {
  7504.         aliases = {"reloadadminlist", "adminlistreload", "adminsreload"},
  7505.         help = [[-- Reload Admin List
  7506.         -- Syntax: %s
  7507.         -- Loads all admins from the admin file.]]
  7508.     },
  7509.     {
  7510.         arguments = {minArgs = 0, maxArgs = 0},
  7511.         func = function(executorPlayerId)
  7512.             loadAllAdminFiles()
  7513.  
  7514.             -- We can now archive the other admin files without worrying about losing the data.
  7515.             os.rename(profilepath .. "ipadmins.txt", profilepath .. "archived_ipadmins.txt")
  7516.             os.rename(profilepath .. "admin.txt", profilepath .. "archived_admin.txt")
  7517.  
  7518.             sendresponse("All admins have been reloaded from the file.", executorPlayerId)
  7519.         end
  7520.     }
  7521. )
  7522.  
  7523. --[====[Commands.Create(
  7524.     "loadbanlist",
  7525.     {
  7526.         aliases = {"banlistload", "loadbans", "bansload", "mergebans", "bansmerge", "mergebanlist", "banlistmerge"},
  7527.         help = [[-- Reload Banlist
  7528.         -- Syntax: %s
  7529.         -- Loads all bans from the ban file.]]
  7530.     },
  7531.     {
  7532.         arguments = {minArgs = 0, maxArgs = 0},
  7533.         func = function(executorPlayerId)
  7534.  
  7535.             -- Save the ban table temporarily
  7536.             local temp_bantable = {}--TM.New()
  7537.             for id = 1,#ban_table do
  7538.                 temp_bantable[id] = ban_table[id]
  7539.             end
  7540.  
  7541.             loadBanFile(profilepath .. "ipbans.txt", "ip") -- load sapp ip bans
  7542.             loadBanFile(profilepath .. "ipbanlist.txt", "ip") -- load ipbanlist file for backwards compatibility
  7543.             loadBanFile(profilepath .. "iprangebanlist.txt", "ip") -- load iprangebanlist file for backwards compatibility
  7544.             loadBanFile(profilepath .. "textbanlist.txt", "chat") -- load textbanlist file for backwards compatibility
  7545.             loadBanFile(profilepath .. "namebans.txt", "name") -- load textbanlist file for backwards compatibility
  7546.  
  7547.             loadBanFile(profilepath .. defaults.banlist_file .. ".txt")
  7548.  
  7549.             -- we're not going to remove the files, let's just rename them so we don't upset anyone.
  7550.             local timestamp = os.date "%Y_%m_%d_%H_%M_%S"
  7551.             os.rename(profilepath .. "ipbans.txt", profilepath .. "old_ipbans_" .. timestamp .. ".txt")
  7552.             os.rename(profilepath .. "ipbanlist.txt", profilepath .. "old_ipbanlist_" .. timestamp .. ".txt")
  7553.             os.rename(profilepath .. "iprangebanlist.txt", profilepath .. "old_iprangebanlist_" .. timestamp .. ".txt")
  7554.             os.rename(profilepath .. "textbanlist.txt", profilepath .. "old_textbanlist_" .. timestamp .. ".txt")
  7555.             os.rename(profilepath .. "namebans.txt", profilepath .. "old_namebans_" .. timestamp .. ".txt")
  7556.  
  7557.             -- Check if a banned player is in the server.
  7558.             local cur_time = os.time()
  7559.             local hash, ip, ban_entry
  7560.             for playerId = 0,15 do
  7561.                 if not getplayer(playerId) then
  7562.                     goto continue
  7563.                 end
  7564.  
  7565.                 hash, ip = gethash(playerId), getip(playerId)
  7566.                 for id = 1,#ban_table do ban_entry = ban_table[id]
  7567.                     if ban_entry.time > cur_time then
  7568.                         if ban_table.type == "hash" and hash == ban_table.hash or ban_table.type == "ip" and netMatch(ban_table.ip, ip) then
  7569.                             tempBanPlayer(resolveplayer(playerId))
  7570.                             break
  7571.                         elseif ban_entry.type == "chat" and (ban_entry.hash == hashOnlyOnScriptReload or netMatch(ban_entry.ip, ip)) then
  7572.                             PlayerClass[playerId].muted = true
  7573.                         elseif ban_entry.type == "name" and ban_entry.name == name then
  7574.                             svcmd("sv_kick " .. resolveplayer(playerId) .. " Found on the Name Banlist during a reload.")
  7575.                             break
  7576.                         end
  7577.                     end
  7578.                 end
  7579.  
  7580.                 ::continue::
  7581.             end
  7582.  
  7583.             updateBanFiles()
  7584.             sendresponse("The Banlist has been reloaded.", executorPlayerId)
  7585.         end
  7586.     }
  7587. )]====]
  7588.  
  7589. Commands.Create(
  7590.     "reloadbanlist",
  7591.     {
  7592.         aliases = {"banlistreload", "reloadbans", "bansreload", "refreshipbans"},
  7593.         help = [[-- Reload Banlist
  7594.         -- Syntax: %s
  7595.         -- Loads all bans from the ban file.]]
  7596.     },
  7597.     {
  7598.         arguments = {minArgs = 0, maxArgs = 0},
  7599.         func = function(executorPlayerId)
  7600.  
  7601.             -- Clear the ban table.
  7602.             for id = 1,#ban_table do
  7603.                 ban_table[id] = nil
  7604.             end
  7605.  
  7606.             local args = defaults.remote_bansystem
  7607.             if args then
  7608.                 reloadRemoteBanlist()
  7609.             end
  7610.             if not args or args and args.mode ~= 2 then
  7611.  
  7612.                 loadBanFile(profilepath .. "ipbans.txt", "ip") -- load sapp ip bans
  7613.                 loadBanFile(profilepath .. "ipbanlist.txt", "ip") -- load ipbanlist file for backwards compatibility
  7614.                 loadBanFile(profilepath .. "iprangebanlist.txt", "ip") -- load iprangebanlist file for backwards compatibility
  7615.                 loadBanFile(profilepath .. "textbanlist.txt", "chat") -- load textbanlist file for backwards compatibility
  7616.                 loadBanFile(profilepath .. "namebans.txt", "name") -- load textbanlist file for backwards compatibility
  7617.  
  7618.                 loadBanFile(profilepath .. defaults.banlist_file .. ".txt")
  7619.  
  7620.                 -- we're not going to remove the files, let's just rename them so we don't upset anyone.
  7621.                 local timestamp = os.date"%Y_%m_%d_%H_%M_%S"
  7622.                 os.rename(profilepath .. "ipbans.txt", profilepath .. "old_ipbans_" .. timestamp .. ".txt")
  7623.                 os.rename(profilepath .. "ipbanlist.txt", profilepath .. "old_ipbanlist_" .. timestamp .. ".txt")
  7624.                 os.rename(profilepath .. "iprangebanlist.txt", profilepath .. "old_iprangebanlist_" .. timestamp .. ".txt")
  7625.                 os.rename(profilepath .. "textbanlist.txt", profilepath .. "old_textbanlist_" .. timestamp .. ".txt")
  7626.                 os.rename(profilepath .. "namebans.txt", profilepath .. "old_namebans_" .. timestamp .. ".txt")
  7627.             end
  7628.  
  7629.             -- The banned player could be currently playing on the server. Apply punishments to players that are found on the banlist.
  7630.             for playerId = 0,15 do
  7631.                 if getplayer(playerId) then
  7632.                     punishIfOnBanlist(playerId)
  7633.                 end
  7634.             end
  7635.  
  7636.             updateBanFiles()
  7637.             sendresponse("The Banlist has been reloaded.", executorPlayerId)
  7638.         end
  7639.     }
  7640. )
  7641.  
  7642. Commands.Create(
  7643.     "respawntime",
  7644.     {
  7645.         aliases = {"setresp", "setrespawntime"},
  7646.         help = [[-- Server Respawn Time
  7647.         -- Syntax: %s {Time}
  7648.         -- Sets the default respawn time for all players.]]
  7649.     },
  7650.     {
  7651.         arguments = {"Time", minArgs = 0, maxArgs = 1},
  7652.         func = function(executorPlayerId, time)
  7653.             if time == -1 then
  7654.                 sendresponse("Respawn time is currently: " .. (defaults.respawn_time ~= -1 and timetoword(defaults.respawn_time) or "Default"))
  7655.             else
  7656.                 defaults.respawn_time = time
  7657.                 sendresponse("Respawn time set to " .. (time ~= -1 and timetoword(time) or "Default"), executorPlayerId)
  7658.             end
  7659.         end
  7660.     }
  7661. )
  7662.  
  7663. Commands.Create(
  7664.     "setspeed",
  7665.     {
  7666.         aliases = {"spd", "s", "speed", "speedset"},
  7667.         scrimBlock = true,
  7668.         help = [[-- Set Speed
  7669.         -- Syntax: %s [Player] {Speed}
  7670.         -- Allow you to view/change the selected players' speed]]
  7671.     },
  7672.     {
  7673.         arguments = {"Player", "Number", minArgs = 1, maxArgs = 2},
  7674.         func = function(executorPlayerId, players, speed)
  7675.             local playerId
  7676.             if not speed then
  7677.                 for i = 1,#players do playerId = players[i]
  7678.                     speed = readfloat(getplayer(playerId) + 0x6C)
  7679.                     sendresponse(getname(playerId) .. "'s speed is currently " .. speed, executorPlayerId)
  7680.                 end
  7681.             else
  7682.                 for i = 1,#players do playerId = players[i]
  7683.                     setspeed(playerId, speed)
  7684.                     sendresponse(getname(playerId) .. " had their speed changed to " .. speed, executorPlayerId)
  7685.                 end
  7686.             end
  7687.         end
  7688.     }
  7689. )
  7690.  
  7691. local function saveTeleportsToFile()
  7692.     local file = assert(io.open(profilepath .. "data\\locations.txt", "w"))
  7693.     local writetbl = {}
  7694.     for map,mapLocations in next,locations do
  7695.         for locname,thisLocation in next,mapLocations do
  7696.             writetbl[#writetbl+1] = map .. "," .. locname .. "," .. thisLocation[1] .. "," .. thisLocation[2] .. "," .. thisLocation[3]
  7697.         end
  7698.     end
  7699.     file:write(concat(writetbl, "\n"))
  7700.     file:close()
  7701. end
  7702.  
  7703. Commands.Create(
  7704.     "setteleport",
  7705.     {
  7706.         aliases = {"settp", "teleportadd", "addteleport", "tadd", "st", "tpadd", "addtp", "addlocation", "locationadd"},
  7707.         help = [[--Set Teleport Location
  7708.         -- Syntax: %s [Location] [Player or X] {Y} {Z}
  7709.         -- Adds a teleport location wherever the specified player is standing.
  7710.         -- Or you can manually specify XYZ Coordinates for a location]]
  7711.     },
  7712.     {
  7713.         arguments = {"String", "Number", "Number", "Number", "String", minArgs = 4, maxArgs = 5},
  7714.         func = function(executorPlayerId, locname, x, y, z, map)
  7715.             locations[map or Map][locname] = {x, y, z}
  7716.             sendresponse("'" .. locname .. "' has been added as a teleport location!", executorPlayerId)
  7717.         end
  7718.     },
  7719.     {
  7720.         arguments = {"String", "Single Player", minArgs = 1, maxArgs = 2},
  7721.         func = function(executorPlayerId, locname, playerId)
  7722.             local m_playerObj, playerObjId = getplayerobject(playerId)
  7723.             if not m_playerObj then
  7724.                 sendresponse("Cannot add teleport because the player is dead.", executorPlayerId)
  7725.                 return
  7726.             end
  7727.  
  7728.             if locations[Map][locname] then
  7729.                 sendresponse("Location '" .. locname .. "' already exists on this map!\nUse sv_teleport_del to remove it from the list first.", executorPlayerId)
  7730.                 return
  7731.             end
  7732.  
  7733.             local x,y,z = getobjectcoords(playerObjId)
  7734.             locations[Map][locname] = {x, y, z}
  7735.             sendresponse("'" .. locname .. "' has been added as a teleport location!", executorPlayerId)
  7736.             saveTeleportsToFile()
  7737.         end
  7738.     }
  7739. )
  7740.  
  7741. Commands.Create(
  7742.     "teleportlist",
  7743.     {
  7744.         aliases = {"tlist", "listteleports", "locations", "teleports", "locs"},
  7745.         help = [[--List Teleport Locations
  7746.         -- Syntax: %s {Map}
  7747.         -- Lists all the teleport locations available for teleporting.]]
  7748.     },
  7749.     {
  7750.         arguments = {"String", minArgs = 0, maxArgs = 0},
  7751.         func = function(executorPlayerId, map)
  7752.             map = map or Map or "all"
  7753.             sendresponse("Teleport Locations " .. (map ~= "all" and (" for map " .. map) or ""), executorPlayerId)
  7754.             cmdreply.header = "Map Location"
  7755.             cmdreply.align = true
  7756.             cmdreply.delim = " "
  7757.             for thisMap,mapLocations in next,locations do
  7758.                 for locname,_ in next,mapLocations do
  7759.                     if map == thisMap or map == "all" then
  7760.                         cmdreply[cmdreply()] = thisMap .. " " .. locname
  7761.                     end
  7762.                 end
  7763.             end
  7764.  
  7765.             sendresponse(cmdreply, executorPlayerId)
  7766.         end
  7767.     }
  7768. )
  7769.  
  7770. Commands.Create(
  7771.     "allvehicles",
  7772.     {
  7773.         aliases = {"allvehis", "spawnvehicles", "spawnallvehicles", "spawnvehis", "spawnallvehi", "spawnallvehis"},
  7774.         help = [[ -- Spawn All Vehicles
  7775.         -- Syntax: %s {Player}
  7776.         -- Spawns all vehicles available to a map at a specific player's location.]]
  7777.     },
  7778.     {
  7779.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  7780.         func = function(executorPlayerId, players)
  7781.             local tag_class, tag_id, tag_name_address, tag_name, tag_address, playerId, playerObjId, m_playerObj, x, y, z
  7782.             for j = 1,#players do playerId = players[j]
  7783.                 for i = 1,#tag_table.vehi do tag_id = tag_table.vehi[i]
  7784.                 --for tag_id,tag_entry in pairs(tag_table) do
  7785.                     playerObjId = getplayerobjectid(playerId)
  7786.                     m_playerObj = getobject(playerObjId)
  7787.                    
  7788.                     x,y,z = getobjectcoords(playerObjId)
  7789.                     x = x + readfloat(m_playerObj + 0x230) * 2
  7790.                     y = y + readfloat(m_playerObj + 0x234) * 2
  7791.                     createobject(tonumber(tag_id), 0, 65534, false, x, y + i*2, z+2)
  7792.                     sendresponse("Vehicle '" .. tostring(tag_id) .. "' spawned at " .. getname(playerId) .. "'s location!", playerId)
  7793.                 end
  7794.             end
  7795.             sendresponse(#tag_table.vehi .. " of each vehicle was spawned.", executorPlayerId)
  7796.         end
  7797.     }
  7798. )
  7799.  
  7800. Commands.Create(
  7801.     "allweapons",
  7802.     {
  7803.         aliases = {"allweaps", "spawnweapons", "spawnallweapons", "spawnweaps", "spawnallweap", "spawnallweaps"},
  7804.         help = [[ -- Spawn All Weapons
  7805.         -- Syntax: %s {Player}
  7806.         -- Spawns all weapons available to a map at a specific player's location.]]
  7807.     },
  7808.     {
  7809.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  7810.         func = function(executorPlayerId, players)
  7811.             local tag_class, tag_id, tag_name_address, tag_name, tag_address, playerId, playerObjId, m_playerObj, x, y, z, iter, objectId, m_object
  7812.             for i = 1,#players do playerId = players[i]
  7813.                 iter = 0
  7814.                 for tag_id,tag_entry in pairs(tag_table) do
  7815.                     if type(tag_entry) == "table" and tag_entry.tag_class == "weap" then
  7816.                         playerObjId = getplayerobjectid(playerId)
  7817.                         m_playerObj = getobject(playerObjId)
  7818.                        
  7819.                         x,y,z = getobjectcoords(playerObjId)
  7820.                         x = x + readfloat(m_playerObj + 0x230) * 2
  7821.                         y = y + readfloat(m_playerObj + 0x234) * 2
  7822.                         objectId = getobject(createobject(tonumber(tag_id), 0, 65534, true, x, y + iter, z+2))
  7823.                         m_object = getobject(objectId)
  7824.                         if m_object then
  7825.                            
  7826.                         end
  7827.                         sendresponse("Weapon '" .. tostring(tag_id) .. "' spawned at " .. getname(playerId) .. "'s location!", playerId)
  7828.                         iter = iter + 0.5
  7829.                     end
  7830.                 end
  7831.             end
  7832.         end
  7833.     }
  7834. )
  7835.  
  7836. Commands.Create(
  7837.     "allequipment",
  7838.     {
  7839.         aliases = {"alleqip", "spawnequipment", "spawnallequipment", "spawneqips", "spawnalleqip", "spawnalleqips"},
  7840.         help = [[ -- Spawn All Equipment
  7841.         -- Syntax: %s {Player}
  7842.         -- Spawns all weapons available to a map at a specific player's location.]]
  7843.     },
  7844.     {
  7845.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  7846.         func = function(executorPlayerId, players)
  7847.             local tag_class, tag_id, tag_name_address, tag_name, tag_address, playerId, playerObjId, m_playerObj, x, y, z, iter
  7848.             for i = 1,#players do playerId = players[i]
  7849.                 iter = 0
  7850.                 for tag_id,tag_entry in pairs(tag_table) do
  7851.                     if type(tag_entry) == "table" and tag_entry.tag_class == "eqip" then
  7852.                         playerObjId = getplayerobjectid(playerId)
  7853.                         m_playerObj = getobject(playerObjId)
  7854.                        
  7855.                         x,y,z = getobjectcoords(playerObjId)
  7856.                         x = x + readfloat(m_playerObj + 0x230) * 2
  7857.                         y = y + readfloat(m_playerObj + 0x234) * 2
  7858.                         createobject(tonumber(tag_id), 0, 65534, true, x, y + iter, z+2 + iter*2)
  7859.                         sendresponse("Equipment '" .. tostring(tag_id) .. "' spawned at " .. getname(playerId) .. "'s location!", playerId)
  7860.                         iter = iter + 0.25
  7861.                     end
  7862.                 end
  7863.             end
  7864.         end
  7865.     }
  7866. )
  7867.  
  7868. -- ADD JETPACK COMMAND FROM BRANDIS SCRIPT HERE!
  7869.  
  7870. Commands.Create(
  7871.     "ghost",
  7872.     {
  7873.         aliases = {"ghostplayer"},
  7874.         help = [[ -- Ghost Player
  7875.         -- Syntax: %s [Player]
  7876.         -- Puts a player into Ghost Mode, they will not have a collision model
  7877.         -- bullets will pass right through them ]]
  7878.     },
  7879.     {
  7880.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  7881.         func = function(executorPlayerId, players)
  7882.             local playerId, m_playerObj
  7883.             for i = 1,#players do playerId = players[i]
  7884.                 m_playerObj = getplayerobject(playerId)
  7885.                 if m_playerObj then
  7886.                     writebit(m_playerObj + 0x10, 0, 1)
  7887.                     sendresponse(getname(playerId) .. " is now a ghost!", executorPlayerId)
  7888.                     --privatesay(playerId, "You are now a ghost.")
  7889.                 else
  7890.                     sendresponse("You cannot ghost " .. getname(playerId) .. " because " .. getname(playerId) .. " is dead!", executorPlayerId)
  7891.                 end
  7892.             end
  7893.         end
  7894.     }
  7895. )
  7896.  
  7897. Commands.Create(
  7898.     "unghost",
  7899.     {
  7900.         aliases = {"ghostplayer"},
  7901.         help = [[ -- Unghost Player
  7902.         -- Syntax: %s [Player]
  7903.         -- Removes a player from Ghost Mode]]
  7904.     },
  7905.     {
  7906.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  7907.         func = function(executorPlayerId, players)
  7908.             local playerId, m_playerObj
  7909.             for i = 1,#players do playerId = players[i]
  7910.                 m_playerObj = getplayerobject(playerId)
  7911.                 if m_playerObj then
  7912.                     writebit(m_playerObj + 0x10, 0, 0)
  7913.                     sendresponse(getname(playerId) .. " is no longer a ghost!", executorPlayerId)
  7914.                 else
  7915.                     sendresponse("You cannot unghost " .. getname(playerId) .. " because " .. getname(playerId) .. " is dead!", executorPlayerId)
  7916.                 end
  7917.             end
  7918.         end
  7919.     }
  7920. )
  7921.  
  7922. local function updateObjectPhysics(objId, m_object)
  7923.     m_object = m_object or getobject(objId)
  7924.     if m_object then
  7925.         writebit(m_object + 0x10, 0, 0) -- Unset noCollisions bit.
  7926.         writebit(m_object + 0x10, 5, 0) -- Unset ignorePhysics.
  7927.     end
  7928. end
  7929.  
  7930. local function setVehicleUpright(objId, m_object)
  7931.     m_object = m_object or getobject(objId)
  7932.     if m_object then
  7933.         writefloat(m_object + 0x8A, 2.3 * (10 ^ -41))
  7934.         writefloat(m_object + 0x8C, 2.3 * (10 ^ -41))
  7935.         writefloat(m_object + 0x90, 2.3 * (10 ^ -41))
  7936.         writefloat(m_object + 0x94, 2.3 * (10 ^ -41))
  7937.         updateObjectPhysics(objId, m_object)
  7938.     end
  7939. end
  7940.  
  7941. Commands.Create(
  7942.     "upright",
  7943.     {
  7944.         aliases = {"rotate", "flip", "f", "setupright"},
  7945.         help = [[ -- Upright Vehicle
  7946.         -- Syntax: %s [Player]
  7947.         -- Places a player's vehicle in the upright position.]]
  7948.     },
  7949.     {
  7950.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  7951.         func = function(executorPlayerId, players)
  7952.             local playerId, playerVehiObjId, m_vehicleObj
  7953.             for i = 1,#players do playerId = players[i]
  7954.                 playerVehiObjId = getplayervehicleid(playerId)
  7955.                 m_vehicleObj = getobject(playerVehiObjId)
  7956.                 if m_vehicleObj then
  7957.                     setVehicleUpright(playerVehiObjId, m_vehicleObj)
  7958.                     sendresponse(getname(playerId) .. " has been rotated upright!", executorPlayerId)
  7959.                 else
  7960.                     sendresponse(getname(playerId) .. " is not in a vehicle!", executorPlayerId)
  7961.                 end
  7962.             end
  7963.         end
  7964.     },
  7965.     {
  7966.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  7967.         func = function(executorPlayerId, strBool)
  7968.             local newBool, response = ReturnScriptBooleanCheck("Antiflip", defaults.antiflip, strBool)
  7969.             if newBool ~= nil then
  7970.                 defaults.antiflip = newBool
  7971.             end
  7972.             sendresponse(response, executorPlayerId)
  7973.         end
  7974.     }
  7975. )
  7976.  
  7977. Commands.Create(
  7978.     "spawn",
  7979.     {
  7980.         aliases = {"spawnobj", "create", "createobject", "spawnobject", "objspawn"},
  7981.         help = [[-- Spawn
  7982.         -- Syntax: %s [Object] [Player] {Amount} {Respawn Time} {Recycle Boolean}
  7983.         -- Spawns specified object near the specified player]]
  7984.     },
  7985.     {
  7986.         arguments = {"Object", "Player", "Positive Number", "Whole Number", "Boolean", minArgs = 1, maxArgs = 5},
  7987.         func = function(executorPlayerId, object, players, amount, resp_time, bRecycle, spawn_type)
  7988.             amount = amount or 1
  7989.             bRecycle = not not bRecycle
  7990.  
  7991.             if spawn_type == "enter" and object.type ~= "vehi" then
  7992.                 sendresponse("Invalid Vehicle!", executorPlayerId)
  7993.                 return
  7994.             end
  7995.  
  7996.             if spawn_type == "give" and object.type ~= "weap" then
  7997.                 sendresponse("Invalid Weapon!", executorPlayerId)
  7998.                 return
  7999.             end
  8000.            
  8001.             if not object.mapId or object.mapId < 400 then
  8002.                 sendresponse("Object " .. object.name .. " could not be spawned at this time.", executorPlayerId)
  8003.                 return
  8004.             end
  8005.  
  8006.             local playerId, m_playerObj, playerObjId, objectId, x, y, z
  8007.             for i = 1,#players do playerId = players[i]
  8008.  
  8009.                 m_playerObj, playerObjId = getplayerobject(playerId)
  8010.                 if not m_playerObj then
  8011.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  8012.                     goto continue
  8013.                 end
  8014.  
  8015.                 -- Spawn the object right where they are looking (should work for vehicles too)
  8016.                 x,y,z = getobjectcoords(playerObjId)
  8017.                 x = x + readfloat(m_playerObj + 0x230) * 2
  8018.                 y = y + readfloat(m_playerObj + 0x234) * 2
  8019.  
  8020.                 -- Create the object
  8021.                 for i = 0,amount-1 do
  8022.                     --hprintf(tostring(object.mapId))
  8023.                     objectId = createobject(object.mapId, 0, resp_time, bRecycle, x, y + i, z+2 + i*2)
  8024.                 end
  8025.  
  8026.                 -- check if object was spawned correctly
  8027.                 if not objectId then
  8028.                     cmdreply[cmdreply()] = "Error spawning object: " .. object.name
  8029.                     goto continue
  8030.                 end
  8031.  
  8032.                 if spawn_type == "give" then
  8033.                     assignweapon(playerId, objectId)
  8034.                     cmdreply[cmdreply()] = object.name .. " given to " .. getname(playerId)
  8035.                 elseif spawn_type == "enter" then
  8036.                     local drones = PlayerClass[playerId].drones
  8037.                     drones[#drones+1] = objectId
  8038.                     entervehicle(playerId, objectId, 0)
  8039.                     cmdreply[cmdreply()] = getname(playerId) .. " was forced to enter a " .. object.name
  8040.                 else
  8041.                     cmdreply[cmdreply()] = object.name .. " spawned at " .. getname(playerId) .. "'s location."
  8042.                 end
  8043.  
  8044.                 ::continue::
  8045.             end
  8046.  
  8047.             sendresponse(cmdreply, executorPlayerId)
  8048.  
  8049.         end
  8050.     }
  8051. )
  8052.  
  8053. Commands.Create(
  8054.     "enter",
  8055.     {
  8056.         aliases = {"entervehicle", "vehicleeneter", "vehienter", "entervehi"},
  8057.         scrimBlock = true,
  8058.         help = [[-- Enter Vehicle
  8059.         -- Syntax: %s [Player1 or Vehicle] [Player2]
  8060.         -- Force specified player into specified vehicle
  8061.         -- Or will put player1 into player2's vehicle, provided halo will let them.
  8062.         -- You cannot enter a vehicle of an enemy (unless sv_multiteam_vehicles is enabled in Free-For-All GameTypes)]]
  8063.     },
  8064.     {
  8065.         arguments = {"Object", "Player", minArgs = 1, maxArgs = 2},
  8066.         func = function(executorPlayerId, object, players) Commands.spawn[1].func(executorPlayerId, object, players, nil, nil, nil, "enter") end
  8067.     },
  8068.     {
  8069.         arguments = {"Player", "Single Player", "Whole Number", minArgs = 3, maxArgs = 3},
  8070.         func = function(executorPlayerId, players, playerId2, seat)
  8071.  
  8072.             local m_vehicleObj, vehicleObjId = getplayervehicle(playerId2)
  8073.             if not m_vehicleObj then
  8074.                 sendresponse(getname(playerId2) .. " is not in a vehicle!", executorPlayerId)
  8075.                 return
  8076.             end
  8077.  
  8078.             local playerId
  8079.             for i = 1,#players do playerId = players[i]
  8080.                 entervehicle(playerId, vehicleObjId, seat)
  8081.                 sendresponse("Entering " .. getname(playerId) .. " into " .. getname(playerId2) .. "'s vehicle!", executorPlayerId)
  8082.             end
  8083.         end
  8084.     }
  8085. )
  8086.  
  8087. Commands.Create(
  8088.     "give",
  8089.     {
  8090.         aliases = {"giveweapon", "weapongive", "cheatgiveweapon"},
  8091.         scrimBlock = true,
  8092.         help = [[-- Give
  8093.         -- Syntax: %s [Object] [Player]
  8094.         -- Gives specified player the specified weapon]]
  8095.     },
  8096.     {
  8097.         arguments = {"Object", "Player", minArgs = 1, maxArgs = 2},
  8098.         func = function(executorPlayerId, object, players) Commands.spawn[1].func(executorPlayerId, object, players, nil, nil, nil, "give") end
  8099.     }
  8100. )
  8101.  
  8102. Commands.Create(
  8103.     "spammax",
  8104.     {
  8105.         aliases = {"smax", "maxspam"},
  8106.         help = [[-- SpamMax
  8107.         -- Syntax: %s {Value or Boolean}
  8108.         -- Determines how many messages a player can send before a player is muted.
  8109.         -- Wizard recommends leaving this at the default, but you're welcome to change it
  8110.         -- Setting this to false or 0 will disable Spam Protection.]]
  8111.     },
  8112.     {
  8113.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  8114.         func = function(executorPlayerId, boolean)
  8115.             if boolean == false and defaults.spam_max ~= false then
  8116.                 defaults.spam_max = 0
  8117.                 sendresponse("Spam protection is now disabled", executorPlayerId)
  8118.             elseif not boolean and defaults.spam_max == false then
  8119.                 sendresponse("Spam protection is already disabled", executorPlayerId)
  8120.             elseif boolean then
  8121.                 defaults.spam_max = 7
  8122.                 sendresponse("Spam protection is now on!", executorPlayerId)
  8123.             end
  8124.         end
  8125.     },
  8126.     {
  8127.         arguments = {"Number", minArgs = 0, maxArgs = 1},
  8128.         func = function(executorPlayerId, time)
  8129.             if time == -1 then
  8130.                 sendresponse("The Spam max is currently '" .. defaults.spam_max .. "'", executorPlayerId)
  8131.             else
  8132.                 defaults.spam_max = time
  8133.                 sendresponse("The Spam max is now " .. time, executorPlayerId)
  8134.             end
  8135.         end
  8136.     }
  8137. )
  8138.  
  8139. Commands.Create(
  8140.     "spamtimeout",
  8141.     {
  8142.         aliases = {"timeoutspam"},
  8143.         help = [[-- SpamTimeout
  8144.         -- Syntax: %s {Time}
  8145.         -- Changes the time you are muted for spamming]],
  8146.     },
  8147.     {
  8148.         arguments = {"Time", minArgs = 0, maxArgs = 1},
  8149.         func = function(executorPlayerId, time)
  8150.             if time == -1 then
  8151.                 sendresponse("Spam timeout is currently " .. timetoword(defaults.spam_timeout), executorPlayerId)
  8152.             else
  8153.                 defaults.spam_timeout = time
  8154.                 sendresponse("The Spam timeout is now " .. timetoword(time), executorPlayerId)
  8155.             end
  8156.         end
  8157.     }
  8158. )
  8159.  
  8160. Commands.Create(
  8161.     "specs",
  8162.     {
  8163.         aliases = {"serverspecs", "machineinfo"},
  8164.         help = [[-- Specs
  8165.         -- Syntax: %s
  8166.         -- Display the server specifications (like processor, RAM, model, etc)]]
  8167.     },
  8168.     {
  8169.         arguments = {minArgs = 0, maxArgs = 0},
  8170.         func = function(executorPlayerId)
  8171.             sendresponse("The server specs are: " .. readstring(addresses.computer_specs_address), executorPlayerId)
  8172.         end
  8173.     }
  8174. )
  8175.  
  8176. Commands.Create(
  8177.     "mapcyclebegin",
  8178.     {
  8179.         aliases = {"mcbegin", "startcycle", "cyclestart", "mc"},
  8180.         is_alias = true,
  8181.         help = [[-- Start MapCycle
  8182.         -- Syntax: %s
  8183.         -- Shortcut for sv_mapcycle_begin]]
  8184.     },
  8185.     {
  8186.         arguments = {minArgs = 0, maxArgs = 0},
  8187.         func = function(executorPlayerId)
  8188.             sendresponse(halo_svcmd("sv_mapcycle_begin", true), executorPlayerId)
  8189.         end
  8190.     }
  8191. )
  8192.  
  8193. Commands.Create(
  8194.     "ffa",
  8195.     {
  8196.         aliases = {"setffa"},
  8197.         help = [[-- Set FFA
  8198.         -- Syntax: %s
  8199.         -- Hard-forces the current slayer game to act like a FFA gametype.
  8200.         -- unknown how it works on other gametypes.]]
  8201.     },
  8202.     {
  8203.         arguments = {minArgs = 0, maxArgs = 0},
  8204.         func = function(executorPlayer)
  8205.             local m_player, client_network_struct, client_color
  8206.             local ce = 0x0
  8207.             if Game == "CE" then
  8208.                 ce = 0x40
  8209.             end
  8210.             for playerId = 0,15 do
  8211.                 m_player = getplayer(playerId)
  8212.                 if m_player then
  8213.                     writebyte(m_player + 0x20, playerId)
  8214.                     client_network_struct = addresses.network_struct + 0x1AA+ce + playerId * 0x20
  8215.                     client_color = readword(client_network_struct + 0x18)
  8216.                     --say(getname(playerId) .. " is trying to turn " .. tostring(player_colors[client_color]) .. " aka " .. tostring(client_color) .. " name: " .. tostring(readwidestring(client_network_struct, 12)))
  8217.                     setcolor(playerId, client_color)
  8218.                     cmdreply[cmdreply()] = "Setting player " .. tostring(getname(playerId)) .. " to team " .. playerId .. " with color " .. player_colors[client_color]
  8219.                 end
  8220.             end
  8221.             team_play = false
  8222.             sendresponse(cmdreply, executorPlayerId)
  8223.             sendresponse("FFA applied successfully", executorPlayerId)
  8224.         end
  8225.     }
  8226. )
  8227.  
  8228. Commands.Create(
  8229.     "teams",
  8230.     {
  8231.         aliases = {"setteams"},
  8232.         help = [[-- Set Teams
  8233.         -- Syntax: %s
  8234.         -- Hard-forces the current slayer game to act like a Team gametype.
  8235.         -- unknown how it works on other gametypes.]]
  8236.     },
  8237.     {
  8238.         arguments = {"Whole Number", minArgs = 0, maxArgs = 1},
  8239.         func = function(executorPlayer, amount)
  8240.             amount = amount or 2
  8241.             local m_player, team
  8242.             for playerId = 0,15 do
  8243.                 m_player = getplayer(playerId)
  8244.                 if m_player then
  8245.                     writebyte(m_player + 0x20, playerId%amount)
  8246.                     setcolor(playerId, playerId%amount+2)
  8247.                     team = getteam(playerId)
  8248.                     team_scores[team] = team_scores[team] + getscore(playerId)
  8249.                     cmdreply[cmdreply()] = "Setting player " .. tostring(getname(playerId)) .. " to team " .. (playerId%amount)
  8250.                 end
  8251.             end
  8252.             sendresponse(cmdreply, executorPlayerId)
  8253.             sendresponse("Teams applied successfully", executorPlayerId)
  8254.             team_play = true
  8255.         end
  8256.     }
  8257. )
  8258.  
  8259. --[[Commands.Create(
  8260.     "map",
  8261.     {
  8262.         aliases = {"m", "setmap", "choosemap"},
  8263.         is_alias = true,
  8264.         help = -- Set Map
  8265.         -- Syntax: %s [Map] [Gametype] {script1} {script2} {script3 etc..}
  8266.         -- Ends the current game, and starts a new game on selected map and gametype.
  8267.     },
  8268.     {
  8269.         arguments = {"Remaining Arguments", minArgs = 1, maxArgs = 10},
  8270.         func = function(executorPlayerId, mapargs)
  8271.             halo_svcmd("sv_mapcycle_timeout 1")
  8272.             halo_svcmd("sv_mapvote 0")
  8273.             sendresponse("sv_map " .. mapargs, executorPlayerId)
  8274.             sendresponse(halo_svcmd("sv_map " .. mapargs, true), executorPlayerId)
  8275.         end
  8276.     }
  8277. )]]
  8278.  
  8279. Commands.Create(
  8280.     "statusmore",
  8281.     {
  8282.         aliases = {"serverinfo", "sinfo"},
  8283.         help = [[-- Status
  8284.         -- Syntax: %s
  8285.         -- Shows a list of all the init.txt commands and their status.]]
  8286.     },
  8287.     {
  8288.         arguments = {minArgs = 0, maxArgs = 0},
  8289.         func = function(executorPlayerId)
  8290.             for key,value in next,defaults do
  8291.                 sendresponse(key .. ": " .. tostring(value), executorPlayerId)
  8292.             end
  8293.         end
  8294.     }
  8295. )
  8296.  
  8297. Commands.Create(
  8298.     "superban",
  8299.     {
  8300.         aliases = {"ultraban", "megaban"},
  8301.         help = [[-- Superban
  8302.         -- Syntax: %s [Player] {Time} {Reason}
  8303.         -- Bans a person via their Name, IP, and Hash
  8304.         -- Most likely overkill in most situations
  8305.         -- This command does the same as doing the following,
  8306.         -- where player is the player being banned, and time is a time if specified
  8307.         -- sv_ipban player time        sv_nameban player        sv_ban player time]],
  8308.         usesBanCounts = true,
  8309.     },
  8310.     {
  8311.         arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3},
  8312.         func = function(executorPlayerId, players, time, reason)
  8313.  
  8314.             local exname = getname(executorPlayerId)
  8315.             local playerId, name, b
  8316.             for i = 1,#players do playerId = players[i]
  8317.                 name = getname(playerId)
  8318.                 if not checkAdminBlockerAccess(executorPlayerId, playerId) then
  8319.                     sendresponse("You cannot use this command on " .. name, executorPlayerId)
  8320.                     privatesay(playerId, exname .. " attempted to SuperBan you!")
  8321.                     goto continue
  8322.                 end
  8323.  
  8324.                 reason = reason == "None Given" and "SuperBan" or reason
  8325.                 WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was Super-Banned by " .. exname .. " Reason: " .. reason)
  8326.                 say(name .. " was Super Banned from the server! Reason: " .. reason)
  8327.  
  8328.                 -- Create name ban.
  8329.                 local b = {}--TM.New()
  8330.                 b.name,b.type,b.reason = name,"name",reason
  8331.                 ban_table[#ban_table+1] = b
  8332.  
  8333.                 -- Add IP Ban
  8334.                 addBan(name, nil, getip(playerId) .. "/24", time, "ip", reason)
  8335.  
  8336.                 -- Execute Hash Ban
  8337.                 svcmd("sv_ban " .. resolveplayer(playerId) .. " " .. timetoword(time))
  8338.  
  8339.                 ::continue::
  8340.             end
  8341.         end
  8342.     }
  8343. )
  8344.  
  8345. Commands.Create(
  8346.     "suspend",
  8347.     {
  8348.         aliases = {"suspendplayer", "playersuspend", "suspendpl", "sleep", "cheatsuspendplayer"},
  8349.         scrimBlock = true,
  8350.         help = [[-- Suspend Player
  8351.         -- Syntax: %s [Player] {Time}
  8352.         -- Kills a player and prevents them from respawning.]]
  8353.     },
  8354.     {
  8355.         arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3},
  8356.         func = function(executorPlayerId, players, time, reason)
  8357.             reason = reason or "None Given"
  8358.             local playerId, player
  8359.             for i = 1,#players do playerId = players[i]
  8360.                 player = PlayerClass[playerId]
  8361.                 if player.suspended then
  8362.                     cmdreply[cmdreply()] = getname(playerId) .. " has already been suspended."
  8363.                     goto continue
  8364.                 end
  8365.  
  8366.                 local m_player = getplayer(playerId)
  8367.                 kill(playerId)
  8368.                 writedword(m_player + 0x2C, (time ~= -1 and time or 2880) * 30)
  8369.                 player.suspended = time ~= -1 and time or true
  8370.                 say(getname(playerId) .. " was suspended by an admin " .. (time ~= -1 and ("for " .. timetoword(time)) or "") .. " Reason: " .. reason)
  8371.  
  8372.                 ::continue::
  8373.             end
  8374.  
  8375.             sendresponse(cmdreply, executorPlayerId)
  8376.         end
  8377.     }
  8378. )
  8379.  
  8380. Commands.Create(
  8381.     "unsuspend",
  8382.     {
  8383.         aliases = {"unsuspendplayer", "unsuspendpl", "playerunsuspend"},
  8384.         help = [[-- Unsuspend Player
  8385.         -- Syntax: %s [Player]
  8386.         -- Unsuspends the specified player.]]
  8387.     },
  8388.     {
  8389.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  8390.         func = function(executorPlayerId, players)
  8391.  
  8392.             local playerId
  8393.             for i = 1,#players do playerId = players[i]
  8394.                 if not PlayerClass[playerId].suspended then
  8395.                     sendresponse(getname(playerId) .. " has never been suspended.", executorPlayerId)
  8396.                     goto continue
  8397.                 end
  8398.  
  8399.                 writedword(getplayer(playerId) + 0x2C, 0)
  8400.                 sendresponse(getname(playerId) .. " has been unsuspended", executorPlayerId)
  8401.  
  8402.                 ::continue::
  8403.             end
  8404.         end
  8405.     }
  8406. )
  8407.  
  8408. Commands.Create(
  8409.     "takeweapons",
  8410.     {
  8411.         aliases = {"removeweapons", "takeweaponspl", "takeweps", "takeweaps", "weaponsremove", "weapsremove", "weapstake"},
  8412.         scrimBlock = true,
  8413.         help = [[-- Take Weapons
  8414.         -- Syntax: %s [Player]
  8415.         -- Take all the weapons away from the specified player.]]
  8416.     },
  8417.     {
  8418.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  8419.         func = function(executorPlayerId, players)
  8420.  
  8421.             local playerId, m_playerObj, playerObjId
  8422.             for i = 1,#players do playerId = players[i]
  8423.                 PlayerClass[playerId].disarmed = true
  8424.                 m_playerObj, playerObjId = getplayerobject(playerId)
  8425.                 if m_playerObj then
  8426.                     for slot = 0,3 do
  8427.                         local m_weapon, weaponObjId = getplayerweapon(playerId, slot)
  8428.                         if m_weapon then
  8429.                             destroyobject(weaponObjId)
  8430.                         end
  8431.                     end
  8432.                 end
  8433.                 cmdreply[cmdreply()] = getname(playerId) .. " now cannot pickup weapons"
  8434.             end
  8435.             sendresponse(cmdreply, executorPlayerId)
  8436.         end
  8437.     }
  8438. )
  8439.  
  8440. Commands.Create(
  8441.     "teleportdel",
  8442.     {
  8443.         aliases = {"tdel", "delteleport", "dellocation", "locationdel", "tpdel", "rmtel", "teldel", "deltel"},
  8444.         help = [[--Delete Teleport Location
  8445.         -- Syntax: %s [Location]
  8446.         -- Deletes the specified teleport location
  8447.         -- Use 'sv_teleport_list' to get a list of teleport locations.]]
  8448.     },
  8449.     {
  8450.         arguments = {"String", "String", minArgs = 1, maxArgs = 2},
  8451.         func = function(executorPlayerId, locname, map)
  8452.             if map and not locations[map] then
  8453.                 sendresponse("Invalid Map!", command, executorPlayerId)
  8454.                 return
  8455.             end
  8456.  
  8457.             if map and locations[map][locname] then
  8458.                 locations[map][locname] = nil
  8459.                 sendresponse("Location '" .. locname .. "' on map '" .. map .. "' has been removed from the teleport locations list!", executorPlayerId)
  8460.             elseif Map and locations[Map][locname] then
  8461.                 locations[Map][locname] = nil
  8462.                 sendresponse("Location '" .. locname .. "' on map '" .. map .. "' has been removed from the teleport locations list!", executorPlayerId)
  8463.             else
  8464.                 sendresponse("'" .. locname .. "' is not a teleport location\nUse sv_teleport_list for current teleport locations.", executorPlayerId)
  8465.                 return
  8466.             end
  8467.             saveTeleportsToFile()
  8468.         end
  8469.     }
  8470. )
  8471.  
  8472. Commands.Create(
  8473.     "teleport",
  8474.     {
  8475.         aliases = {"tp", "t", "teletolocation", "tele", "teletoloc"},
  8476.         help = [[--Teleport Player
  8477.         -- Syntax: %s [Player] [Player2 or Location or X] {Y} {Z}
  8478.         -- Teleports the specified players' to a location.
  8479.         -- Use 'sv_teleport_list' to get a list of teleport locations.
  8480.         -- You can also use this command to teleport to a set of XYZ coordinates]]
  8481.     },
  8482.     {
  8483.         arguments = {"Player", "Single Player", minArgs = 2, maxArgs = 2},
  8484.         func = function(executorPlayerId, players, playerId2)
  8485.             local m_player2Obj, player2ObjId = getplayerobject(playerId2)
  8486.             if not m_player2Obj then
  8487.                 sendresponse("The player you are trying to teleport to is dead!", executorPlayerId)
  8488.                 return
  8489.             end
  8490.  
  8491.             local teletoname = getname(playerId2)
  8492.             local x,y,z = getobjectcoords(player2ObjId)
  8493.             local playerId, m_playerObj, playerObjId, m_vehicleObj, vehicleObjId
  8494.             for i = 1,#players do playerId = players[i]
  8495.  
  8496.                 m_playerObj, playerObjId = getplayerobject(playerId)
  8497.                 if not m_playerObj then
  8498.                     cmdreply[cmdreply()] = "The players you are trying to teleport are dead"
  8499.                     goto continue
  8500.                 end
  8501.  
  8502.                 m_vehicleObj, vehicleObjId = getplayervehicle(playerId)
  8503.                 movobjectcoords(m_vehicleObj and vehicleObjId or playerObjId, x, y, z+1)
  8504.                 cmdreply[cmdreply()] = getname(playerId) .. " was teleported to " .. teletoname
  8505.  
  8506.                 ::continue::
  8507.             end
  8508.  
  8509.             sendresponse(cmdreply, executorPlayerId)
  8510.         end
  8511.     },
  8512.     {
  8513.         arguments = {"Player", "String", minArgs = 2, maxArgs = 2},
  8514.         func = function(executorPlayerId, players, location)
  8515.             local thisLocation = locations[Map][location]
  8516.             if not thisLocation then
  8517.                 sendresponse("Location '" .. location .. "' doesn't exist on this map!", executorPlayerId)
  8518.                 return
  8519.             end
  8520.  
  8521.             -- A player can never exist unless the game is started on a map.
  8522.             local x,y,z = thisLocation[1], thisLocation[2], thisLocation[3]
  8523.             local playerId, m_playerObj, playerObjId, m_vehicleObj, vehicleObjId
  8524.             for i = 1,#players do playerId = players[i]
  8525.  
  8526.                 m_playerObj, playerObjId = getplayerobject(playerId)
  8527.                 if not m_playerObj then
  8528.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead and cannot be teleported."
  8529.                     goto continue
  8530.                 end
  8531.  
  8532.                 m_vehicleObj, vehicleObjId = getplayervehicle(playerId)
  8533.                 movobjectcoords(m_vehicleObj and vehicleObjId or playerObjId, x, y, z+1)
  8534.                 cmdreply[cmdreply()] = getname(playerId) .. " was teleported to " .. location
  8535.  
  8536.                 ::continue::
  8537.             end
  8538.  
  8539.             sendresponse(cmdreply, executorPlayerId)
  8540.         end
  8541.     },
  8542.     {
  8543.         arguments = {"Player", "Number", "Number", "Number", minArgs = 4, maxArgs = 4},
  8544.         func = function(executorPlayerId, players, x, y, z)
  8545.             local playerId, m_playerObj, playerObjId, m_vehicleObj, vehicleObjId
  8546.             for i = 1,#players do playerId = players[i]
  8547.  
  8548.                 m_playerObj, playerObjId = getplayerobject(playerId)
  8549.                 if not m_playerObj then
  8550.                     cmdreply[cmdreply()] = "The players you are trying to teleport are dead"
  8551.                     goto continue
  8552.                 end
  8553.  
  8554.                 m_vehicleObj, vehicleObjId = getplayervehicle(playerId)
  8555.                 movobjectcoords(m_vehicleObj and vehicleObjId or playerObjId, x, y, z+1)
  8556.                 cmdreply[cmdreply()] = getname(playerId) .. " was teleported to " .. teletoname
  8557.  
  8558.                 ::continue::
  8559.             end
  8560.  
  8561.             sendresponse(cmdreply, executorPlayerId)
  8562.         end
  8563.     }
  8564. )
  8565.  
  8566. Commands.Create(
  8567.     "textban",
  8568.     {
  8569.         aliases = {"mute", "muteplayer", "textbanplayer", "tban", "chatban", "playermute"},
  8570.         help = [[-- Text Ban
  8571.         -- Syntax: %s [Player] {Time}]],
  8572.     },
  8573.     {
  8574.         arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3},
  8575.         func = function(executorPlayerId, players, time, reason)
  8576.  
  8577.             local exname = getname(executorPlayerId)
  8578.             local playerId, name, player
  8579.             for i = 1,#players do playerId = players[i]
  8580.  
  8581.                 player = PlayerClass[playerId]
  8582.                 if PlayerClass[playerId].admin_entry then
  8583.                     cmdreply[cmdreply()] = "Admins cannot be banned from the chat!"
  8584.                 elseif player.muted then
  8585.                     cmdreply[cmdreply()] = getname(playerId) .. " is already textbanned!"
  8586.                 else
  8587.                     name = getname(playerId)
  8588.  
  8589.                     player.muted = true
  8590.                     addBan(name, gethash(playerId), getip(playerId) .. "/24", time, "chat", reason)
  8591.  
  8592.                     WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was text banned by " .. exname .. " Reason: " .. reason)
  8593.                     say(name .. " was text banned from the server by an admin! Reason: " .. reason)
  8594.                     cmdreply[cmdreply()] = name .. " has been banned from the chat " .. ((time == -1 and "indefinitely") or ("for " .. timetoword(time)))
  8595.                 end
  8596.             end
  8597.  
  8598.             sendresponse(cmdreply, executorPlayerId)
  8599.         end
  8600.     }
  8601. )
  8602.  
  8603. Commands.Create(
  8604.     "timecur",
  8605.     {
  8606.         aliases = {"curtime"},
  8607.         scrimBlock = true,
  8608.         help = [[-- Current Time
  8609.         -- Syntax: %s {Time}]]
  8610.     },
  8611.     {
  8612.         arguments = {"Time", minArgs = 0, maxArgs = 1},
  8613.         func = function(executorPlayerId, time)
  8614.             if time == -1 then
  8615.                 local time_passed = readdword(readdword(addresses.gameinfo_header) + 0xC) - (time_passed_value or 0)
  8616.                 local timelimit = timelimit_set_value or readdword(addresses.gametype_base + 0x78)
  8617.                 local time_left = (timelimit - time_passed) / 30
  8618.                 sendresponse("Current Timelimit is " .. timetoword(timelimit) .. ". Time remaining: " .. timetoword(time_left), executorPlayerId)
  8619.             else
  8620.                 timelimit_set_value = time
  8621.                 time_passed_value = readdword(readdword(addresses.gameinfo_header) + 0xC)
  8622.                 writedword(addresses.gametype_base + 0x78, time_passed_value + 30*time) -- Can't set time_passed to 0 because it causes weird stuff to happen.
  8623.                 sendresponse("Timelimit set to " .. timetoword(time), executorPlayerId)
  8624.             end
  8625.         end
  8626.     }
  8627. )
  8628.  
  8629. Commands.Create(
  8630.     "unbos",
  8631.     {
  8632.         aliases = {"removebos", "bosremove", "unbanbos", "bosunban"},
  8633.         help = [[-- Remove from Ban on Sight List
  8634.         -- Syntax: %s [ID]
  8635.         -- Remove selected index off of the ban on sight list]]
  8636.     },
  8637.     {
  8638.         arguments = {"Positive Number", minArgs = 1, maxArgs = 1},
  8639.         func = function(executorPlayerId, ID)
  8640.             local entry = bos_table[ID]
  8641.             if not entry then
  8642.                 sendresponse("Invalid Entry", executorPlayerId)
  8643.             else
  8644.                 sendresponse("Removing " .. entry.name .. " - " .. entry.hash .. " from BoS.", executorPlayerId)
  8645.                 remove(bos_table, ID)
  8646.             end
  8647.         end
  8648.     }
  8649. )
  8650.  
  8651. Commands.Create(
  8652.     "ungod",
  8653.     {
  8654.         aliases = {"unsetgod", "removegod", "godunset", "godremove", "cheatunsetgod", "cheatremovegod", "cheatremovegodmode"},
  8655.         help = [[-- Ungod
  8656.         -- Syntax: %s [Player]
  8657.         -- Ungods the specified player.]]
  8658.     },
  8659.     {
  8660.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  8661.         func = function(executorPlayerId, players)
  8662.             local playerId, player
  8663.             for i = 1,#players do playerId = players[i]
  8664.                 local m_playerObj, playerObjId = getplayerobject(playerId)
  8665.                 if m_playerObj then
  8666.                     player = PlayerClass[playerId]
  8667.                     if player.godmode then
  8668.                         player.godmode = false
  8669.                         sendresponse(getname(playerId) .. " is no longer in godmode", executorPlayerId)
  8670.                     else
  8671.                         sendresponse(getname(playerId) .. " is not in godmode", executorPlayerId)
  8672.                     end
  8673.                 else
  8674.                     sendresponse(getname(playerId) .. " is dead", executorPlayerId)
  8675.                 end
  8676.             end
  8677.         end
  8678.     }
  8679. )
  8680.  
  8681. Commands.Create(
  8682.     "cheatunhax",
  8683.     {
  8684.         aliases = {"unhax"},
  8685.         help = [[-- Cheat Unhax
  8686.         -- Syntax: %s [Player]
  8687.         -- Unhaxs the specified player.]]
  8688.     },
  8689.     {
  8690.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  8691.         func = function(executorPlayerId, players)
  8692.             local playerId, m_player
  8693.             for i = 1,#players do playerId = players[i]
  8694.                 m_player = getplayer(playerId)
  8695.                 setscore(playerId, 0)
  8696.                 writeshort(m_player + 0x9C, 0)
  8697.                 writeshort(m_player + 0xA4, 0)
  8698.                 writeshort(m_player + 0xAC, 0)
  8699.                 writeshort(m_player + 0xAE, 0)
  8700.                 writeshort(m_player + 0xB0, 0)
  8701.                 sendresponse(getname(playerId) .. " has been unhaxed", executorPlayerId)
  8702.             end
  8703.         end
  8704.     }
  8705. )
  8706.  
  8707. Commands.Create(
  8708.     "unhide",
  8709.     {
  8710.         aliases = {"removehide", "cheatunhide", "cheatunhideplayer"},
  8711.         help = [[-- Unhide
  8712.         -- Syntax: %s [Player]
  8713.         -- Unhides the specified player.]]
  8714.     },
  8715.     {
  8716.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  8717.         func = function(executorPlayerId, players)
  8718.  
  8719.             local playerId, player
  8720.             for i = 1,#players do playerId = players[i]
  8721.                 player = PlayerClass[playerId]
  8722.                 if player.hidden then
  8723.                     cmdreply[cmdreply()] = getname(playerId) .. " is no longer hidden."
  8724.                     player.hidden = false
  8725.                 else
  8726.                     cmdreply[cmdreply()] = getname(playerId) .. " was never hidden."
  8727.                 end
  8728.             end
  8729.             sendresponse(cmdreply, executorPlayerId)
  8730.         end
  8731.     }
  8732. )
  8733.  
  8734. Commands.Create(
  8735.     "uninvis",
  8736.     {
  8737.         aliases = {"uncamo", "removeinvis", "removecamo", "cheatuncamoplayer", "cheatuninvis", "cheatremovecamo", "cheatuncamo", "cheatuncamoplayer"},
  8738.         help = [[-- Uninvis
  8739.         -- Syntax: %s [Player]
  8740.         -- Removes camouflage from the specified player.]]
  8741.     },
  8742.     {
  8743.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  8744.         func = function(executorPlayerId, players)
  8745.  
  8746.             local playerId, player
  8747.             for i = 1,#players do playerId = players[i]
  8748.                 player = PlayerClass[playerId]
  8749.                 if not player.invisible then
  8750.                     cmdreply[cmdreply()] = getname(playerId) .. " is not invisible"
  8751.                 else
  8752.                     player.invisible = false
  8753.                     cmdreply[cmdreply()] = getname(playerId) .. " is no longer invisible"
  8754.                 end
  8755.             end
  8756.             sendresponse(cmdreply, executorPlayerId)
  8757.         end
  8758.     }
  8759. )
  8760.  
  8761. Commands.Create(
  8762.     "unmute",
  8763.     {
  8764.         aliases = {"removemute"},
  8765.         help = [[-- Unmute
  8766.         -- Syntax: %s [Player]
  8767.         -- Unmutes the specified player.
  8768.         -- Will also unban their chat ban from the banlist]]
  8769.     },
  8770.     {
  8771.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  8772.         func = function(executorPlayerId, players)
  8773.             local playerId, player, ban_entry
  8774.             for i = 1,#players do playerId = players[i]
  8775.                 player = PlayerClass[playerId]
  8776.                 if player.muted then
  8777.                     player.muted = false
  8778.  
  8779.                     -- remove them from the textbanlist
  8780.                     ban_entry = findBanlistEntry(nil, gethash(playerId), getip(playerId), "chat")
  8781.                     if ban_entry then
  8782.                         sendresponse(getname(playerId) .. " has been unmuted", executorPlayerId)
  8783.                         ban_entry.time = os.time()
  8784.                         updateBanFiles()
  8785.                         return
  8786.                     end
  8787.  
  8788.                     if player.spamcounter < 0 then
  8789.                         sendresponse(getname(playerId) .. " has been forgiven for spamming.", executorPlayerId)
  8790.                         player.spamcounter = 0
  8791.                     else
  8792.                         sendresponse(getname(playerId) .. " is not found in any ban entries somehow???", executorPlayerId)
  8793.                     end
  8794.                 else
  8795.                     sendresponse(getname(playerId) .. " has not been muted.", executorPlayerId)
  8796.                 end
  8797.             end
  8798.         end
  8799.     }
  8800. )
  8801.  
  8802. Commands.Create(
  8803.     "viewadmins",
  8804.     {
  8805.         aliases = {"curadmins", "adminscur"},
  8806.         help = [[-- Viewadmins
  8807.         -- Syntax: %s
  8808.         -- Shows Current Admins in the Server]]
  8809.     },
  8810.     {
  8811.         arguments = {minArgs = 0, maxArgs = 0},
  8812.         func = function(executorPlayerId)
  8813.             sendresponse("The current admins in the server are listed below:", executorPlayerId)
  8814.             cmdreply.header = "[Level | Nickname | Name | Admin Type]"
  8815.             cmdreply.align = true
  8816.             cmdreply.delim = "|"
  8817.             local admin_entry
  8818.             for playerId = 0,15 do
  8819.                 if getplayer(playerId) then
  8820.                     admin_entry = PlayerClass[playerId].admin_entry
  8821.                     if admin_entry then
  8822.                         cmdreply[cmdreply()] = format("%s | %s | %s | %s", admin_entry.level, admin_entry.name, getname(playerId), (admin_entry.type == "ip" and "IP Admin" or "Hash Admin"))
  8823.                     end
  8824.                 end
  8825.             end
  8826.             sendresponse(cmdreply, executorPlayerId)
  8827.         end
  8828.     }
  8829. )
  8830.  
  8831. Commands.Create(
  8832.     "votekickaction",
  8833.     {
  8834.         aliases = {"vkaction"},
  8835.         help = [[-- Vote Kick Action
  8836.         -- Syntax: %s [Kick/Ban]
  8837.         -- Allows you to either ban or kick the player that has been voted out.]]
  8838.     },
  8839.     {
  8840.         arguments = {"String", minArgs = 0, maxArgs = 1},
  8841.         func = function(executorPlayerId, action)
  8842.             if not action then
  8843.                 sendresponse("The current action for people who are votekicked is '" .. defaults.votekick_action .. "'", executorPlayerId)
  8844.                 sendresponse("Valid actions are 'kick' and 'ban'", executorPlayerId)
  8845.             elseif action == "kick" or action == "ban" then
  8846.                 sendresponse("The current VoteKick action has been changed to '" .. action .. "'", executorPlayerId)
  8847.                 defaults.votekick_action = action
  8848.             else
  8849.                 sendresponse("That is not a valid action", executorPlayerId)
  8850.             end
  8851.         end
  8852.     }
  8853. )
  8854.  
  8855. Commands.Create(
  8856.     "votekicktimeout",
  8857.     {
  8858.         help = [[-- VoteKick Timeout
  8859.         -- Syntax: %s [Time]
  8860.         -- The amount of time between each votekick.]]
  8861.     },
  8862.     {
  8863.         arguments = {"Time", minArgs = 0, maxArgs = 1},
  8864.         func = function(executorPlayerId, time)
  8865.             if time == -1 then
  8866.                 sendresponse("VoteKick Timeout is currently " .. timetoword(defaults.votekick_timeout), executorPlayerId)
  8867.             else
  8868.                 sendresponse("VoteKick Timeout has been set to " .. timetoword(time), executorPlayerId)
  8869.                 defaults.votekick_timeout = time
  8870.             end
  8871.         end
  8872.     }
  8873. )
  8874.  
  8875. Commands.Create(
  8876.     "votekickrequired",
  8877.     {
  8878.         aliases = {"votekickneeded"},
  8879.         help = [[-- Vote Kick Needed
  8880.         -- Syntax: %s [Percent]
  8881.         -- Allow you to change the number of votes needed for VoteKick to kick the player.]]
  8882.     },
  8883.     {
  8884.         arguments = {"Percent", minArgs = 0, maxArgs = 1},
  8885.         func = function(executorPlayerId, percent)
  8886.             if not percent then
  8887.                 sendresponse(defaults.votekick_required .. "% votes required for VoteKick", executorPlayerId)
  8888.             else
  8889.                 sendresponse("Votes required for VoteKick has been set to " .. percent .. "%", executorPlayerId)
  8890.                 defaults.votekick_required = percent
  8891.             end
  8892.         end
  8893.     }
  8894. )
  8895.  
  8896. function GetRequiredVersion()
  8897.     return 200
  8898. end
  8899.  
  8900. function OnScriptLoad(process, game, persistent)
  8901.    
  8902.     -- Sort the commands so they're alphabetical when someone does /list or sv_commands
  8903.     table.sort(Commands,
  8904.         function(word1, word2)
  8905.             local myChar1, myChar2
  8906.             local word1Len = #word1
  8907.             local word2Len = #word2
  8908.             local longestLen = word1Len >= word2Len and word1Len or word2Len
  8909.             local chartobyte = string.byte
  8910.             for i = 1,longestLen do
  8911.                 myChar1 = i <= word1Len and chartobyte(sub(word1, i, i)) or 0
  8912.                 myChar2 = i <= word2Len and chartobyte(sub(word2, i, i)) or 0
  8913.                 if myChar1 < myChar2 then
  8914.                     return true
  8915.                 elseif myChar1 ~= myChar2 then
  8916.                     return false
  8917.                 end
  8918.             end
  8919.             return false
  8920.         end
  8921.     )
  8922.     processid = process
  8923.     Persistent = persistent
  8924.     profilepath = getprofilepath()
  8925.     Game = game
  8926.     GetGameAddresses(game)
  8927.     if _SERVERAPP ~= "Sapp" then
  8928.         writeword(addresses.servername_patch, 0x9090)
  8929.         writeword(addresses.devmode_patch1, 0x9090)
  8930.         writeword(addresses.devmode_patch2, 0x9090)
  8931.         --writebyte(addresses.color_patch, 0xEB)
  8932.     end
  8933.  
  8934.     -- This bit of code fixes the stupidness that is sv_public.
  8935.     -- Usually if sv_public is disabled, no one can join the server (or weird things start happening)
  8936.     -- This bit of code will fix that.
  8937.     --[[local public_status = readdword(addresses.public_value_address) == 0x10101
  8938.     if not public_status then
  8939.         writedword(addresses.public_value_address, 0x101)
  8940.         writestring(addresses.version_address, "01.23.45.6789") -- write a bad version string so it will never show in the lobby. (only if sv_public is false)
  8941.     end]]
  8942.  
  8943.     local file = io.open("changelog_" .. script_version .. ".txt")
  8944.     if file then
  8945.         changelog = true
  8946.         file:close()
  8947.     else
  8948.         WriteChangeLog()
  8949.     end
  8950.    
  8951.     registertimer(0, "turnAdminCheckOff")
  8952.  
  8953.     -- don't worry, this isn't malicious code, this simply removes all of halo's bans so I can override them with my system (it's much better, I promise)
  8954.     -- No bans will be deleted, anything in banned.txt will be formatted exactly the same as it was before.
  8955.     writedword(addresses.banlist_header, 0) -- writing the number of bans to 0 seems to remove all bans, sweet
  8956.    
  8957.     file = io.open(defaults.sharedhash_file .. ".txt")
  8958.     if file then
  8959.         local iter = 0
  8960.         for line in file:lines() do
  8961.             if match(line, "%g%g%g+") then
  8962.                 --reset our sharedhashes table and only load stuff in the sharedhashes file.
  8963.                 if iter == 0 then -- only reset the table during the first iteration
  8964.                     sharedhashes = {}
  8965.                 end
  8966.                 iter = iter + 1
  8967.                 sharedhashes[iter] = line
  8968.             end
  8969.         end
  8970.         file:close()
  8971.         if iter == 0 then
  8972.             file = io.open(defaults.sharedhash_file .. ".txt", "a")
  8973.             if file then
  8974.                 for hash,index in next,sharedhashes do
  8975.                     file:write(hash .. "\n")
  8976.                 end
  8977.             end
  8978.             file:close()
  8979.         end
  8980.     else
  8981.         file = io.open(defaults.sharedhash_file .. ".txt", "w")
  8982.         if file then
  8983.             for hash,index in next,sharedhashes do
  8984.                 file:write(hash .. "\n")
  8985.             end
  8986.         end
  8987.         file:close()
  8988.     end
  8989.  
  8990.     local args = defaults.remote_bansystem
  8991.     if not args or args.mode ~= 2 then
  8992.         loadBanFile(profilepath .. "ipbans.txt", "ip") -- load sapp ip bans
  8993.         loadBanFile(profilepath .. "ipbanlist.txt", "ip") -- load ipbanlist file for backwards compatibility
  8994.         loadBanFile(profilepath .. "iprangebanlist.txt", "ip") -- load iprangebanlist file for backwards compatibility
  8995.         loadBanFile(profilepath .. "textbanlist.txt", "chat") -- load textbanlist file for backwards compatibility
  8996.         loadBanFile(profilepath .. "namebans.txt", "name") -- load textbanlist file for backwards compatibility
  8997.  
  8998.         loadBanFile(profilepath .. defaults.banlist_file .. ".txt")
  8999.  
  9000.         updateBanFiles()
  9001.  
  9002.         -- we're not going to remove the files, let's just rename them so we don't upset anyone.
  9003.         local timestamp = os.date "%Y_%m_%d_%H_%M_%S"
  9004.         os.rename(profilepath .. "ipbans.txt", profilepath .. "old_ipbans_" .. timestamp .. ".txt")
  9005.         os.rename(profilepath .. "ipbanlist.txt", profilepath .. "old_ipbanlist_" .. timestamp .. ".txt")
  9006.         os.rename(profilepath .. "iprangebanlist.txt", profilepath .. "old_iprangebanlist_" .. timestamp .. ".txt")
  9007.         os.rename(profilepath .. "textbanlist.txt", profilepath .. "old_textbanlist_" .. timestamp .. ".txt")
  9008.         os.rename(profilepath .. "namebans.txt", profilepath .. "old_namebans_" .. timestamp .. ".txt")
  9009.     end
  9010.  
  9011.     loadAllAdminFiles()
  9012.  
  9013.     -- We can now archive the other admin files without worrying about losing the data.
  9014.     os.rename(profilepath .. "ipadmins.txt", profilepath .. "archived_ipadmins.txt")
  9015.     os.rename(profilepath .. "admin.txt", profilepath .. "archived_admin.txt")
  9016.     file = io.open(profilepath .. "access.ini")
  9017.     if file then
  9018.         local commands, lvlMatch, level, accessEntry, thisCommand, fullaccess
  9019.         local iter = 0
  9020.         local allcommands = concat(Commands, ", ")
  9021.         for line in file:lines() do
  9022.             -- ignore blank lines
  9023.             if match(line, "%g%g%g+") then
  9024.                 lvlMatch = tonumber(match(line, "%[([0-9]+)%]"))
  9025.                 commands = match(line, "data=(.+)")
  9026.                 commands = commands == "-1" and allcommands or commands
  9027.                 fullaccess = commands == allcommands
  9028.                 if iter % 2 == 0 and lvlMatch then
  9029.                     level = lvlMatch
  9030.                 elseif iter % 2 ~= 0 and commands then
  9031.                     -- String full of commands this access level can execute.
  9032.                     access_entry = {commands = commands, allcommands = fullaccess}
  9033.                     -- We want to set each access_table[level][command] to equal the actual true name of the command (e.g. Display Admins List).
  9034.                     -- Doing this will allow command aliases like sv_rcon_add, /rcon_add, add_rcon etc to work without using AccessMerging anymore (yuck)
  9035.  
  9036.                     commands = tokenizestring(commands, ",")
  9037.                     for i = 1,#commands do
  9038.                         thisCommandName = getvalidformat(commands[i])
  9039.                         thisCommandEntry = Commands[thisCommandName]
  9040.                         if not thisCommandEntry then
  9041.                             thisCommandName = commands[i]
  9042.                             thisCommandEntry = thisCommandName
  9043.                         end
  9044.                         commandIndex = #access_entry+1
  9045.                         access_entry[thisCommandEntry] = commandIndex
  9046.                         access_entry[commandIndex] = thisCommandName
  9047.                     end
  9048.  
  9049.                     table.sort(access_entry, alphabetize)
  9050.                     access_table[level] = access_entry
  9051.                 else
  9052.                     error(profilepath .. "access.ini is formatted incorrectly! Line: " .. line)
  9053.                 end
  9054.                 iter = iter + 1
  9055.             end
  9056.         end
  9057.         file:close()
  9058.     end
  9059.  
  9060.  
  9061.  
  9062.     file = io.open(profilepath .. "data\\bos.data")
  9063.     if file then
  9064.         local name, hash, ip
  9065.         for line in file:lines() do
  9066.             name, hash, ip = match(line, "^(.-),(%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x+),(%g+)$")
  9067.             ip = validate_ipv4(ip)
  9068.             bos_table[#bos_table+1] = {name = name, hash = hash, ip = ip}
  9069.         end
  9070.         file:close()
  9071.     end
  9072.  
  9073.     file = io.open(profilepath .. "data\\locations.txt")
  9074.     if file then
  9075.         local map, locname, x, y, z
  9076.         for line in file:lines() do
  9077.             map,locname,x,y,z = match(line, "^(%g+),(%g+),([%d%.%-]+),([%d%.%-]+),([%d%.%-]+)")
  9078.             x,y,z = tonumber(x), tonumber(y), tonumber(z)
  9079.             if locname and x and y and z then
  9080.                 locations[map] = locations[map] or {}--TM.New()
  9081.                 locations[map][locname] = {x, y, z}
  9082.             end
  9083.         end
  9084.         file:close()
  9085.     end
  9086.    
  9087.     -- Load the remote banlist.
  9088.     local args = defaults.remote_bansystem
  9089.     if args then
  9090.         reloadRemoteBanlist()
  9091.     end
  9092.    
  9093.     local gameinfo_base = readdword(addresses.gameinfo_header)
  9094.     -- Code for script reload.
  9095.     -- If this script loads as a persistent script (in the persistent folder) this will sometimes be nil/0.
  9096.     if gameinfo_base and gameinfo_base ~= 0 then
  9097.         local gameinfo_time_passed = readdword(gameinfo_base + 0xC)
  9098.         -- Seems to not work when starting at 0.
  9099.         if gameinfo_time_passed >= 30 then
  9100.             gameend = false
  9101.             Map = readstring(addresses.map_name_address2)
  9102.             locations[Map] = locations[Map] or {}
  9103.             team_play = readbyte(addresses.gametype_base + 0x34) == 1
  9104.             gametype = readbyte(addresses.gametype_base + 0x30)
  9105.             starting_equipment = readbit(addresses.gametype_base + 0x38, 2) and "Generic" or "Custom"
  9106.             LoadTags()
  9107.             for playerId = 0,15 do
  9108.                 if not getplayer(playerId) then
  9109.                     goto continue
  9110.                 end
  9111.  
  9112.                 -- Increase our total player counter.
  9113.                 cur_players = cur_players + 1
  9114.                
  9115.                 -- Add player in the script's tables.
  9116.                 PlayerClass:Initialize(playerId)
  9117.  
  9118.                 -- Remove the player from the server if they are on the banlist.
  9119.                 punishIfOnBanlist(playerId)
  9120.  
  9121.                 ::continue::
  9122.             end
  9123.         end
  9124.     end
  9125.    
  9126.     -- override slayer's score system by setting the scorelimit to a high number and swapping the map in onplayerkill.
  9127.     if gametype == 2 then
  9128.         team_scores[0] = getteamscore(0)
  9129.         team_scores[1] = getteamscore(1)
  9130.         --writebyte(addresses.slayer_score_patch, 0xEB)
  9131.         -- how tf do i set slayer scorelimit: figured it out writebyte(addresses.gametype_base + 0x58, score)
  9132.     end
  9133.    
  9134.    
  9135.     hprintf "-------------------------------------------------------------------------------"
  9136.     hprintf("   >> Command Script Version: " .. script_version .. " <<")
  9137.     if not changelog then
  9138.     hprintf("   >> [!] Change log Version " .. script_version .. " is being written [!] <<")
  9139.     end
  9140.     hprintf "   >> Credit: Creator Wizard, Updater Aelite_Prime <<"
  9141.     hprintf "   >> Xfire: th3w1zard3 <<"
  9142.     hprintf "   >> Support: http://phasor.proboards.com/ <<"
  9143.     hprintf "-------------------------------------------------------------------------------"
  9144.    
  9145.     file = io.open("temp_" .. processid .. ".tmp") or io.open "defaults.txt"
  9146.    
  9147.     local temp_commands_executed = {} --TM.New()
  9148.     local words
  9149.    
  9150.     -- if gameinfo_base is nil, then this script is being loaded from the persistent folder, so we don't need to do anything (loading from the init now :D)
  9151.     if gameinfo_base and file then
  9152.         for line in file:lines() do
  9153.             if match(line, "[%w_]+%s+[%w%p]+") then
  9154.                 -- used to call svcmd but I hate it using halo's servercommand call
  9155.                 -- no need when I only want it to execute scripted commands anyway.
  9156.                 OnServerCommand(nil, line)
  9157.             end
  9158.             words = tokenizecmdstring(line)
  9159.             temp_commands_executed[#temp_commands_executed+1] = words[1]
  9160.         end
  9161.         file:close()
  9162.         if filename == "temp_" .. processid .. ".tmp" then
  9163.             os.remove(filename)
  9164.         end
  9165.     elseif file then
  9166.         file:close()
  9167.     else
  9168.         file = io.open("defaults.txt", "a")
  9169.         hprintf "       >> Defaults.txt not found. File will be created..."
  9170.         for command,value in next,defaults do
  9171.             file:write("sv_" .. command .. " " .. tostring(value) .. "\n")
  9172.         end
  9173.        
  9174.         file:close()
  9175.     end
  9176.  
  9177.     maintimer = registertimer(33, "MainTimer")
  9178.    
  9179.     collectgarbage()
  9180. end
  9181.  
  9182. function turnAdminCheckOff(id, count)
  9183.     halo_svcmd "sv_admin_check false" -- stupid phasor :(
  9184.  
  9185.     -- Load Maplist and Gamelist.
  9186.     --[[local gmatch = string.gmatch
  9187.     for map in gmatch(concat(halo_svcmd("sv_maplist", true)), "%w+") do
  9188.         valid_maps[map] = true
  9189.     end
  9190.     for gametype in gmatch(concat(halo_svcmd("sv_gamelist", true)), "%w+") do
  9191.         valid_gametypes[gametype] = true
  9192.     end--]]
  9193.  
  9194.     return false
  9195. end
  9196.  
  9197. function OnScriptUnload()
  9198.     if defaults.remotecontrol then
  9199.         for i = 1,#clients do
  9200.             clients[i].socket:close()
  9201.         end
  9202.         server:close()
  9203.         server = nil
  9204.     end
  9205.    
  9206.     local writetbl = {}--TM.New()
  9207.  
  9208.     local file = assert(io.open(profilepath .. "data\\bos.data", "w"))
  9209.     local bos_entry
  9210.     for id = 1,#bos_table do bos_entry = bos_table[id]
  9211.         writetbl[#writetbl+1] = bos_entry.name .. "," .. bos_entry.hash .. "," .. bos_entry.ip
  9212.     end
  9213.     file:write(concat(writetbl, "\n"))
  9214.     file:close()
  9215.  
  9216.     -- Continue to write these onscriptunload because they aren't as important as admins/bans and they're written to a lot more.
  9217.     --[[file = assert(io.open(profilepath .. "uniques.txt", "w"))
  9218.     start = #writetbl+1
  9219.     for k,unique_entry in next,unique_table do
  9220.         if k ~= "total" then
  9221.             writetbl[#writetbl+1] = k .. "," .. unique_entry.joincount .. "," .. concat(unique_entry.names, ",")
  9222.         end
  9223.     end
  9224.     writetbl[#writetbl+1] = unique_table.total
  9225.     file:write(concat(writetbl, "\n", start))
  9226.     file:close()--]]
  9227.  
  9228.     -- Write all script game variables to temp file
  9229.     file = assert(io.open("temp_" .. processid .. ".tmp", "w"))
  9230.     start = #writetbl+1
  9231.     for command,value in next,defaults do
  9232.         if command == "remote_bansystem" and type(value) == "table" then
  9233.             writetbl[#writetbl+1] = command .. " " .. value.host .. " " .. value.phpscript .. " " .. value.banfile .. " " .. value.mode .. " " .. value.port
  9234.         else
  9235.             writetbl[#writetbl+1] = command .. " " .. tostring(value)
  9236.         end
  9237.     end
  9238.  
  9239.     for rcon,level in next,rcon_passwords do
  9240.         writetbl[#writetbl+1] = "sv_rcon_add " .. rcon .. " " .. level
  9241.     end
  9242.     file:write(concat(writetbl, "\n", start))
  9243.     file:close()
  9244.    
  9245.     if gametype == 2 then
  9246.         --writebyte(addresses.slayer_score_patch, 0x74)
  9247.         -- how tf do i set slayer scorelimit: figured it out writebyte(addresses.gametype_base + 0x58, score)
  9248.     end
  9249.  
  9250.     -- Clean up drones.
  9251.     for playerId = 0,15 do
  9252.         if getplayer(playerId) then
  9253.             cleanupdrones(playerId)
  9254.         end
  9255.     end
  9256. end
  9257.  
  9258. local NameRequestName
  9259. function OnNameRequest(hash, name)
  9260.    
  9261.     -- No commas allowed in the name (it's our delimiter for the banlist and admin file.)
  9262.     local count
  9263.     name, count = gsub(name, ",", "")
  9264.    
  9265.     NameRequestName = tostring(name)
  9266.    
  9267.     if findBanlistEntry(name, nil, nil, "name") then
  9268.         hprintf(name .. " joined with a banned name, using random name.")
  9269.         return false
  9270.     end
  9271.    
  9272.     if count and count >= 1 then
  9273.         return false, name
  9274.     end
  9275. end
  9276.  
  9277. -- brief Called when a hash is validated by gamespy
  9278. -- param hash:      The hash that was checked
  9279. -- param status:    Result of the check (1 = valid, 2 = invalid, 3 = valid hash but invalid challenge)
  9280. -- Status 2 indicates that somebody is trying to spoof a player's hash
  9281. -- (i.e. pretend to be them). The player is immediately kicked after calling this function.
  9282. function OnHashValidation(hash, status)
  9283.     hprintf("Hash: " .. tostring(hash) .. " Status: " .. tostring(status))
  9284.     --[[if status == 2 then
  9285.         WriteLog(profilepath .. "logs\\SecurityIssues.log", hash .. " attempted to spoof, status 2")
  9286.     end--]]
  9287. end
  9288.  
  9289. local isMuted
  9290. function OnBanCheck(hash, ip)
  9291.     hprintf(NameRequestName .. " (Hash: " .. tostring(hash) .. " IP: " .. tostring(ip) .. ") is attempting to join the server")
  9292.     -- Do not let anyone with hacked hashes (they did some serious hacking and memory modding to change it to something like 'myfakehashlolz') into the game ever.
  9293.     if not match(hash, "%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x+") then return false end
  9294.  
  9295.     -- Check if they are on boslist.
  9296.     local bos_entry
  9297.     for i = 1,#bos_table do bos_entry = bos_table[i]
  9298.         if netMatch(bos_entry.ip, ip) then
  9299.             privateSayAdmins(bos_entry.name .. " banned from BoS.\nEntry: " .. bos_entry.name .. "- " .. bos_entry.ip)
  9300.             hprintf(bos_entry.name .. " banned from BoS.\nEntry: " .. bos_entry.name .. "- " .. bos_entry.ip)
  9301.             WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", bos_entry.name .. " was Banned on Sight")
  9302.             addBan(bos_entry.name, nil, ip, -1, "ip", "Ban on Sight")
  9303.             return false
  9304.         end
  9305.     end
  9306.  
  9307.     -- Check if they are on banlist.
  9308.     local ban_entry = findBanlistEntry(nil, hash, ip)
  9309.     if ban_entry then
  9310.         hprintf(NameRequestName .. " (Hash: " .. hash .. " IP: " .. ip .. ") has been rejected because they were found on the " .. ban_entry.type .. " banlist with index '" .. ( ban_entry.name .. ":" .. (ban_entry.hash or "") .. ":" .. (ban_entry.ip or "") ) .. "'")
  9311.         if ban_entry.type == "chat" then
  9312.             isMuted = true
  9313.         else
  9314.             return false
  9315.         end
  9316.     end
  9317. end
  9318.  
  9319. function OnPlayerJoin(playerId)
  9320.     local player = PlayerClass:Initialize(playerId)
  9321.  
  9322.     -- write the team colors to the player (required since we are using the color patch)
  9323.     if team_play then
  9324.         --writeword(getplayer(playerId) + 0x60, getteam(playerId)+2)
  9325.     elseif readword(getplayer(playerId) + 0x60) == 10 and sub(gethash(playerId), 1, 5) ~= "56d5f" --[[forjessasblack-or readword(getplayer(playerId) + 0x60) == 1 and sub(gethash(playerId), 1, 5) ~= "c68bd"--]] or readword(getplayer(playerId) + 0x60) == 12 and sub(gethash(playerId), 1, 5) ~= "abd5c" then
  9326.         writeword(getplayer(playerId) + 0x60, 13)
  9327.     end
  9328.     cur_players = cur_players + 1
  9329.     local name = getname(playerId)
  9330.     local hash = gethash(playerId)
  9331.     local ip = getip(playerId)
  9332.  
  9333.     local iprange = match(ip, "^%d+%.%d+%.%d+")
  9334.  
  9335.     player.muted = player.muted or not not isMuted
  9336.     isMuted = nil
  9337.  
  9338.     if player.suspended then
  9339.         kill(playerId)
  9340.         writeshort(getplayer(playerId) + 0x2C, tonumber(player.suspended) or 3000)
  9341.     end
  9342.  
  9343.     if defaults.uniques_enabled then
  9344.         if unique_table[hash] or unique_table[ip] or unique_table[iprange] then
  9345.             if defaults.wb_message then
  9346.                 privatesay(playerId, "Welcome back " .. name .. "")
  9347.             end
  9348.             unique_table[hash] = unique_table[hash] or {}--TM.New()
  9349.             unique_table[hash].joincount = (unique_table[hash].joincount or 0) + 1
  9350.             unique_table[ip] = unique_table[ip] or {}--TM.New()
  9351.             unique_table[ip].joincount = (unique_table[ip].joincount or 0) + 1
  9352.             unique_table[iprange] = unique_table[iprange] or {}--TM.New()
  9353.             unique_table[iprange].joincount = (unique_table[iprange].joincount or 0) + 1
  9354.         else
  9355.             unique_table[hash] = {joincount = 1, names = {name}}
  9356.             unique_table[ip] = {joincount = 1, names = {name}}
  9357.             unique_table[iprange] = {joincount = 1, names = {name}}
  9358.             unique_table.total = unique_table.total + 1
  9359.             if defaults.firstjoin_message then
  9360.                 say("This is " .. name .. "'s first time in the server unique player #: " .. unique_table.total)
  9361.             end
  9362.         end
  9363.     end
  9364.     if defaults.sa_message then
  9365.         if PlayerClass[playerId].admin_entry then
  9366.             hprintf("Server Admin: " .. name)
  9367.             Say("Server Admin: " .. name)
  9368.         end
  9369.     end
  9370.     if defaults.multiteam_vehicles then
  9371.         writebyte(getplayer(playerId) + 0x20, 0)
  9372.     end
  9373.     hprintf(name .. " has joined the game")
  9374. end
  9375.  
  9376. function OnPlayerLeave(playerId)
  9377.     cleanupdrones(playerId)
  9378.     cur_players = cur_players - 1
  9379.     local name = getname(playerId)
  9380.     local player = PlayerClass[playerId]
  9381.     local ip = player.ip
  9382.     player.playerId = -1
  9383.     if not gameend and player.tempadmin then
  9384.         player.tempadmin = false
  9385.     end
  9386.     if votekickPlayerId == playerId then
  9387.         votekicktimer = nil
  9388.         votekickPlayerId = nil
  9389.         votekick_counter = -defaults.votekick_timeout
  9390.         for playerId = 0,15 do
  9391.             if getplayer(playerId) then
  9392.                 PlayerClass[playerId].used_votekick = false
  9393.             end
  9394.         end
  9395.         say "Votekick ending because votekicked player left the server!"
  9396.     end
  9397.    
  9398.     ResetPlayer(playerId)
  9399.     local left_entry = {}--TM.New()
  9400.     left_entry.name = name
  9401.     left_entry.hash = gethash(playerId)
  9402.     left_entry.ip = ip
  9403.     leave_table[resolveplayer(playerId)] = left_entry
  9404.     hprintf(name .. " is leaving the game")
  9405.  
  9406.     PlayerClass[playerId].player_struct = false
  9407. end
  9408.  
  9409. function OnTeamChange(playerId, old_team, new_team, relevant)
  9410.     if team_play then
  9411.         --say(tostring(getname(playerId)) .. " swapping from " .. tostring(old_team) .. " to " .. tostring(new_team))
  9412.         --[[writeword(getplayer(playerId) + 0x60, new_team+2)
  9413.         PlayerClass[playerId].changing_teams = true--]]
  9414.     end
  9415. end
  9416.  
  9417. function destroyPlayer(id, count, playerId)
  9418.     local player = PlayerClass[playerId]
  9419.     local playerObjId = getplayerobjectid(playerId)
  9420.     if getobject(playerObjId) then
  9421.         --say("Destroying " .. tostring(getname(playerId)))
  9422.         destroyobject(playerObjId)
  9423.         --say("Done! Player " .. tostring(getname(playerId)) .. " is now " .. readword(getplayer(playerId) + 0x60))
  9424.     end
  9425.     player.changing_teams = false
  9426.     return false
  9427. end
  9428.  
  9429. function OnPlayerSpawn(playerId, playerObjId)
  9430.  
  9431.     local player = PlayerClass[playerId]
  9432.  
  9433.     if player.changing_teams then
  9434.         --say(getname(playerId) .. " is changing teams")
  9435.         registertimer(100, "destroyPlayer", playerId)
  9436.         return
  9437.     end
  9438.    
  9439.     if defaults.noweapons or player.disarmed then
  9440.         local m_weapon, weaponObjId
  9441.         for slot = 0,3 do
  9442.             m_weapon, weaponObjId = getplayerweapon(playerId, slot)
  9443.             if m_weapon then
  9444.                 destroyobject(weaponObjId)
  9445.             end
  9446.         end
  9447.     end
  9448.  
  9449.     if defaults.multiteam_vehicles then
  9450.         writebyte(player.player_struct + 0x20, 0)
  9451.     end
  9452.  
  9453.     if player.colorspawn then
  9454.         movobjectcoords(playerObjId, player.x, player.y, player.z)
  9455.         player.colorspawn = false
  9456.     end
  9457.     player.suspended = false
  9458.     player.ghostmode = false
  9459.     --writebit(m_playerObj + 0x10, 0, 1) -- both for ghostmode
  9460.     --writebit(m_playerObj + 0x10, 24, 0)
  9461.    
  9462.     -- default spawn weapons code:
  9463.     if next(spawnWeapons) then
  9464.         if starting_equipment == "Generic" then
  9465.  
  9466.             -- check if we still need to assign leftover weapons to players (tertiary and quartenary weapons)
  9467.             if spawnWeapons[3] then
  9468.                 -- assign the leftover weapons to the player
  9469.                 registertimer(0, "AssignLeftoverWeapons", playerId)
  9470.             end
  9471.         elseif starting_equipment == "Custom" then
  9472.             -- assign the correct weapons to the player
  9473.             registertimer(0, "AssignWeapons", playerId)
  9474.         end
  9475.     end
  9476. end
  9477.  
  9478. local mode = 1 -- screw you phasor
  9479. function OnNewGame(map)
  9480.     if Persistent then
  9481.         rtv_counter = 0
  9482.         for _,entry in next,PlayerClass do
  9483.             if type(entry) ~= "function" then
  9484.                 entry.rtv_rocked = false
  9485.             end
  9486.         end
  9487.     end
  9488.     Map = map
  9489.     locations[map] = locations[map] or {}
  9490.     gameend = false
  9491.     gametype = readbyte(addresses.gametype_base + 0x30)
  9492.     team_play = readbyte(addresses.gametype_base + 0x34) == 1
  9493.     scorelimit = getscorelimit()
  9494.     starting_equipment = readbit(addresses.gametype_base + 0x38, 2) and "Generic" or "Custom"
  9495.    
  9496.     -- Turn MTV Off
  9497.     if team_play then
  9498.         defaults.multiteam_vehicles = false
  9499.     end
  9500.    
  9501.     LoadTags()
  9502.     mode = 1
  9503.    
  9504.     if gametype == 2 then
  9505.         --writebyte(addresses.slayer_score_patch, 0xEB)
  9506.         -- how tf do i set slayer scorelimit: figured it out writebyte(addresses.gametype_base + 0x58, score)
  9507.     end
  9508.    
  9509.     local args = defaults.remote_bansystem
  9510.     if args then
  9511.         reloadRemoteBanlist()
  9512.     end
  9513.  
  9514.     collectgarbage()
  9515. end
  9516.  
  9517.  
  9518. function OnGameEnd(mode_that_sometimes_lies)
  9519.     if mode == 1 then
  9520.         gameend = true
  9521.         collectgarbage()
  9522.         if gametype == 2 then
  9523.             team_scores[0] = 0
  9524.             team_scores[1] = 0
  9525.             for i = 0,15 do
  9526.                 player_scores[i] = 0
  9527.             end
  9528.             --writebyte(addresses.slayer_score_patch, 0x74)
  9529.             -- how tf do i set slayer scorelimit: figured it out writebyte(addresses.gametype_base + 0x58, score)
  9530.         end
  9531.         team_play_temp = nil
  9532.     end
  9533.     mode = mode + 1
  9534. end
  9535.  
  9536. local function votekick()
  9537.     say("Removing " .. getname(votekickPlayerId) .. " from the server")
  9538.     if defaults.votekick_action == "ban" then
  9539.         svcmd("sv_ban " .. resolveplayer(votekickPlayerId) .. " 5m Votekicked with " .. votekick_counter .. " votes")
  9540.     else
  9541.         svcmd("sv_kick " .. resolveplayer(votekickPlayerId) .. " Votekicked with " .. votekick_counter .. " votes")
  9542.     end
  9543.     votekickPlayerId = nil
  9544.     if votekicktimer then
  9545.         removetimer(votekicktimer)
  9546.         votekicktimer = nil
  9547.     end
  9548.     votekick_counter = -defaults.votekick_timeout
  9549. end
  9550.  
  9551. function OnServerChat(playerId, chattype, message)
  9552.     local AllowChat, found, receiverPlayer
  9553.     if chattype == 4 then
  9554.         -- don't do anything if the server is private messaging someone.
  9555.         local msg = gsub(message, "**SERVER**", "\n**SERVER TO " .. getname(playerId) .. "**")
  9556.         hprintf(msg)
  9557.         if server_prefix then
  9558.             return true, gsub(message, "**SERVER**", server_prefix)
  9559.         end
  9560.         return nil
  9561.     elseif not playerId then
  9562.         -- do nothing here if the server is globally talking to everyone.
  9563.         hprintf("\n" .. message)
  9564.         if server_prefix then
  9565.             return true, gsub(message, "**SERVER**", server_prefix)
  9566.         end
  9567.         return nil
  9568.     end
  9569.  
  9570.     local name, hash, ip = getname(playerId), gethash(playerId), getip(playerId)
  9571.  
  9572.     local player = PlayerClass[playerId]
  9573.  
  9574.     if player.muted or player.spamcounter < 0 then
  9575.         return false
  9576.     end
  9577.     local t = tokenizecmdstring(message)
  9578.     local count = #t
  9579.     local cmd = t[1]
  9580.  
  9581.     if cmd == "rtv" or cmd == "skip" then
  9582.         if count ~= 1 then
  9583.             goto endchat
  9584.         end
  9585.  
  9586.         AllowChat = false
  9587.  
  9588.         if not defaults.rtv_enabled then
  9589.             privatesay(playerId, "Rockthevote is disabled.")
  9590.             goto endchat
  9591.         end
  9592.  
  9593.         if rtv_counter < 0 then
  9594.             privatesay(playerId, "You cannot initiate rtv at this time")
  9595.             goto endchat
  9596.         end
  9597.  
  9598.         local total_votes_required = round(cur_players * defaults.rtv_required * 0.01)
  9599.  
  9600.         if player.rtv_rocked then
  9601.             privatesay(playerId, "You have already voted for rtv")
  9602.             goto endchat
  9603.         end
  9604.  
  9605.         rtv_counter = rtv_counter + 1
  9606.         if rtv_counter == 1 then
  9607.             say(name .. " has initiated rtv")
  9608.             say('Type "rtv" to join the vote')
  9609.             rtvtimer = registertimer(defaults.rtv_timeout * 1000, "rtvTimer")
  9610.         else
  9611.             say(name .. " has voted for rtv")
  9612.         end
  9613.  
  9614.         say(rtv_counter .. " of " .. total_votes_required .. " votes required for rtv")
  9615.  
  9616.         player.rtv_rocked = true
  9617.         if rtv_counter >= total_votes_required then
  9618.             if rtvtimer then
  9619.                 removetimer(rtvtimer)
  9620.                 rtvtimer = nil
  9621.             end
  9622.             rtv_counter = -defaults.rtv_timeout
  9623.             say("Enough votes for rtv, game is now ending...")
  9624.             halo_svcmd "sv_map_next"
  9625.         end
  9626.     elseif cmd == "votekick" then
  9627.         if count ~= 2 then
  9628.             goto endchat
  9629.         end
  9630.  
  9631.         AllowChat = false
  9632.  
  9633.         if not defaults.votekick_enabled then
  9634.             privatesay(playerId, "Votekick is disabled")
  9635.             goto endchat
  9636.         end
  9637.  
  9638.         if player.used_votekick then
  9639.             privatesay(playerId, "You have already voted for a votekick!")
  9640.             goto endchat
  9641.         end
  9642.  
  9643.         if votekick_counter < 0 then
  9644.             privatesay(playerId, "Votekick will be available in " .. -votekick_counter .. " seconds")
  9645.             goto endchat
  9646.         elseif votekick_counter > 0 then
  9647.             privatesay(playerId, "There is already a votekick in progress.")
  9648.             goto endchat
  9649.         end
  9650.  
  9651.         local players = getvalidplayers(t[2])
  9652.         if not players then
  9653.             privatesay(playerId, "Invalid Player!")
  9654.             goto endchat
  9655.         end
  9656.  
  9657.         if players[2] then
  9658.             privatesay(playerId, "You can only votekick one player at a time!")
  9659.             goto endchat
  9660.         end
  9661.  
  9662.         receiverPlayer = players[1]
  9663.         if playerId == receiverPlayer then
  9664.             privatesay(playerId, "You cannot votekick yourself noob.")
  9665.             goto endchat
  9666.         end
  9667.  
  9668.         if PlayerClass[receiverPlayer].admin_entry then
  9669.             privatesay(playerId, "Admins cannot be votekicked")
  9670.             goto endchat
  9671.         end
  9672.  
  9673.         local total_votes_required = round(cur_players*(defaults.votekick_required * 0.01))
  9674.         votekickPlayerId = receiverPlayer
  9675.         player.used_votekick = true
  9676.         votekick_counter = votekick_counter + 1
  9677.         say(name .. ' has initiated a votekick on ' .. getname(receiverPlayer) .. '\n Type "kick" to join the vote\n 1 of ' .. total_votes_required .. ' votes required to kick')
  9678.  
  9679.         if votekick_counter >= total_votes_required then
  9680.             votekick()
  9681.         end
  9682.     elseif cmd == "kick" then
  9683.         if count ~= 1 then
  9684.             goto endchat
  9685.         end
  9686.  
  9687.         AllowChat = false
  9688.  
  9689.         if not defaults.votekick_enabled then
  9690.             privatesay(playerId, "Votekick is disabled")
  9691.             goto endchat
  9692.         end
  9693.  
  9694.         if player.used_votekick then
  9695.             privatesay(playerId, "You have already voted for a votekick!")
  9696.             goto endchat
  9697.         end
  9698.  
  9699.         if votekick_counter <= 0 then
  9700.             privatesay(playerId, "There is no votekick in progress. Use 'votekick (playerIndex)' to start one!")
  9701.             goto endchat
  9702.         end
  9703.  
  9704.         if playerId == votekickPlayerId then
  9705.             privatesay(playerId, "You cannot vote for yourself to be kicked noob")
  9706.             goto endchat
  9707.         end
  9708.  
  9709.         local total_votes_required = round(cur_players*(defaults.votekick_required*0.01))
  9710.  
  9711.         player.used_votekick = true
  9712.         votekick_counter = votekick_counter + 1
  9713.         say(name .. " has voted to kick " .. getname(votekickPlayerId))
  9714.         say(votekick_counter .. " of " .. total_votes_required .. " votes required to kick")
  9715.  
  9716.         if votekick_counter >= total_votes_required then
  9717.             votekick()
  9718.         end
  9719.     end
  9720.     receiverPlayer = match(cmd, "^@(%g+)$")
  9721.     if defaults.pm_enabled and receiverPlayer then
  9722.  
  9723.         AllowChat = false
  9724.  
  9725.         local players = getvalidplayers(receiverPlayer, playerId)
  9726.         if not players then
  9727.             privatesay(playerId, "There is no player identified as '" .. receiverPlayer .. "'")
  9728.             goto endchat
  9729.         end
  9730.  
  9731.         if #players > 4 then
  9732.             privatesay(playerId, "You cannot privatemessage more than 4 people at once!")
  9733.             goto endchat
  9734.         end
  9735.  
  9736.         local privatemessage = concat(t, " ", 2, #t)
  9737.         local names = {}--TM.New()
  9738.  
  9739.         for i = 1,#players do receiverPlayer = players[i]
  9740.             if playerId == receiverPlayer then
  9741.                 goto nextPlayer
  9742.             end
  9743.             names[i] = getname(receiverPlayer) .. " (" .. resolveplayer(receiverPlayer) .. ")"
  9744.             sendconsoletext(receiverPlayer, getname(playerId) .. ": (" .. resolveplayer(playerId) .. ") " .. privatemessage)
  9745.             ::nextPlayer::
  9746.         end
  9747.         sendconsoletext(playerId, "PM to " .. concat(names, ", ") .. " " .. privatemessage)
  9748.     end
  9749.  
  9750.     if sub(cmd, 1, 1) == "/" then
  9751.         output_environment = 2
  9752.         found = true
  9753.         AllowChat = _SERVERAPP == "Phasor" or not not say(name .. ": " .. message, false) -- sapp will execute the command a second time if this isn't here. I still like this environment showing up in the chat.
  9754.     elseif sub(cmd, 1, 1) == "\\" then
  9755.         output_environment = 3
  9756.         found = true
  9757.         AllowChat = false
  9758.     end
  9759.  
  9760.     if found then
  9761.         if defaults.chatcommands then
  9762.             if cmd == "/" or cmd == "\\" then
  9763.                 sendresponse("Invalid Command", playerId)
  9764.             elseif cmd == "/e" or cmd == "\\e" then
  9765.                 cmd = concat(t, " ", 2)
  9766.                 sendresponse("Executed " .. cmd, playerId)
  9767.                 sendresponse(svcmdplayer(cmd, playerId, true), playerId)
  9768.             --[[elseif cmd == "/l" or cmd == "/login" then
  9769.                 remove(t, 1) -- command is not an argument
  9770.                 Commands[cmd](t, cmd, playerId)--]]
  9771.             else
  9772.                 sendresponse(svcmdplayer(message, playerId, true), playerId)
  9773.             end
  9774.         else
  9775.             privatesay(playerId, "Chat commands are currently disabled.")
  9776.         end
  9777.     end
  9778.  
  9779.     ::endchat::
  9780.  
  9781.     if AllowChat ~= false and defaults.spam_max > 0 and (defaults.antispam == "all" or defaults.antispam == "players" and not getaccess(playerId)) then
  9782.         player.spamcounter = player.spamcounter + 1
  9783.     end
  9784.  
  9785.     -- Print a message to the console of the chat.
  9786.     hprintf("\nOnServerChat(" .. playerId .. ", " .. tostring(chattype) .. ") " .. getname(playerId) .. ": (" .. resolveplayer(playerId) .. ") " .. message)
  9787.     if AllowChat ~= false then
  9788.         if defaults.anticaps then
  9789.             if defaults.chatids then
  9790.                 return true, " (" .. resolveplayer(playerId) .. ") " .. lower(message)
  9791.             end
  9792.             return true, lower(message)
  9793.         elseif defaults.chatids then
  9794.             return true, " (" .. resolveplayer(playerId) .. ") " .. message
  9795.         end
  9796.     end
  9797.     return AllowChat
  9798. end
  9799.  
  9800. function rtvTimer(id, count)
  9801.     if rtv_counter > 0 then
  9802.         rtv_counter = -defaults.rtv_timeout
  9803.         for playerId = 0,15 do
  9804.             if getplayer(playerId) then
  9805.                 PlayerClass[playerId].rtv_rocked = false
  9806.             end
  9807.         end
  9808.         say "The current rtv has expired"
  9809.     end
  9810.     return false
  9811. end
  9812.  
  9813. function rconBruteForceTimeout(id, count, player)
  9814.     if player.rcon_fails == 0 then
  9815.         player.rconfail_timer = -1
  9816.         return false
  9817.     end
  9818.  
  9819.     player.rcon_fails = player.rcon_fails - 1
  9820.     return true
  9821. end
  9822.  
  9823. local command_attempt
  9824. -- this function is horrendously named, would you believe it's only SUPPOSED to be called when BAD rcon passwords are given?
  9825. function OnServerCommandAttempt(playerId, command, password)
  9826.     local t = tokenizecmdstring(command)
  9827.     local cmd = getvalidformat(t[1])
  9828.  
  9829.     -- EVEN IF the server is executing a command, we don't want it executing commands during scrimmode.
  9830.     if defaults.scrim_mode then
  9831.  
  9832.         -- Format our command.
  9833.         if not Commands[cmd].scrim then
  9834.             sendresponse("This command is currently disabled.\nTurn Scrim mode off to reenable this command.", playerId)
  9835.             cmdlog(getname(playerId) .. " attempted to use " .. cmd .. " during scrim mode.")
  9836.             return false
  9837.         end
  9838.     end
  9839.  
  9840.     -- Do nothing if the server is executing a command
  9841.     if not playerId then return nil end
  9842.  
  9843.     -- If the player has gotten the password wrong too many times, register our brute force timer
  9844.     local player = PlayerClass[playerId]
  9845.     if player.rcon_fails >= 10 then
  9846.         if player.rconfail_timer ~= -1 then
  9847.             player.rcon_fails = player.rcon_fails + 1
  9848.         else
  9849.             player.rconfail_timer = registertimer(1000, "rconBruteForceTimeout", player)
  9850.         end
  9851.         return false
  9852.     end
  9853.  
  9854.     if password then
  9855.         output_environment = 1
  9856.     end
  9857.  
  9858.     -- We now have several cases here.
  9859.     -- If there are no admins, anyone can use the generic rcon
  9860.     -- If there are admins, then only admins can use the generic rcon
  9861.     -- If there is no generic rcon (sv_rcon_password set to "any"), admins can use any rcon password they want.
  9862.     -- If there is no password given, it is a chatcommand and we need to check their access.
  9863.     -- Everyone can use global rcons (in the rcon_passwords table).
  9864.  
  9865.     local permission = false
  9866.     local access
  9867.  
  9868.     -- Check out global passwords (sv_rcon_add)
  9869.     local level = password and rcon_passwords[password]
  9870.     if level then
  9871.         permission = checkaccess(cmd, level)
  9872.     else
  9873.         access = getaccess(playerId)
  9874.         local generic_rcon = readstring(addresses.network_server_globals + 0x128)
  9875.         -- If there are no admins on the server, and the rcon was correct, allow the command
  9876.         if not next(admin_table) and generic_rcon == password then
  9877.             permission = true
  9878.         -- If the player has admin access, then allow the command IF a password was not provided (chat command), sv_rcon_password is set to 'any' (allow all rcon passwords), or check if the rcon matches the rcon password.
  9879.         elseif access and (not password or generic_rcon == "any" or generic_rcon == password) then
  9880.             permission = checkaccess(cmd, access)
  9881.         end
  9882.     end
  9883.  
  9884.     if permission == false then
  9885.         local admin_entry = PlayerClass[playerId].admin_entry
  9886.         local admin_name = admin_entry and admin_entry.name or "N/A"
  9887.         if level then
  9888.             cmdlog("    >>Security Alert: " .. getname(playerId) .. " (Nickname: " .. admin_name .. " Hash:" .. gethash(playerId) .. " IP: " .. getip(playerId) .. ") tried to execute: '" .. command .. "'")
  9889.             sendresponse("This Rcon does not have access to that command. This will be reported.", playerId)
  9890.         elseif password and output_environment <= 1 then
  9891.             if not access then
  9892.                 cmdlog(getname(playerId) .. " (Nickname: " .. admin_name .. " Hash:" .. gethash(playerId) .. " IP: " .. getip(playerId) .. ") tried to use '" .. password .. "' as an rcon password")
  9893.                 sendresponse("You are not an admin. This will be reported", playerId)
  9894.                 goto ReturnPermission
  9895.             elseif password ~= generic_rcon then
  9896.                 cmdlog(getname(playerId) .. " (Nickname: " .. admin_name .. " Hash:" .. gethash(playerId) .. " IP: " .. getip(playerId) .. ") tried to use '" .. password .. "' as an rcon password")
  9897.                 sendresponse("That is not an rcon password", playerId)
  9898.             else
  9899.                 cmdlog(getname(playerId) .. " (Nickname: " .. admin_name .. " Hash:" .. gethash(playerId) .. " IP: " .. getip(playerId) .. ") tried to execute: '" .. command .. "'")
  9900.                 sendresponse("You cannot execute this command.", playerId)
  9901.             end
  9902.         else
  9903.             cmdlog(getname(playerId) .. " (Nickname: " .. admin_name .. " Hash:" .. gethash(playerId) .. " IP: " .. getip(playerId) .. ") tried to execute: '" .. command .. "'")
  9904.             sendresponse("You cannot execute this command.", playerId)
  9905.             goto ReturnPermission
  9906.         end
  9907.  
  9908.         player.rcon_fails = player.rcon_fails + 1
  9909.     else
  9910.         command_attempt = true
  9911.         player.rcon_fails = 0
  9912.     end
  9913.    
  9914.     ::ReturnPermission::
  9915.     return permission
  9916. end
  9917.  
  9918. function OnServerCommand(playerId, command)
  9919.  
  9920.     -- prevents rare issues that happen when init files execute blank commands
  9921.     if not match(command, "%w+") then return nil end
  9922.  
  9923.     -- this is to prevent infinite loops from when I want to execute a halo command
  9924.     -- without creating infinite loops (continually calling my sv_unban which will then continually call this etc)
  9925.     if dont_call_onservercommand then return nil end
  9926.  
  9927.     -- this means that a valid password was given so oncommandattempt was never actually called.
  9928.     -- It also means the command came using the console, and not the chat
  9929.     if not command_attempt then
  9930.         if OnServerCommandAttempt(playerId, command, readstring(addresses.network_server_globals + 0x128)) == false then
  9931.             return false
  9932.         elseif playerId then
  9933.             output_environment = 1
  9934.         end
  9935.         command_attempt = nil
  9936.     else
  9937.         command_attempt = nil
  9938.     end
  9939.  
  9940.     local response, thisCommand
  9941.     local t = tokenizecmdstring(command)
  9942.     local count = #t
  9943.  
  9944.     -- Format our command.
  9945.     local cmd = getvalidformat(t[1])
  9946.     if cmd == "help" or cmd == "gethelp" then
  9947.         response = false
  9948.         t[2] = concat(t, "", 2)
  9949.         thisCommand = Commands[getvalidformat(t[2])]
  9950.  
  9951.         if thisCommand and thisCommand.info.help then
  9952.             sendresponse(gsub(thisCommand.info.help, "%%s", t[2]), playerId)
  9953.         else
  9954.             sendresponse("No help topics for command '" .. tostring(t[2]) .. "'", playerId)
  9955.         end
  9956.     else
  9957.         -- this is a bit hacky, but I've made hackier stuff before, plus this will always work :D
  9958.         -- Code for commands with spaces in it.
  9959.         local tempCmd = cmd
  9960.         local i = 2
  9961.         while i <= count do
  9962.  
  9963.             tempCmd = tempCmd .. gsub(t[i], "_", "")
  9964.             thisCommand = Commands[tempCmd]
  9965.  
  9966.             if thisCommand then
  9967.                 t[1] = tempCmd
  9968.                 for j = 2,i do
  9969.                     remove(t, 2)
  9970.                 end
  9971.                 break
  9972.             end
  9973.             i = i + 1
  9974.         end
  9975.         thisCommand = Commands[getvalidformat(t[1])]
  9976.  
  9977.         -- First possibility: a command gets truncated in a valid format, and this function recognizes it as a script command
  9978.         if thisCommand then
  9979.             response = false
  9980.             local origCommand = t[1]
  9981.             remove(t, 1) -- the command isn't an argument.
  9982.             thisCommand:Execute(t, origCommand, playerId)
  9983.  
  9984.         -- this means it is NOT one of my scripted commands.
  9985.         else
  9986.             local message
  9987.             local newcmd = command
  9988.            
  9989.             if not match(newcmd, "script_reload") and not match(newcmd, "script_unload " .. sub(debug.getinfo(1, "S").source, 2, -5)) then
  9990.                 if sub(newcmd, 1, 1) == "/" or sub(newcmd, 1, 1) == "\\" then
  9991.                 --  print("1st CHECK")
  9992.                     newcmd = sub(newcmd, 2)
  9993.                     message = halo_svcmd(newcmd, true)
  9994.                 end
  9995.  
  9996.                 -- Second Possibility: the command might need an sv_, or might need the sv_ removed.
  9997.                 if type(message) ~= "table" or type(message[1]) ~= "string" or find(concat(message), "Requested function \"") then
  9998.                     --print("2nd check")
  9999.                     -- Add the sv_
  10000.                     if sub(newcmd, 1, 3) ~= "sv_" then
  10001.                         --print("3rd CHECK")
  10002.                         message = halo_svcmd("sv_" .. newcmd, true)
  10003.                     -- Remove the sv_
  10004.                     else
  10005.                         message = halo_svcmd(sub(newcmd, 4), true)
  10006.                     end
  10007.                 end
  10008.  
  10009.  
  10010.                 if type(message) ~= "table" or type(message[1]) ~= "string" or find(concat(message), "Requested function \"") then
  10011.                     --sendresponse('Command "' .. t[1] .. '" not found.', playerId)
  10012.                 -- Send back the message from the non-scripted command.
  10013.                 else
  10014.                     sendresponse(message, playerId)
  10015.                 end
  10016.             end
  10017.         end
  10018.     end
  10019.     if playerId and response == false then
  10020.         cmdlog(format("%s (Nickname: %s Hash: %s IP: %s) has executed: %s", getname(playerId), (PlayerClass[playerId].admin_entry and PlayerClass[playerId].admin_entry.name or "N/A"), gethash(playerId), getip(playerId), command))
  10021.     end
  10022.  
  10023.     return response
  10024. end
  10025.  
  10026. local function sendKillingSpreeMessages(killerPlayerId, victimPlayerId)
  10027.     local m_kplayer = getplayer(killerPlayerId)
  10028.     local kname = getname(killerPlayerId)
  10029.  
  10030.     local multikill = readword(m_kplayer + 0x98)
  10031.     if multikill == 2 then
  10032.         sendconsoletext(killerPlayerId, "Double Kill")
  10033.     elseif multikill == 3 then
  10034.         sendconsoletext(killerPlayerId, "Triple Kill")
  10035.     elseif multikill == 4 then
  10036.         sendconsoletext(killerPlayerId, "OverKill")
  10037.     elseif multikill == 5 then
  10038.         sendconsoletext(killerPlayerId, "Killtacular")
  10039.     elseif multikill == 6 then
  10040.         sendconsoletext(killerPlayerId, "Killtrocity")
  10041.     elseif multikill == 7 then
  10042.         sendconsoletext(killerPlayerId, "Killimanjaro")
  10043.     elseif multikill == 8 then
  10044.         sendconsoletext(killerPlayerId, "Killtastrophe")
  10045.     elseif multikill == 9 then
  10046.         sendconsoletext(killerPlayerId, "Killpocalypse")
  10047.     elseif multikill >= 10 then
  10048.         sendconsoletext(killerPlayerId, "Killionaire")
  10049.     end
  10050.  
  10051.     local spree = readword(m_kplayer + 0x96)
  10052.     if spree >= 40 and spree%2 == 0 then
  10053.         Say("OMFGWTFBBQWAFFLES " .. kname .. " is Unfrigginbelievable with " .. spree .. " kills!", 1, playerId)
  10054.         sendconsoletext(killerPlayerId, "OMFGWTFBBQWAFFLES Unfrigginbelievable")
  10055.     elseif spree >= 35 and spree < 40 then
  10056.         Say(kname .. " is Inconceivable with " .. spree .. " kills!", 1, playerId)
  10057.         sendconsoletext(killerPlayerId, "Inconceivable")
  10058.     elseif spree >= 30 then
  10059.         Say(kname .. " is Invincible with " .. spree .. " kills!", 1, playerId)
  10060.         sendconsoletext(killerPlayerId, "Invincible")
  10061.     elseif spree >= 25 then
  10062.         Say(kname .. " is Untouchable with " .. spree .. " kills!", 1, playerId)
  10063.         sendconsoletext(killerPlayerId, "Untouchable")
  10064.     elseif spree >= 20 then
  10065.         Say(kname .. " is on a Rampage with " .. spree .. " kills!", 1, playerId)
  10066.         sendconsoletext(killerPlayerId, "Rampage")
  10067.     elseif spree >= 15 then
  10068.         Say(kname .. " is on a Running Riot with " .. spree .. " kills!", 1, playerId)
  10069.         sendconsoletext(killerPlayerId, "Running Riot")
  10070.     elseif spree >= 10 then
  10071.         Say(kname .. " is on a Killing Frenzy with " .. spree .. " kills!", 1, playerId)
  10072.         sendconsoletext(killerPlayerId, "Killing Frenzy")
  10073.     elseif spree >= 5 then
  10074.         Say(kname .. " is on a Killing Spree with " .. spree .. " kills!", 1, playerId)
  10075.         sendconsoletext(killerPlayerId, "Killing Spree")
  10076.     end
  10077.    
  10078.     local m_vplayer = getplayer(victimPlayerId)
  10079.     local victim_spree = readword(m_vplayer + 0x96)
  10080.     if victim_spree >= 5 then
  10081.         Say(kname .. " just ended " .. getname(victimPlayerId) .. "'s killing spree of " .. victim_spree .. "!")
  10082.     end
  10083. end
  10084.  
  10085. function OnPlayerKill(killerPlayerId, victimPlayerId, mode)
  10086.     if mode == 6 then
  10087.         hprintf(getname(victimPlayerId) .. " has committed suicide!")
  10088.     elseif mode == 0 or mode >= 4 then
  10089.         hprintf(getname(victimPlayerId) .. " was killed by " .. getname(killerPlayerId))
  10090.     elseif mode == 1 then
  10091.         hprintf(getname(victimPlayerId) .. " fell off a high place")
  10092.     elseif mode == 2 then
  10093.         hprintf(getname(victimPlayerId) .. " was killed by the Guardians")
  10094.     elseif mode == 3 then
  10095.         hprintf(getname(victimPlayerId) .. " was rolled over by a vehicle")
  10096.     end
  10097.  
  10098.     cleanupdrones(victimPlayerId)
  10099.  
  10100.     local victim = PlayerClass[victimPlayerId]
  10101.     local killer = PlayerClass[killerPlayerId]
  10102.     victim.godmode = false
  10103.     if defaults.respawn_time then
  10104.         writedword(getplayer(victimPlayerId) + 0x2C, defaults.respawn_time * 30)
  10105.     end
  10106.     if mode == 4 then
  10107.    
  10108.         -- Score monitoring.
  10109.         if gametype == 2 then
  10110.             local score = player_scores[killerPlayerId]
  10111.             player_scores[killerPlayerId] = score + 1
  10112.             if team_play then
  10113.                 team_scores[getteam(killerPlayerId)] = team_scores[getteam(killerPlayerId)] + 1
  10114.                 score = team_scores[getteam(killerPlayerId)]
  10115.             end
  10116.             --say("Score: " .. tostring(score) .. "Team Score: " .. tostring(team_scores[getteam(killerPlayerId)]) .. " Scorelimit: " .. tostring(scorelimit))
  10117.             if score >= scorelimit then -- check if the scorelimit has been reached.
  10118.                 halo_svcmd("sv_map_next")
  10119.             end
  10120.         end
  10121.         if defaults.killing_spree then
  10122.             sendKillingSpreeMessages(killerPlayerId, victimPlayerId)
  10123.         end
  10124.     end
  10125.     if defaults.tbag_detection then
  10126.         killer.tbagname = getname(victimPlayerId)
  10127.         killer.tbagcount = 0
  10128.         victim.tbagcount = 0
  10129.         victim.x,
  10130.         victim.y,
  10131.         victim.z = getobjectcoords(getplayerobjectid(victimPlayerId))
  10132.     end
  10133. end
  10134.  
  10135.  
  10136. function playerWeaponCheckTimer(id, count)
  10137.     for playerId = 0,15 do
  10138.  
  10139.         if not getplayer(playerId) then
  10140.             goto continue
  10141.         end
  10142.  
  10143.         local m_playerObj, playerObjId = getplayerobject(playerId)
  10144.         if not m_playerObj then
  10145.             goto continue
  10146.         end
  10147.  
  10148.         local pweaptable = PlayerClass[playerId].weapons
  10149.  
  10150.         local m_weaponObj, weaponObjId
  10151.         for slot = 0,3 do
  10152.             weaponObjId = readdword(m_playerObj + 0x2F8+(slot-1)*4)
  10153.             m_weaponObj = getobject(weaponObjId)
  10154.             if m_weaponObj and weaponObjId ~= pweaptable[slot] then
  10155.                 writeshort(m_weaponObj + 0x2B6, 0x7CFF)
  10156.                 writeshort(m_weaponObj + 0x2B8, 0x7CFF)
  10157.                 updateammo(weaponObjId)
  10158.                 pweaptable[slot] = weaponObjId
  10159.             end
  10160.         end
  10161.         ::continue::
  10162.     end
  10163.  
  10164.     return true
  10165. end
  10166.  
  10167. function OnClientUpdate(playerId)
  10168.  
  10169.     if not defaults.tbag_detection then
  10170.         return
  10171.     end
  10172.    
  10173.     local player = PlayerClass[playerId]
  10174.     if player.tbagname == "" then
  10175.         return
  10176.     end
  10177.    
  10178.     local playerObjId = getplayerobjectid(playerId)
  10179.     local m_playerObj = getobject(playerObjId)
  10180.     if not m_playerObj then
  10181.         return
  10182.     end
  10183.  
  10184.     local crouching = readbyte(m_playerObj + 0x2A0) == 3
  10185.     if not player.crouch and crouching then
  10186.         player.tbagcount = (player.tbagcount or 0) + 1
  10187.         if player.tbagcount == 4 then
  10188.             player.tbagcount = 0
  10189.             say(getname(playerId) .. " is T-Bagging " .. player.tbagname)
  10190.             player.tbagname = ""
  10191.         end
  10192.         player.crouch = true
  10193.     elseif player.crouch and not crouching then
  10194.         player.crouch = false
  10195.     end
  10196. end
  10197.  
  10198. function OnObjectInteraction(playerId, objectId, mapId)
  10199.     if defaults.noweapons or PlayerClass[playerId].disarmed then
  10200.         if getObjType(objectId) == 2 then
  10201.             return false
  10202.         end
  10203.     end
  10204.     return nil -- gotta return a value
  10205. end
  10206.  
  10207. local object_types = {
  10208.     [0] = "Biped",
  10209.     "Vehicle",
  10210.     "Weapon",
  10211.     "Equipment",
  10212.     "Garbage",
  10213.     "Projectile",
  10214.     "Scenery",
  10215.     "Machine",
  10216.     "Control",
  10217.     "Light Fixture",
  10218.     "Placeholder",
  10219.     "Sound Scenery"
  10220. }
  10221.  
  10222. function OnDamageApplication(receiverObjId, causerObjId, tagId, hit, backtap)
  10223.     if not getobject(causerObjId) then
  10224.         return
  10225.     end
  10226.  
  10227.     local playerId = objectidtoplayer(causerObjId)
  10228.     if not playerId then
  10229.         return
  10230.     end
  10231.  
  10232.     local player = PlayerClass[playerId]
  10233.     if player.bulletmode == "destroy" then
  10234.         destroyobject(receiverObjId)
  10235.     elseif player.bulletmode == "entergun" then
  10236.         local m_receiverObj = getobject(receiverObjId)
  10237.         if not m_receiverObj then
  10238.             return
  10239.         end
  10240.  
  10241.         local objtype = readword(m_receiverObj + 0xB4)
  10242.         if objtype == 1 then -- check if object is a vehicle
  10243.             entervehicle(playerId, receiverObjId, 0)
  10244.         end
  10245.     elseif player.bulletmode == "debuggun" then
  10246.         local m_receiverObj = getobject(receiverObjId)
  10247.         if not m_receiverObj then
  10248.             return
  10249.         end
  10250.     end
  10251. end
  10252.  
  10253.  
  10254.  
  10255. function OnDamageLookup(receiverObjId, causerObjId, mapId, tagdata)
  10256.     local receivingPlayerId = objectidtoplayer(receiverObjId)
  10257.     if not defaults.falldamage and (mapId == gettag("jpt!", "globals\\falling") or mapId == gettag("jpt!", "globals\\distance")) then
  10258.         odl_multiplier(0.01)
  10259.     elseif defaults.deathless or (receivingPlayerId and PlayerClass[receivingPlayerId].godmode) then
  10260.         odl_multiplier(0.00000000000000000000000000000000000000001)
  10261.         local dmg_side_effect = readword(tagdata + 0x1C4)
  10262.         if dmg_side_effect == 2 or dmg_side_effect == 3 then
  10263.             writeword(tagdata + 0x1C4, 0)
  10264.             registertimer(0, "DamageAddressReset", {tagdata, 0x1C4, dmg_side_effect}) -- new phasor doesn't automatically reset tagdata anymore.
  10265.         end
  10266.     elseif getobject(causerObjId) and receivingPlayerId then
  10267.         --say("2APPLYING DAMAGE TO: " .. tostring(getname(receivingPlayerId)))
  10268.         -- make sure firefister doesn't take fire damage
  10269.         local dmg_damage_category = readword(tagdata + 0x1C6)
  10270.         if dmg_damage_category == 7 then
  10271.             --say("2FLAME DAMAGE BEING APPLIED TO: " .. tostring(getname(receivingPlayerId)))
  10272.             if PlayerClass[receivingPlayerId].firefist then
  10273.                 --say("2SETTING 0 DAMAGE")
  10274.                 odl_multiplier(0)
  10275.             end
  10276.         end
  10277.         local causingPlayerId = objectidtoplayer(causerObjId)
  10278.         local m_causingPlayer, m_receivingPlayer = getplayer(causingPlayerId), getplayer(receivingPlayerId)
  10279.         if not m_receivingPlayer or not m_causingPlayer or causingPlayerId == receivingPlayerId then
  10280.             return
  10281.         end
  10282.  
  10283.         local player = PlayerClass[causingPlayerId]
  10284.         if player.dmgmultiplier ~= 1 then
  10285.             odl_multiplier(player.dmgmultiplier)
  10286.         end
  10287.  
  10288.         if defaults.multiteam_vehicles then
  10289.             writebyte(m_receivingPlayer + 0x20, getteam(receivingPlayerId)+1)
  10290.             registertimer(0, "multiteamtimer", receivingPlayerId)
  10291.         end
  10292.        
  10293.         if PlayerClass[receivingPlayerId].firefist then -- check for melee damage
  10294.             ApplyFlame(receivingPlayerId, causerObjId)
  10295.             PlayerClass[receivingPlayerId].firecauser = causerPlayerId
  10296.         end
  10297.     elseif receivingPlayerId then
  10298.         --say("1APPLYING DAMAGE TO: " .. tostring(getname(receivingPlayerId)))
  10299.         -- make sure firefister doesn't take fire damage
  10300.         local dmg_damage_category = readword(tagdata + 0x1C6)
  10301.         if dmg_damage_category == 7 then
  10302.             --say("1FLAME DAMAGE BEING APPLIED TO: " .. tostring(getname(receivingPlayerId)))
  10303.             if PlayerClass[receivingPlayerId].firefist then
  10304.                 --say("1SETTING 0 DAMAGE")
  10305.                 odl_multiplier(0)
  10306.             end
  10307.         end
  10308.     end
  10309. end
  10310.  
  10311. function multiteamtimer(id, count, playerId)
  10312.     local m_player = getplayer(playerId)
  10313.     if m_player and defaults.multiteam_vehicles then
  10314.         writebyte(m_player + 0x20, 0)
  10315.     end
  10316.     return false
  10317. end
  10318.  
  10319. function DamageAddressReset(id, count, userdata)
  10320.     local address = userdata[1]
  10321.     local offset = userdata[2]
  10322.     local orig_value = userdata[3]
  10323.     writeword(address + offset, orig_value)
  10324.     return false
  10325. end
  10326.  
  10327. local TempObjectTable = {}
  10328. function OnObjectCreationAttempt(mapId, parentObjId, playerId)
  10329.     TempObjectTable[1] = mapId
  10330.     TempObjectTable[2] = playerId
  10331.     return nil
  10332. end
  10333.  
  10334. function portalgunTimer(id, count, userdata)
  10335.     local playerObjId = userdata[1]
  10336.     local m_bulletObj = userdata[2]
  10337.     if count < 100 then
  10338.         if getobject(playerObjId) then
  10339.             if readfloat(m_bulletObj + 0x68) == 0 then
  10340.                 local x = readfloat(m_bulletObj, 0x5C)
  10341.                 local y = readfloat(m_bulletObj, 0x60)
  10342.                 local z = readfloat(m_bulletObj, 0x64)
  10343.                 movobjectcoords(playerObjId, x, y, z)
  10344.             else
  10345.                 return true
  10346.             end
  10347.         end
  10348.     end
  10349.     return false
  10350. end
  10351.  
  10352. function spawngunTimer(id, count, userdata)
  10353.     local playerId = userdata[1]
  10354.     local m_bulletObj = userdata[2]
  10355.     if getplayerobject(playerId) then
  10356.         local x = readfloat(m_bulletObj, 0x5C)
  10357.         local y = readfloat(m_bulletObj, 0x60)
  10358.         local z = readfloat(m_bulletObj, 0x64)
  10359.         local objspawnid = PlayerClass[playerId].objspawnid
  10360.         if objspawnid then
  10361.             createobject(objspawnid, 0, 60, false, x, y, z+0.6)
  10362.         end
  10363.     end
  10364.     return false
  10365. end
  10366.  
  10367. function OnObjectCreation(objectId)
  10368.     if defaults.infinite_ammo then
  10369.         local m_object = getobject(objectId)
  10370.         if m_object then
  10371.             local obj_type = readword(m_object, 0xB4)
  10372.             if obj_type == 2 then -- check if it is a weapon
  10373.                 writeshort(m_object + 0x2B6, 0x7CFF)
  10374.                 writeshort(m_object + 0x2B8, 0x7CFF)
  10375.                 return -- we can safely return here
  10376.             end
  10377.         end
  10378.     end
  10379.  
  10380.     local mapId = TempObjectTable[1]
  10381.     local playerId = TempObjectTable[2]
  10382.     if getplayer(playerId) then
  10383.         if mapId ~= gettag("proj", "weapons\\flamethrower\\flame")
  10384.         and mapId ~= gettag("proj", "weapons\\needler\\mp_needle")
  10385.         and mapId ~= gettag("proj", "weapons\\frag grenade\\frag grenade")
  10386.         and mapId ~= gettag("proj", "weapons\\plasma grenade\\plasma grenade") then
  10387.             local player = PlayerClass[playerId]
  10388.             if player.bulletmode == "portalgun" then
  10389.                 registertimer(100, "portalgunTimer", {getplayerobjectid(playerId), getobject(objectId)})
  10390.             elseif player.bulletmode == "spawngun" then
  10391.                 registertimer(100, "spawngunTimer", {playerId, getobject(objectId)})
  10392.             end
  10393.         end
  10394.     end
  10395. end
  10396.  
  10397. function OnWeaponAssignment(playerId, objId, slot, weapTagId)
  10398.     if not next(spawnWeapons) then return nil end
  10399.     if playerId then
  10400.         local m_player = getplayer(playerId)
  10401.         if m_player then
  10402.             if slot == 0 and spawnWeapons[1] then
  10403.                 return spawnWeapons[1]
  10404.             elseif slot == 1 and spawnWeapons[2] then
  10405.                 return spawnWeapons[2]
  10406.             end
  10407.         end
  10408.     end
  10409.     return nil
  10410. end
  10411.  
  10412. -- basically this timer assigns the tertiary and quarternary weapons to players for the default_spawn_weapons command.
  10413. -- this is needed since onweaponassignment isn't called for tertiary and quartenary weapons
  10414. -- This timer is used for Generic gametypes
  10415. function AssignLeftoverWeapons(id, count, playerId)
  10416.     local m_object = getplayerobject(playerId)
  10417.     if m_object then
  10418.         if spawnWeapons[3] then
  10419.             local m_weaponId = createobject(spawnWeapons[3], 0, 60, false, 5, 2, 2)
  10420.             if m_weaponId and m_weaponId ~= 0xFFFFFFFF then
  10421.                 local m_weapon = getobject(m_weaponId)
  10422.                 if m_weapon then
  10423.                
  10424.                     -- set the ammo
  10425.                     writeword(m_weapon + 0x2B6, ammocount)
  10426.                     writeword(m_weapon + 0x2B8, clipcount)
  10427.                     writefloat(m_weapon + 0x240, math.abs(batterycount - 1))
  10428.                    
  10429.                     -- force it to sync
  10430.                     updateammo(m_weaponId)
  10431.                 end
  10432.             end
  10433.            
  10434.             if spawnWeapons[4] then
  10435.        
  10436.                 -- create the quarternary weapon
  10437.                 local m_weaponId = createobject(spawnWeapons[4], 0, 60, false, 1, 1, 1)
  10438.  
  10439.                 -- make sure createobject didn't screw up
  10440.                 if m_weaponId ~= 0xFFFFFFFF then
  10441.  
  10442.                     -- assign the weapon to the player
  10443.                     assignweapon(playerId, m_weaponId)
  10444.  
  10445.                     -- make sure we can safely set the ammo
  10446.                     local m_weapon = getobject(m_weaponId)
  10447.                     if m_weapon then
  10448.                    
  10449.                         -- set the ammo
  10450.                         writeword(m_weapon + 0x2B6, ammocount)
  10451.                         writeword(m_weapon + 0x2B8, clipcount)
  10452.                         writefloat(m_weapon + 0x240, math.abs(batterycount - 1))
  10453.                        
  10454.                         -- force it to sync
  10455.                         updateammo(m_weaponId)
  10456.                     end
  10457.                 end
  10458.             end
  10459.         end
  10460.     end
  10461.     return false
  10462. end
  10463.  
  10464. -- This timer is used for Custom gametypes
  10465. function AssignWeapons(id, count, userdata)
  10466.     local playerId = userdata[1]
  10467.     local clipcount = userdata[2]
  10468.     local ammocount = userdata[3]
  10469.     local batterycount = userdata[4]
  10470.     if not playerId or not getplayer(playerId) then
  10471.         return false
  10472.     end
  10473.     local m_object = getplayerobject(playerId)
  10474.     if m_object then
  10475.         -- count is increased everytime the timer is called
  10476.         if count == 1 then
  10477.             -- gets rid of any weapons a zombie is holding
  10478.             destroyweapons(playerId)
  10479.         end
  10480.         local i = count
  10481.         if spawnWeapons[i] then
  10482.             local m_weaponId = createobject(spawnWeapons[i], 0, 60, false, 1, 1, 1) or 0xFFFFFFFF
  10483.             local m_weapon = getobject(m_weaponId)
  10484.             if m_weapon then
  10485.                
  10486.                 -- Assign the weapon to the player.
  10487.                 assignweapon(playerId, m_weaponId)
  10488.                
  10489.                 -- set the ammo
  10490.                 writeword(m_weapon + 0x2B6, ammocount)
  10491.                 writeword(m_weapon + 0x2B8, clipcount)
  10492.                 writefloat(m_weapon + 0x240, 1)
  10493.  
  10494.                 -- force it to sync
  10495.                 updateammo(m_weaponId)
  10496.             end
  10497.         end
  10498.         if count < 4 then return true else return false end
  10499.     end
  10500.     return false
  10501. end
  10502.  
  10503. function MainTimer(id, count)
  10504.  
  10505.     -- For hiding.
  10506.     local m_player
  10507.     for playerId = 0,15 do
  10508.         if getplayer(playerId) and PlayerClass[playerId] and PlayerClass[playerId].hidden then
  10509.             m_player = getplayer(playerId)
  10510.             if m_player then
  10511.                 writefloat(m_player + 0x100, -100)
  10512.             end
  10513.         end
  10514.     end
  10515.  
  10516.     -- will run every second
  10517.     if count % 30 == 0 then
  10518.  
  10519.         -- local variables used
  10520.         local player
  10521.  
  10522.         -- For invisible timer, suspended timer, and message spamming.
  10523.         for playerId = 0,15 do
  10524.             if getplayer(playerId) then
  10525.                 player = PlayerClass[playerId]
  10526.                 if player.invisible == -1 then
  10527.                     applycamo(playerId, 1.2)
  10528.                 elseif player.invisible then
  10529.                     applycamo(playerId, 1.2)
  10530.                     player.invisible = player.invisible - 1
  10531.                     if player.invisible <= 0 then
  10532.                         player.invisible = false
  10533.                     end
  10534.                 end
  10535.  
  10536.                 if type(player.suspended) == "number" then
  10537.                     player.suspended = player.suspended - 1
  10538.                     if player.suspended == 0 then
  10539.                         player.suspended = false
  10540.                         say(player.name .. " is no longer suspended")
  10541.                     end
  10542.                 end
  10543.  
  10544.                 -- Player is currently muted for spamming, add 1 second from their timeout counter until they are at 0 (or above).
  10545.                 if player.spamcounter < 0 then
  10546.                     player.spamcounter = player.spamcounter + 1
  10547.                     if player.spamcounter > 0 then
  10548.                         say(getname(playerId) .. " has been unmuted")
  10549.                         player.spamcounter = 0
  10550.                     end
  10551.                 -- Player has spammed too many messages, mute them for spamming
  10552.                 elseif player.spamcounter > defaults.spam_max then
  10553.                     say(getname(playerId) .. " has been muted for " .. timetoword(defaults.spam_timeout) .. " seconds for spamming")
  10554.                     player.spamcounter = -defaults.spam_timeout
  10555.                 -- Player has sent a message within the last second, will take 4 seconds to remove from spam counter.
  10556.                 elseif player.spamcounter > 0 then
  10557.                     player.spamcounter = player.spamcounter - 0.25
  10558.                 end
  10559.             end
  10560.         end
  10561.  
  10562.         -- RTV Counter
  10563.         if rtv_counter < 0 then
  10564.             rtv_counter = rtv_counter + 1
  10565.             if rtv_counter == 0 then
  10566.                 say "RTV can be started again."
  10567.             end
  10568.         end
  10569.  
  10570.         -- VoteKick Counter
  10571.         if votekick_counter < 0 then
  10572.             votekick_counter = votekick_counter + 1
  10573.             if votekick_counter == 0 then
  10574.                 say "VoteKick can be started again!"
  10575.             end
  10576.         end
  10577.     end
  10578.  
  10579.     return true
  10580. end
  10581.  
  10582. -- This script is now compatible with BOTH Sapp and Phasor!
  10583. if loadstring then -- don't need the module if this script is loaded via phasor.
  10584.     _G = require"PhasorSappCompatibility"
  10585. else
  10586.     _SERVERAPP = "Phasor"
  10587. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement