Advertisement
th3w1zard1

Commands 'Nimbus' Release (Version 5.13)

Feb 20th, 2015
800
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 314.73 KB | None | 0 0
  1.     --Creator: Wizard
  2.     --Script Name: Command Script
  3.     --Website: http://phasorscripts.wordpress.com/
  4.     --Xfire: th3w1zard3
  5.     --Version: 5.13 The 'Nimbus' Release
  6.     --Check Change Log for information on the updates
  7.     --Thank you Elite for the awesome work you did in updating this script to the latest phasor, and the other awesome features you put in.
  8.     --Without you I never would have updated to the newer phasor, and this script never would have been made.
  9.    
  10.     -- 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)
  11.  
  12.  
  13.     --Do Not Modify unless you really know what you are doing
  14.  
  15. -- Script Variables
  16.     -- Counts
  17. local cur_players = 0
  18. local rtv_counter = 0
  19. local votekick_counter = 0
  20.  
  21.     -- Strings
  22. local script_version = "5.13 The 'Nimbus' Release"
  23.  
  24.     -- Timers
  25. local infammo_timer
  26. local lo3_timer
  27. local maintimer
  28. local rtvtimer
  29. local votekicktimer
  30.  
  31.     -- Script Variables
  32. local changelog
  33. local dont_call_onservercommand
  34. local executingPlayerId
  35. local Game
  36. local gameend
  37. local gametype
  38. local Map
  39. local output_environment = -1
  40. local Persistent
  41. local processid
  42. local profilepath
  43. local server_prefix
  44. local team_play
  45. local timelimit_set_value
  46. local votekickPlayerId
  47.  
  48. -- Phasor doesn't automatically check limits for write functions, it just errors, so let's make our own check.
  49. local function writewithinlimit(address, value, writefunc, minlimit, maxlimit)
  50.     writefunc(address, value <= minlimit and minlimit or value >= maxlimit and maxlimit or value)
  51. end
  52.  
  53. local function writebyte(address, offset, value)
  54.     if value then
  55.         address = address + offset
  56.     else
  57.         value = offset
  58.     end
  59.     writewithinlimit(address, value, _G.writebyte, 0, 0xFF)
  60. end
  61.  
  62. local function writechar(address, offset, value)
  63.     if value then
  64.         address = address + offset
  65.     else
  66.         value = offset
  67.     end
  68.     writewithinlimit(address, value, _G.writechar, -0x80, 0x7F)
  69. end
  70.  
  71. local function writeword(address, offset, value)
  72.     if value then
  73.         address = address + offset
  74.     else
  75.         value = offset
  76.     end
  77.     writewithinlimit(address, value, _G.writeword, 0, 0xFFFF)
  78. end
  79.  
  80. local function writeshort(address, offset, value)
  81.     if value then
  82.         address = address + offset
  83.     else
  84.         value = offset
  85.     end
  86.     writewithinlimit(address, value, _G.writeshort, -0x8000, 0x7FFF)
  87. end
  88.  
  89. local function writedword(address, offset, value)
  90.     if value then
  91.         address = address + offset
  92.     else
  93.         value = offset
  94.     end
  95.     writewithinlimit(address, value, _G.writedword, 0, 0xFFFFFFFF)
  96. end
  97.  
  98. local function writeint(address, offset, value)
  99.     if value then
  100.         address = address + offset
  101.     else
  102.         value = offset
  103.     end
  104.     writewithinlimit(address, value, _G.writeint, -0x80000000, 0x7FFFFFFF)
  105. end
  106.  
  107. -- Phasor's read/writestring in previous versions are broken.
  108. local function readstring(address, length)
  109.     address = type(address) == "number" and address or error "bad argument #1 to 'readstring' expected number, got '" .. type(address) .. "'"
  110.     if length then
  111.         length = type(length) == "number" and length or error "bad argument #2 to 'readstring' expected number, got '" .. type(length) .. "'"
  112.     else
  113.         length = length or 256
  114.     end
  115.     local char_table = {}
  116.     local char = string.char
  117.     local word, dword, byte1, byte2, byte3, byte4
  118.     local i = 0
  119.     while i < length do
  120.         -- quickens write calls (screw you oxide for using virtualprotect)
  121.         if (length-i) >= 4 then
  122.             dword = readdword(address + i)
  123.  
  124.             byte1 = bit32.band(dword, 0xFF)
  125.             if byte1 == 255 or byte1 == 0 then break end
  126.             char_table[#char_table+1] = char(byte1)
  127.            
  128.             byte2 = bit32.band(bit32.rshift(dword, 8), 0xFF)
  129.             if byte2 == 255 or byte2 == 0 then break end
  130.             char_table[#char_table+1] = char(byte2)
  131.            
  132.             byte3 = bit32.band(bit32.rshift(dword, 16), 0xFF)
  133.             if byte3 == 255 or byte3 == 0 then break end
  134.             char_table[#char_table+1] = char(byte3)
  135.            
  136.             byte4 = bit32.band(bit32.rshift(dword, 24), 0xFF)
  137.             if byte4 == 255 or byte4 == 0 then break end
  138.             char_table[#char_table+1] = char(byte4)
  139.            
  140.             i = i + 4
  141.         elseif (length-i) >= 2 then
  142.             word = readword(address + i)
  143.            
  144.             byte1 = bit32.band(word, 0xFF)
  145.             if byte1 == 255 or byte1 == 0 then break end
  146.             char_table[#char_table+1] = char(byte1)
  147.            
  148.             byte2 = bit32.band(bit32.rshift(word, 8), 0xFF)
  149.             if byte2 == 255 or byte2 == 0 then break end
  150.             char_table[#char_table+1] = char(byte2)
  151.            
  152.             i = i + 2
  153.         else
  154.             byte1 = readbyte(address + i)
  155.             if byte1 == 0 or byte1 == 255 then break end
  156.             char_table[#char_table+1] = char(byte1)
  157.             i = i + 1
  158.         end
  159.     end
  160.     return table.concat(char_table)
  161. end
  162.  
  163. function readwidestring(address, length)
  164.     address = type(address) == "number" and address or error "bad argument #1 to 'readwidestring' expected number, got '" .. type(address) .. "'"
  165.     if length then
  166.         length = type(length) == "number" and length or error "bad argument #2 to 'readwidestring' expected number, got '" .. type(length) .. "'"
  167.     else
  168.         length = length or 51001
  169.     end
  170.     local char_table = {}
  171.     local char = string.char
  172.     local word, dword, byte1, byte2, byte3, byte4
  173.     local i = 0
  174.     while i < length do
  175.         -- quickens write calls (screw you oxide for using virtualprotect)
  176.         if (length-i) >= 4 then
  177.             dword = readdword(address + i)
  178.  
  179.             byte1 = bit32.band(dword, 0xFF)
  180.             if byte1 == 255 or byte1 == 0 then break end
  181.             char_table[#char_table+1] = char(byte1)
  182.            
  183.             byte2 = bit32.band(bit32.rshift(dword, 8), 0xFF)
  184.             if byte2 ~= 255 or byte2 ~= 0 then break end
  185.            
  186.             byte3 = bit32.band(bit32.rshift(dword, 16), 0xFF)
  187.             if byte3 == 255 or byte3 == 0 then break end
  188.             char_table[#char_table+1] = char(byte3)
  189.            
  190.             byte4 = bit32.band(bit32.rshift(dword, 24), 0xFF)
  191.             if byte4 ~= 255 or byte4 ~= 0 then break end
  192.            
  193.             i = i + 4
  194.         else
  195.             word = readword(address + i)
  196.            
  197.             byte1 = bit32.band(word, 0xFF)
  198.             if byte1 == 255 or byte1 == 0 then break end
  199.             char_table[#char_table+1] = char(byte1)
  200.            
  201.             byte2 = bit32.band(bit32.rshift(word, 8), 0xFF)
  202.             if byte2 ~= 255 or byte2 ~= 0 then break end
  203.            
  204.             i = i + 2
  205.         end
  206.     end
  207.     return table.concat(char_table)
  208. end
  209.  
  210. local function writestring(address, offset, str)
  211.     address = type(address) == "number" and address or error "bad argument #1 to 'writestring' expected number, got '" .. type(address) .. "'"
  212.     if str then
  213.         offset = type(offset) == "number" and offset or error "bad argument #2 to 'writestring' expected number, got '" .. type(offset) .. "'"
  214.         str = type(str) == "string" and str or error "bad argument #3 to 'writestring' expected string, got '" .. type(str) .. "'"
  215.     else
  216.         str = type(offset) == "string" and offset or error "bad argument #2 to 'writestring' expected string, got '" .. type(offset) .. "'"
  217.         offset = nil
  218.     end
  219.     address = address + (offset or 0x0)
  220.     local byte_table = {}
  221.     local byte = string.byte
  222.     for char in string.gmatch(str, '.') do
  223.         byte_table[#byte_table+1] = byte(char)
  224.     end
  225.     local length = #byte_table
  226.     local i = 0
  227.     while i < length do
  228.         -- quickens write calls (screw you oxide for using virtualprotect)
  229.         if (length-i) >= 4 then
  230.             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))
  231.             i = i + 4
  232.         elseif (length-i) >= 2 then
  233.             writeword(address + i, tonumber(string.format("%02X%02X", byte_table[i+2], byte_table[i+1]), 16))
  234.             i = i + 2
  235.         else
  236.             writebyte(address + i, byte_table[i+1])
  237.             i = i + 1
  238.         end
  239.     end
  240. end
  241.  
  242. local function writewidestring(address, offset, str)
  243.     address = type(address) == "number" and address or error "bad argument #1 to 'writewidestring' expected number, got '" .. type(address) .. "'"
  244.     if str then
  245.         offset = type(offset) == "number" and offset or error "bad argument #2 to 'writewidestring' expected number, got '" .. type(offset) .. "'"
  246.         str = type(str) == "string" and str or error "bad argument #3 to 'writewidestring' expected string, got '" .. type(str) .. "'"
  247.     else
  248.         str = type(offset) == "string" and offset or error "bad argument #2 to 'writewidestring' expected string, got '" .. type(offset) .. "'"
  249.         offset = nil
  250.     end
  251.     address = address + (offset or 0x0)
  252.     local byte_table = {}
  253.     local byte = string.byte
  254.     for char in string.gmatch(str, '.') do
  255.         byte_table[#byte_table+1] = byte(char)
  256.     end
  257.     local length = #byte_table
  258.     while i < length do
  259.         -- quickens write calls (screw you oxide for using virtualprotect)
  260.         if i % 4 == 0 and length - i >= 4 then
  261.             writedword(address + i, tonumber((byte_table[i+2]*100) .. (byte_table[i+1]*100)))
  262.             i = i + 2
  263.         else
  264.             writeword(address + i, byte_table[i+1])
  265.             i = i + 1
  266.         end
  267.     end
  268. end
  269.  
  270. -- Local variables defined for decreased execution time (and also to organize what is using the global environment)
  271. local io, tostring, tonumber, next, type, os, select = io, tostring, tonumber, next, type, os, select
  272. local sub, gsub, find, lower, format, match = string.sub, string.gsub, string.find, string.lower, string.format, string.match
  273. local insert, remove, concat = table.insert, table.remove, table.concat
  274. local ceil, floor = math.ceil, math.floor
  275.  
  276.     -- Table Management
  277. local TM = setmetatable({
  278.         unused_tables = {},
  279.         __gc = function(self) self.unused_tables[#self.unused_tables+1] = self end,
  280.         __tostring = function(t)
  281.             local tableStr = "table { "
  282.             if next(t) then
  283.                 for k,v in next,t do
  284.                     if v == t then goto nextVal end
  285.                     k = type(k) == "string" and '"' .. k .. '"' or k
  286.                     v = type(v) == "string" and '"' .. v .. '"' or tostring(v)
  287.                     tableStr = tableStr .. (k .. " => ") .. v .. ", "
  288.                     ::nextVal::
  289.                 end
  290.                
  291.                 tableStr = sub(tableStr, 1, #tableStr-2) .. " }"
  292.             else
  293.                 tableStr = tableStr .. " }"
  294.             end
  295.             return tableStr
  296.         end,
  297.         deleteEntries = function(t)
  298.             for key,_ in next,t do
  299.                 t[key] = nil
  300.             end
  301.             return t
  302.         end
  303.     },
  304.     {
  305.         __call = function(TM, t)
  306.             local mt = getmetatable(t)
  307.             if mt then
  308.                 mt.__index = TM
  309.                 return t
  310.             else
  311.                 return setmetatable(t, TM)
  312.             end
  313.         end
  314.     }
  315. )
  316. TM.__index = TM
  317.  
  318. local function getobject(objId)
  319.     return objId and _G.getobject(objId)
  320. end
  321.  
  322.     -- Tables
  323. local access_table = {}
  324. local addresses
  325. local admin_table = {}
  326. local ban_table = {}
  327. local ban_penalty = {}
  328. local bos_table = {}
  329. local Commands = TM{commandAliases = TM{}}
  330. Commands.__index = Commands -- class setup
  331. local commandAliases = Commands.commandAliases
  332.  
  333. local cmdreply = setmetatable({index = 0}, {
  334.     __mode = "v", -- weak table
  335.     __len = function(self) return (rawget(self, "index") or 0) end,
  336.     __call = function(self, bResetAll)
  337.         if not bResetAll then
  338.             local index = rawget(self, "index") + 1
  339.             rawset(self, "index", index)
  340.             return index
  341.         end
  342.         rawset(self, "header", nil)
  343.         rawset(self, "align", nil)
  344.         rawset(self, "delim", nil)
  345.         rawset(self, "separator", nil)
  346.         rawset(self, "index", 0)
  347.     end
  348. })
  349. -- Default Scripted Game Variables
  350. local defaults = {
  351.     kickbans_file = "KicksAndBans",
  352.     commands_file = "commands",
  353.     admin_file = "admins",
  354.     banlist_file = "banned",
  355.     sharedhash_file = "sharedhashes",
  356.     ban_penalty = "5m 1d 10d",
  357.     --tkban_type = "ip",
  358.     adminblocker = 0,
  359.     anticaps = false,
  360.     antispam = "players",
  361.     chatcommands = true,
  362.     chatids = true,
  363.     crouch_camo = false,
  364.     deathless = false,
  365.     falldamage = true,
  366.     firstjoin_message = true,
  367.     hash_duplicates = true,
  368.     infinite_ammo = false,
  369.     killing_spree = true,
  370.     multiteam_vehicles = false,
  371.     noweapons = false,
  372.     pm_enabled = true,
  373.     respawn_time = false,
  374.     rtv_enabled = true,
  375.     rtv_required = 50,
  376.     rtv_timeout = 120,
  377.     sa_message = true,
  378.     scrim_mode = false,
  379.     spam_max = 7,
  380.     spam_timeout = 60,
  381.     tbag_detection = true,
  382.     uniques_enabled = true,
  383.     votekick_enabled = true,
  384.     votekick_action = "kick",
  385.     votekick_required = 70,
  386.     votekick_timeout = 120,
  387.     wb_message = true
  388. }
  389. local ip_table = setmetatable(TM{}, TM{
  390.     __call = function(ip_table, ip, bScriptReloadNeedMuteCheck)
  391.         local iptable = TM.New()
  392.         iptable.disarmed = false
  393.        
  394.         iptable.tempadmin = false
  395.         iptable.spamcounter = 0
  396.         iptable.rcon_fails = 0
  397.         iptable.rconfail_timer = 0
  398.        
  399.         if bScriptReloadNeedMuteCheck then
  400.             local ban_entry
  401.             for id = 1,#ban_table do ban_entry = ban_table[id]
  402.                 if ban_entry.time ~= "Unbanned" and ban_entry.type == "chat" and netMatch(ban_entry.ip, ip) then
  403.                     iptable.muted = true
  404.                     break
  405.                 end
  406.             end
  407.         else
  408.             iptable.muted = false
  409.         end
  410.         ip_table[ip] = iptable
  411.         return iptable
  412.     end
  413. })
  414. local leave_table = TM{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}
  415. local locations = TM{} -- map = {locname = {x, y, z}}
  416. local spawnWeapons = TM{}
  417. local tag_table = TM{}
  418. local objects = TM{}
  419. local player_table = setmetatable(TM{[0] = TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}, TM{drones = TM{}, weapons = TM{}}},
  420. TM{
  421.     __call = function(player_table, playerId)
  422.         local ptable = player_table[playerId]
  423.        
  424.         ptable.hash = gethash(playerId)
  425.         ptable.ip = getip(playerId)
  426.         ptable.admin_entry = admin_table[ptable.hash]
  427.         for index,thisAdmin in next,admin_table do
  428.             if thisAdmin.type == "ip" and netMatch(index, ptable.ip) and (ptable.admin_entry and ptable.admin_entry.level > thisAdmin.level or not ptable.admin_entry) then
  429.                 ptable.admin_entry = thisAdmin
  430.                 break
  431.             end
  432.         end
  433.        
  434.         ptable.afk = false
  435.         ptable.bulletmode = false
  436.         ptable.colorspawn = false
  437.         ptable.crouch = false
  438.         ptable.drones = ptable.drones and ptable.drones:deleteEntries() or TM.New()
  439.         ptable.dmgmultiplier = 1
  440.         ptable.name = getname(playerId)
  441.         ptable.godmode = false
  442.         ptable.ghostmode = false
  443.         ptable.invisible = false
  444.         ptable.hidden = false
  445.         ptable.objspawnid = false
  446.         ptable.player_struct = getplayer(playerId)
  447.         ptable.objectId = getplayerobjectid(playerId)
  448.         ptable.object_struct = getobject(ptable.objectId)
  449.         ptable.vehicleObjId = ptable.object_struct and readdword(ptable.object_struct + 0x11C) or 0xFFFFFFFF
  450.         ptable.m_vehicleObj = getobject(ptable.vehicleObjId)
  451.         ptable.playerIndex = resolveplayer(playerId)
  452.         ptable.tbagname = ""
  453.         ptable.x,ptable.y,ptable.z = 0,0,0
  454.         return ptable
  455.     end
  456. })
  457. local randomNames = TM{"Butcher", "Caboose", "Crazy", "Cupid", "Darling", "Dasher", "Disco", "Donut", "Dopey", "Ghost", "Goat", "Grumpy", "Hambone", "Hollywood", "Howard", "Jack", "Killer", "King", "Mopey", "Noodle", "Penguin", "Pirate", "Prancer", "Saucy", "Shadow", "Sleepy", "Snake", "Sneak", "Stompy", "Stumpy", "The Bear", "The Big L", "Tooth", "Walla Walla", "Weasel", "Wheezy", "Whicker", "Whisp", "Wilshire"}
  458. local rcon_passwords = TM{}
  459. local sharedhashes = TM{
  460.     "f443106bd82fd6f3c22ba2df7c5e4094",
  461.     "c702226e783ea7e091c0bb44c2d0ec64",
  462.     "d72b3f33bfb7266a8d0f13b37c62fddb",
  463.     "55d368354b5021e7dd5d3d1525a4ab82",
  464.     "3d5cd27b3fa487b040043273fa00f51b",
  465.     "b661a51d4ccf44f5da2869b0055563cb",
  466.     "740da6bafb23c2fbdc5140b5d320edb1",
  467.     "10440b462f6cbc3160c6280c2734f184",
  468.     "7503dad2a08026fc4b6cfb32a940cfe0",
  469.     "4486253cba68da6786359e7ff2c7b467",
  470.     "f1d7c0018e1648d7d48f257dc35e9660",
  471.     "40da66d41e9c79172a84eef745739521",
  472.     "2863ab7e0e7371f9a6b3f0440c06c560",
  473.     "34146dc35d583f2b34693a83469fac2a",
  474.     "b315d022891afedf2e6bc7e5aaf2d357",
  475.     "81f9c914b3402c2702a12dc1405247ee",
  476.     "63bf3d5a51b292cd0702135f6f566bd1",
  477.     "6891d0a75336a75f9d03bb5e51a53095",
  478.     "325a53c37324e4adb484d7a9c6741314",
  479.     "0e3c41078d06f7f502e4bb5bd886772a",
  480.     "fc65cda372eeb75fc1a2e7d19e91a86f",
  481.     "f35309a653ae6243dab90c203fa50000",
  482.     "50bbef5ebf4e0393016d129a545bd09d",
  483.     "a77ee0be91bd38a0635b65991bc4b686",
  484.     "3126fab3615a94119d5fe9eead1e88c1",
  485.     "d41d8cd98f00b204e9800998ecf8427e"
  486. }
  487. local unique_table = TM(setmetatable({total = 0}, TM{__len = function(self) return self.total end}))
  488. local valid_maps = TM{}
  489. local valid_gametypes = TM{}
  490.  
  491. -- Get Unused Table if available.
  492. function TM.New()
  493.    
  494.     local unused_tables = TM.unused_tables
  495.     local length = #unused_tables
  496.     local t = unused_tables[length]
  497.     if t then
  498.         -- use an unused table
  499.         unused_tables[length] = nil
  500.         t:deleteEntries()
  501.     else
  502.         -- no tables available, make a new one
  503.         t = setmetatable({}, TM)
  504.     end
  505.  
  506.     return t
  507. end
  508.  
  509. -- Memoize Code.
  510. local globalCache = TM.New()
  511.  
  512. local function getCallMetamethod(f)
  513.     if type(f) ~= 'table' then return nil end
  514.     local mt = getmetatable(f)
  515.     return type(mt)=='table' and mt.__call
  516. end
  517.  
  518. local function resetCache(f, call)
  519.     globalCache[f] = TM{ results = TM.New(), children = TM.New(), call = call or getCallMetamethod(f) }
  520. end
  521.  
  522. local function getCacheNode(cache, args)
  523.     local node = cache
  524.     local arg
  525.     for i = 1,#args do arg = args[i]
  526.         node = node.children[--[[type(arg) == "table" and concat(arg, "", 1, #arg) or--]] arg]
  527.         if not node then return nil end
  528.     end
  529.     return node
  530. end
  531.  
  532. local function getOrBuildCacheNode(cache, args)
  533.     local node = cache
  534.     local arg
  535.     for i = 1,#args do arg = args[i]
  536.         --arg = type(arg) == "table" and concat(arg, "", 1, #arg) or arg
  537.         node.children[arg] = node.children[arg] or TM{ children = TM.New() }
  538.         node = node.children[arg]
  539.     end
  540.     return node
  541. end
  542.  
  543. local function getFromCache(cache, args)
  544.     local node = getCacheNode(cache, args)
  545.     return node and node.results or TM.New()
  546. end
  547.  
  548. local function insertInCache(cache, args, results)
  549.     local node = getOrBuildCacheNode(cache, args)
  550.     node.results = results
  551. end
  552.  
  553. local function resetCacheIfMetamethodChanged(t)
  554.     local call = getCallMetamethod(t)
  555.     assert(type(call) == "function", "The __call metamethod must be a function")
  556.     if globalCache[t].call ~= call then
  557.         resetCache(t, call)
  558.     end
  559. end
  560.  
  561. local function buildMemoizedFunction(f)
  562.     local tf = type(f)
  563.     return function (...)
  564.         if tf == "table" then resetCacheIfMetamethodChanged(f) end
  565.  
  566.         local results = getFromCache( globalCache[f], TM{...} )
  567.  
  568.         if #results == 0 then
  569.             results = TM{ f(...) }
  570.             insertInCache(globalCache[f], TM{...}, results)
  571.         end
  572.        
  573.         return table.unpack(results)
  574.     end
  575. end
  576.  
  577. local function isCallable(f)
  578.     local tf = type(f)
  579.     if tf == 'function' then return true end
  580.     if tf == 'table' then
  581.         return type(getCallMetamethod(f))=="function"
  582.     end
  583.     return false
  584. end
  585.  
  586. local function assertCallable(f)
  587.     assert(isCallable(f), "Only functions and callable tables are admitted on memoize. Received " .. tostring(f))
  588. end
  589.  
  590. local function memoize(f)
  591.     assertCallable(f)
  592.     resetCache(f)
  593.     return buildMemoizedFunction(f)
  594. end
  595.  
  596. -- fixes a phasor bug where player 1 gets output from hprintf in their console...
  597. local function privatesay(message, playerId)
  598.     _G.privatesay(message, playerId)
  599.     if getplayer(0) then
  600.         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 ")
  601.     end
  602. end
  603.  
  604. local function getname(playerId)
  605.     return playerId and player_table[playerId].name or "the Server"
  606. end
  607.  
  608. local function gethash(playerId)
  609.     return playerId and player_table[playerId].hash or nil
  610. end
  611.  
  612. local function getip(playerId)
  613.     return playerId and player_table[playerId].ip or nil
  614. end
  615.  
  616. local function getplayer(playerId)
  617.     return playerId and player_table[playerId].player_struct or nil
  618. end
  619.  
  620. local function GetGameAddresses(game)
  621.  
  622.     if game == "PC" then
  623.         addresses = {
  624.             stats_header = 0x639720,
  625.             stats_globals = 0x639898,
  626.             ctf_globals = 0x639B98,
  627.             slayer_globals = 0x63A0E8,
  628.             oddball_globals = 0x639E58,
  629.             koth_globals = 0x639BD0,
  630.             race_globals = 0x639FA0,
  631.             race_locs = 0x670F40,
  632.             map_pointer = 0x63525C,
  633.             gametype_base = 0x671340,
  634.             network_struct = 0x745BA0,
  635.             camera_base = 0x69C2F8,
  636.             player_header_pointer = 0x75ECE4,
  637.             obj_header_pointer = 0x744C18,
  638.             collideable_objects_pointer = 0x744C34,
  639.             map_header_base = 0x630E74,
  640.             banlist_header = 0x641280,
  641.             game_globals = "???", -- (???) Why do I not have this for PC?
  642.             gameinfo_header = 0x671420,
  643.             mapcycle_header = 0x614B4C,
  644.             network_server_globals = 0x69B934,
  645.             sockaddr_pointer = 0x6A1F08,
  646.             flags_pointer = 0x6A590C,
  647.             hash_table_base = 0x6A2AE4,
  648.  
  649.             -- String/Data Addresses.
  650.             init_file_address = 0x8EB38,
  651.             broadcast_version_address = 0x5DF840,
  652.             version_info_address = 0x5E02C0,
  653.             broadcast_game_address = 0x5E4768,
  654.             public_value_address = 0x6164C0,
  655.             server_port_address = 0x625230,
  656.             timelimit_address = 0x626630,
  657.             server_path_address = 0x62C390,
  658.             computer_name_address = 0x62CD60,
  659.             profile_path_address = 0x635610,
  660.             map_name_address = 0x63BC78,
  661.             computer_specs_address = 0x662D04,
  662.             map_name_address2 = 0x698F21,
  663.             server_password_address = 0x69B93C,
  664.             banlist_path_address = 0x69B950,
  665.             rcon_password_address = 0x69BA5C,
  666.  
  667.             --Patches
  668.             special_chars_patch = 0x517D6B,
  669.             gametype_patch = 0x481F3C,
  670.             color_patch = 0x4828FE,
  671.             devmode_patch1 = 0x4A4DBF,
  672.             devmode_patch2 = 0x4A4E7F,
  673.             hash_duplicate_patch = 0x59C516,
  674.             gametype_patch = 0x481F3C, -- I 'thought' this worked but haven't tested in ages.
  675.             hashcheck_patch = 0x59c280,
  676.             servername_patch = 0x517D6B,
  677.             versioncheck_patch = 0x5152E7
  678.         }
  679.     elseif game == "CE" then
  680.         addresses = {
  681.             -- Structs/headers.
  682.             stats_header = 0x5BD740,
  683.             stats_globals = 0x5BD8B8,
  684.             ctf_globals = 0x5BDBB8,
  685.             slayer_globals = 0x5BE108,
  686.             oddball_globals = 0x5BDE78,
  687.             koth_globals = 0x5BDBF0,
  688.             race_globals = 0x5BDFC0,
  689.             race_locs = 0x5F5098,
  690.             map_pointer = 0x5B927C,
  691.             gametype_base = 0x5F5498,
  692.             network_struct = 0x6C7980,
  693.             camera_base = 0x62075C,
  694.             player_globals = 0x6E1478, -- From OS.
  695.             player_header_pointer = 0x6E1480,
  696.             obj_header_pointer = 0x6C69F0,
  697.             collideable_objects_pointer = 0x6C6A14,
  698.             map_header_base = 0x6E2CA4,
  699.             banlist_header = 0x5C52A0,
  700.             game_globals = 0x61CFE0, -- (???)
  701.             gameinfo_header = 0x5F55BC,
  702.             mapcycle_header = 0x598A8C,
  703.             network_server_globals = 0x61FB64,
  704.             sockaddr_pointer = 0x626388,
  705.             hash_table_base = 0x5AFB34,
  706.            
  707.             -- String/Data Addresses.
  708.             init_file_address = 0x8EB26,
  709.             broadcast_version_address = 0x564B34,
  710.             version_info_address = 0x565104,
  711.             broadcast_game_address = 0x569EAC,
  712.             public_value_address = 0x59A424,
  713.             server_port_address = 0x5A91A0,
  714.             timelimit_address = 0x5AA5B0,
  715.             server_path_address = 0x5B0670,
  716.             computer_name_address = 0x5B0D40,
  717.             profile_path_address = 0x5B9630,
  718.             map_name_address = 0x5BFC98,
  719.             computer_specs_address = 0x5E6E5C,
  720.             map_name_address2 = 0x61D151,
  721.             server_password_address = 0x61FB6C,
  722.             banlist_path_address = 0x61FB80,
  723.             rcon_password_address = 0x61FC8C,
  724.            
  725.             --Patches
  726.             special_chars_patch = 0x4CE0CD,
  727.             gametype_patch = 0x45E50C,
  728.             color_patch = 0x45EB5E,
  729.             devmode_patch1 = 0x47DF0C,
  730.             devmode_patch2 = 0x47DFBC,
  731.             hash_duplicate_patch = 0x5302E6,
  732.             hashcheck_patch = 0x530130,
  733.             servername_patch = 0x4CE0CD,
  734.             versioncheck_patch = 0x4CB587,
  735.         }
  736.     end
  737. end
  738.  
  739. -- This is my ingenius way to execute a command and bypass ALL of my code.
  740. -- So I can do sv_kick without having to worry about creating an infinite loop.
  741. local function halo_svcmd(command, retBool)
  742.     dont_call_onservercommand = true
  743.     --print "BEFORE HALO_SVCMD"
  744.     local response = svcmd(command, retBool)
  745.     --print "AFTER HALO_SVCMD"
  746.     dont_call_onservercommand = false
  747.     return retBool and response
  748. end
  749.  
  750. local function halo_svcmdplayer(command, playerId, retBool)
  751.     dont_call_onservercommand = true
  752.     --print "BEFORE HALO_SVCMDPLAYER"
  753.     local response = svcmdplayer(command, playerId, retBool)
  754.     --print "AFTER HALO_SVCMDPLAYER"
  755.     dont_call_onservercommand = false
  756.     return retBool and response
  757. end
  758.  
  759. local function svcmd(command, retBool)
  760.     --print "BEFORE SVCMD"
  761.     if OnServerCommandAttempt(nil, command) ~= false then
  762.         --print "AFTER SVCMD"
  763.         return _G.svcmd(command, retBool)
  764.     end
  765. end
  766.  
  767. local function svcmdplayer(command, playerId, retBool)
  768.     --print "BEFORE SVCMDPLAYER"
  769.     if OnServerCommandAttempt(playerId, command) ~= false and OnServerCommand(playerId, command) ~= false then
  770.         --print "AFTER SVCMDPLAYER"
  771.         return halo_svcmd(command, retBool)
  772.     end
  773. end
  774.  
  775.  
  776. math.randomseed(ceil(os.clock()) + os.time())
  777. local getsuckyrand = math.random
  778. getsuckyrand(1, 10) getsuckyrand(1, 10) getsuckyrand(1, 10)
  779. --Low and High are INCLUSIVE.
  780. local function rand(low, high)
  781.    
  782.     low = tonumber(low) or error("Bad argument #1 to 'rand' (number expected, got " .. type(low) .. ")")
  783.     high = tonumber(high) or error("Bad argument #2 to 'rand' (number expected, got " .. type(high) .. ")")
  784.    
  785.     return getsuckyrand(low, high)
  786. end
  787. local getrandomnumber = math.rand
  788.  
  789. local function setspeed(playerId, speed)
  790.     local m_player = getplayer(playerId) or error("bad argument #1 to 'setspeed' expected valid playerId, got '" .. type(playerId) .. "'")
  791.     speed = tonumber(speed) or error("bad argument #2 to 'setspeed' expected number, got '" .. type(speed) .. "'")
  792.     writefloat(getplayer(playerId) + 0x6C, speed and speed < 999999999999999999999999999999 and speed or 999999999999999999999999999999)
  793. end
  794.  
  795. -- This local function gets the playerId's memory ID from their object struct
  796. -- Accepts the object ID of the playerId as an argument
  797. -- Returns the playerId, or nil.
  798. local function objectidtoplayer(objectId)
  799.     local m_object = getobject(objectId)
  800.     if m_object then
  801.         local playerId = readword(m_object + 0xC0)
  802.         local m_player = _G.getplayer(playerId)
  803.         if m_player then
  804.             return playerId
  805.         end
  806.     end
  807. end
  808. objectidtoplayer = memoize(objectidtoplayer) -- memoized
  809.  
  810. -- I am having weird issues with resolveplayer not working correctly, so I'm overriding it.
  811. local function resolveplayer(playerId)
  812.     return playerId and player_table[playerId].playerIndex
  813. end
  814.  
  815. -- This function will get the XYZ coordinates of an object, and return them as 3 separate variables.
  816. -- It will also determine if the object has a parent (i.e player in a vehicle) and return those coords instead.
  817. -- I don't trust Phasor's getobjectcoords, and this way I know exactly how it will work.
  818. function getobjectcoords(objectId)
  819.     local m_object = getobject(objectId)
  820.     local vehicleObjId = readdword(m_object + 0x11C)
  821.     local m_vehicleObj = getobject(vehicleObjId)
  822.    
  823.     -- Replace m_object with vehicle object struct (if there is one)
  824.     m_object = m_vehicleObj or m_object
  825.  
  826.     return readfloat(m_object + 0x5C),readfloat(m_object + 0x60),readfloat(m_object + 0x64)
  827. end
  828.  
  829. local function getplayerobjectid(playerId)
  830.     return playerId and player_table[playerId].objectId or 0xFFFFFFFF
  831. end
  832.  
  833. local function getplayerobject(playerId)
  834.     local ptable = playerId and player_table[playerId]
  835.     return (ptable and ptable.object_struct or nil), (ptable and ptable.objectId or 0xFFFFFFFF)
  836. end
  837.  
  838. -- Gets the object ID of the player's vehicle.
  839. -- Accepts argument 'playerId' (memory ID), object_struct
  840. -- Returns the vehicle's object ID, or nil
  841. local function getplayervehicleid(playerId)
  842.     return playerId and player_table[playerId].vehicleObjId or 0xFFFFFFFF
  843. end
  844.  
  845. -- This is the same as getplayervehicleid except it returns BOTH the vehicle's object struct and vehicleObjId.
  846. -- Returns the vehicle's object struct and vehicle's object ID, or nil.
  847. local function getplayervehicle(playerId)
  848.     local ptable = playerId and player_table[playerId]
  849.     return (ptable and ptable.m_vehicleObj or nil), (ptable and ptable.vehicleObjId or 0xFFFFFFFF)
  850. end
  851.  
  852. -- Gets the object ID of the player's weapon.
  853. -- Accepts arguments 'playerId' (memory ID) and 'slot' (weapon slot) which is a number from 0 to 3.
  854. -- and object_struct, object_id, and player_struct (for efficiency)
  855. -- Slot is an optional argument. If not passed, then getplayerweaponid returns player's current weapon ID.
  856. -- Returns the weapon's object ID, or 0xFFFFFFFF if no weapon, or nil if the player is dead
  857. local function getplayerweaponid(playerId, slot)
  858.    
  859.     m_playerObj = m_playerObj or getplayerobject(playerId, slot)
  860.    
  861.     if not m_playerObj then
  862.         return
  863.     end
  864.    
  865.     -- Return vehicle's weapon if they are in a vehicle.
  866.     local m_vehicleObj = getplayervehicle(playerId)
  867.     if m_vehicleObj then
  868.         return readdword(m_vehicleObj + 0x2F8)
  869.     end
  870.    
  871.     -- Return current weapon if no slot passed.
  872.     if not slot then
  873.         return readdword(m_playerObj + 0x118)
  874.     end
  875.    
  876.     -- Return weapon at the specified slot.
  877.     return readdword(m_playerObj + 0x2F8 + slot*4)
  878. end
  879.  
  880. -- This is the same as getplayerweaponid except it returns BOTH the weapon's object struct and weaponObjId.
  881. -- Returns the weapon's object struct and weapon's object ID, or nil.
  882. local function getplayerweapon(playerId, slot)
  883.     local weaponObjId = getplayerweaponid(playerId, slot)
  884.     return getobject(weaponObjId), weaponObjId
  885. end
  886.  
  887. local function cleanupdrones(playerId)
  888.     local ptable = player_table[playerId]
  889.     local vehicleObjId
  890.     for i = 1,#ptable.drones do vehicleObjId = ptable.drones[i]
  891.         if getobject(vehicleObjId) then
  892.             destroyobject(vehicleObjId)
  893.         end
  894.         ptable.drones[i] = nil
  895.     end
  896. end
  897.  
  898. --[[ General lua functions ]]--
  899.  
  900. local function round(val, place)
  901.     place = place or 0 return floor(val * (10 ^ place) + 0.5) * (10 ^ -place)
  902. end
  903.  
  904. local function formatTime(time)
  905.     time = tonumber(time)
  906.     if time == -1 then
  907.         return "--"
  908.     elseif time then
  909.         local temp = time
  910.         local centuries = floor(temp / 3153600000)
  911.         temp = temp - centuries * 3153600000
  912.         local years = floor(temp / 31536000)
  913.         temp = temp - years * 31536000
  914.         local weeks = floor(temp / 604800)
  915.         temp = temp - weeks * 604800
  916.         local days = floor(temp / 86400)
  917.         temp = temp - days * 86400
  918.         local hours = floor(temp / 3600)
  919.         temp = temp - hours * 3600
  920.         local minutes = floor(temp / 60)
  921.         temp = temp - minutes * 60
  922.         local seconds = floor(temp)
  923.         return format("%02d:%02d:%02d:%02d:%02d:%02d", years, weeks, days, hours, minutes, seconds)
  924.     else
  925.         return time
  926.     end
  927. end
  928. formatTime = memoize(formatTime) -- memoized
  929.  
  930. local function wordtotime(timeStr, bancount)
  931.     local length = #timeStr
  932.     local time
  933.    
  934.     -- Check if timeStr is in the correct format before we do anything.
  935.     if tonumber(sub(timeStr, 1, length-1)) and match(sub(timeStr, length, length), "[cywdhms]") then
  936.         time = 0
  937.         local num = ""
  938.         local holder, tempnum, char
  939.         for i = 1,length do
  940.             char = sub(timeStr, i, i)
  941.             if tonumber(char) then
  942.                 num = num .. char
  943.             else
  944.                 tempnum = tonumber(num)
  945.                 holder = 0
  946.                 holder = char == "s" and tempnum
  947.                 holder = char == "m" and tempnum * 60 or holder
  948.                 holder = char == "h" and tempnum * 3600 or holder
  949.                 holder = char == "d" and tempnum * 86400 or holder
  950.                 holder = char == "w" and tempnum * 604800 or holder
  951.                 holder = char == "y" and tempnum * 31536000 or holder
  952.                 holder = char == "c" and tempnum * 3153600000 or holder
  953.                 holder = holder or 1
  954.                 time = time + holder
  955.             end
  956.         end
  957.         if time > 0 then
  958.             return time, char
  959.         end
  960.     end
  961.     time = tonumber(timeStr)
  962.     if time == 0 and bancount then
  963.         return ban_penalty[bancount], "?"
  964.     elseif time then
  965.         return time, "*"
  966.     end
  967. end
  968. wordtotime = memoize(wordtotime) -- memoized
  969.  
  970. local function timetoword(time)
  971.     time = type(time) == "number" and time or tonumber(time)
  972.     if time then
  973.         local returntime = ""
  974.         local centuries = floor(time / 3153600000)
  975.         time = time - centuries * 3153600000
  976.         local years = floor(time / 31536000)
  977.         time = time - years * 31536000
  978.         local weeks = floor(time / 604800)
  979.         time = time - weeks * 604800
  980.         local days = floor(time / 86400)
  981.         time = time - days * 86400
  982.         local hours = floor(time / 3600)
  983.         time = time - hours * 3600
  984.         local minutes = floor(time / 60)
  985.         time = time - minutes * 60
  986.         local seconds = floor(time)
  987.        
  988.         returntime = seconds > 0 and (seconds == 1 and "1 second" or seconds .. " seconds") or returntime
  989.         returntime = minutes > 0 and (minutes == 1 and "1 minute" or minutes .. " minutes " .. returntime) or returntime
  990.         returntime = hours > 0 and (hours == 1 and "1 hour" or hours .. " hours " .. returntime) or returntime
  991.         returntime = days > 0 and (days == 1 and "1 day" or days .. " days " .. returntime) or returntime
  992.         returntime = weeks > 0 and (weeks == 1 and "1 week" or weeks .. " weeks " .. returntime) or returntime
  993.         returntime = years > 0 and (years == 1 and "1 year" or years .. " years " .. returntime) or returntime
  994.         returntime = centuries > 0 and (centuries == 1 and "1 century" or centuries .. " centuries " .. returntime) or returntime
  995.         return returntime or "0 seconds"
  996.     end
  997. end
  998. timetoword = memoize(timetoword) -- memoized
  999.  
  1000. local function getTimeAndReason(timeandreason, bancount)
  1001.     local words = tokenizecmdstring(timeandreason)
  1002.     local count = #words
  1003.    
  1004.     local time
  1005.     local reasons = TM.New()
  1006.    
  1007.     local timetypes_used = ""
  1008.     local word, addTime, timetype, reasons_started
  1009.     for i = 1,count do word = words[i]
  1010.         if not reasons_started then
  1011.             addTime, timetype = wordtotime(word)
  1012.             if timetype and (find(timetypes_used, timetype) or find(timetypes_used, "[%?%*]")) then
  1013.                 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"
  1014.             elseif addTime then
  1015.                 time = (time or 0) + addTime
  1016.                 if not find(timetypes_used, timetype) then
  1017.                     timetypes_used = timetypes_used .. timetype
  1018.                 end
  1019.             else
  1020.                 reasons_started = true
  1021.                 reasons[#reasons+1] = word
  1022.             end
  1023.         else
  1024.             reasons[#reasons+1] = word
  1025.         end
  1026.     end
  1027.     return (time or -1), (reasons[2] and concat(reasons, " ") or reasons[1] or "None Given")
  1028. end
  1029. getTimeAndReason = memoize(getTimeAndReason) -- memoized
  1030.  
  1031. local function gettag(type_or_id, tagname)
  1032.     if tagname then
  1033.         return tag_table[type_or_id] and tag_table[type_or_id][tagname] or nil
  1034.     elseif tag_table[type_or_id] then
  1035.         return tag_table[type_or_id].tag_class, tag_table[type_or_id].tag_name
  1036.     end
  1037. end
  1038.  
  1039. local function getObjType(objectId)
  1040.     local m_object = getobject(objectId)
  1041.     return m_object and readword(m_object + 0xB4) or nil
  1042. end
  1043. getObjType = memoize(getObjType) -- memoized
  1044.  
  1045. local function resetweapons(playerId)
  1046.     local m_playerObj, playerObjId = getplayerobject(playerId)
  1047.     if getplayerweapon(playerId) then return end
  1048.     local x,y,z = getobjectcoords(playerObjId)
  1049.     assignweapon(playerId, createobject(gettag("weap", "weapons\\pistol\\pistol"), 0, 60, false, x+1.0, y, z + 2.0))
  1050.     assignweapon(playerId, createobject(gettag("weap", "weapons\\assault rifle\\assault rifle"), 0, 60, false, x+1.0, y, z + 2.0))
  1051. end
  1052.  
  1053. local function ResetPlayer(playerId)
  1054.     local ptable = player_table[playerId]
  1055.     local iptable = ip_table[getip(playerId)]
  1056.     local m_playerObj, playerObjId = getplayerobject(playerId)
  1057.     if playerObjId ~= 0xFFFFFFFF then
  1058.         ptable.godmode = false
  1059.         cleanupdrones(playerId)
  1060.         resetweapons(playerId)
  1061.     end
  1062.     ptable.bulletmode = false
  1063.     iptable.disarmed = false
  1064.     ptable.dmgmultiplier = 1
  1065.     ptable.ghostmode = false
  1066.     ptable.hidden = false
  1067.     ptable.objspawnid = false
  1068.     --ptable.rcon_fails = 0 -- shouldn't reset this.. lol
  1069.     iptable.suspended = false
  1070. end
  1071.  
  1072.  
  1073. local function validate_ipv4(ip)
  1074.     if not ip then return nil end
  1075.     ip = gsub(gsub(ip, "[%s]*", ""), "x+", "*")
  1076.     local a,b,c,slash,d,finish = match(ip, "^([^%.]+)%.([^%.]*)%.?([^%./]*)%.?(/?)([^%.]*)()")
  1077.     a = a == "" and "*" or match(a or "", "[%d%*]+")
  1078.     b = b == "" and "*" or match(b or "", "[%d%*]+")
  1079.     c = c == "" and "*" or match(c or "", "[%d%*]+")
  1080.     slash = slash ~= ""
  1081.     d = d or ""
  1082.     --print("IP VALIDATION I:",a,b,c,d,slash,finish)
  1083.     if slash then
  1084.         if d:find("/") or not match(d, "[%d%*]+") then return false end -- can't have two slashes
  1085.         d = "0/"..d -- Alternate form 194.1.4/24
  1086.     else
  1087.         d = d == "" and "*" or match(d, "[%d%*/]+")
  1088.     end
  1089.    
  1090.     if not a or not b or not c then
  1091.         return false -- bad ip
  1092.     end
  1093.    
  1094.     local found,a2,b2,c2,d2 = match(ip, "(%-)(%d+)%.(%d*)%.?(%d*)%.?(%d*)%c*$", finish)
  1095.     --print("IP VALIDATION II:",found,a2,b2,c2,d2)
  1096.     if not found then
  1097.         if a2 and a ~= "" then return false end -- this should just never happen lol
  1098.         return format("%s.%s.%s.%s",a,b,c,d)
  1099.     elseif slash then
  1100.         return false -- can't have a slash, and a iplimit.. lol
  1101.     end
  1102.     a2 = a2 == "" and "*" or match(a2, "[%d%*]+")
  1103.     b2 = b2 == "" and "*" or match(b2, "[%d%*]+")
  1104.     c2 = c2 == "" and "*" or match(c2, "[%d%*]+")
  1105.     d2 = d2 == "" and "*" or match(d2, "[%d%*]+")
  1106.    
  1107.     if not a2 or not b2 or not c2 then
  1108.         return false -- bad ip
  1109.     end
  1110.    
  1111.     if c2:find("/") and d2:find("/") then return false end
  1112.     return format("%s.%s.%s.%s-%s.%s.%s.%s", a,b,c,d,a2,b2,c2,d2)
  1113. end
  1114. validate_ipv4 = memoize(validate_ipv4) -- memoized
  1115.  
  1116. local function check_ip(ip)
  1117.     local i = 1
  1118.     local octets = 1
  1119.     local octet = ""
  1120.     local err = ""
  1121.     local errors = 0
  1122.     local blocks = TM.New()
  1123.     local c, block
  1124.     while (i <= #ip + 1) do
  1125.         c = sub(ip, i, i)
  1126.         if c == "." or #ip+1 == i then
  1127.             octets = octets + 1
  1128.             block = tonumber(octet)
  1129.             if not block or block > 255 or block < 0 or octets > 5 then
  1130.                 errors = errors + 1
  1131.                 err = err .. " \f3>" .. (block or "?") .. "<\f8"
  1132.             else
  1133.                 blocks[#blocks + 1] = octet
  1134.                 err = err .. "\f0 " .. block .. "\f8"
  1135.             end
  1136.             octet = ""
  1137.         else
  1138.             octet = octet .. c
  1139.         end
  1140.         i = i + 1
  1141.     end
  1142.    
  1143.     local result = TM.New()
  1144.     result[1] = err
  1145.    
  1146.     if errors > 0 then
  1147.         return result
  1148.     end
  1149.    
  1150.     result[2] = blocks
  1151.     return result
  1152. end
  1153. check_ip = memoize(check_ip) -- memoized
  1154.  
  1155.  
  1156. local function ip2long(ip_addr)
  1157.     local blocks = check_ip(ip_addr)[2] or error("Invalid IP-Address. IP_ADDR: " .. tostring(ip_addr) .. "\r\nError: " .. check_ip(ip_addr)[1])
  1158.     local a = bit32.lshift(blocks[1], 24)
  1159.     local b = #blocks >= 2 and bit32.lshift(blocks[2], 16)
  1160.     local c = #blocks >= 3 and bit32.lshift(blocks[3], 8)
  1161.     if not b or not c then return nil end
  1162.     return bit32.bor(bit32.bor(a, b, c), blocks[4])
  1163. end
  1164. ip2long = memoize(ip2long) -- memoized
  1165.  
  1166. local function convertSign(num, maxSize)
  1167.     return num - bit32.band(num, maxSize)*2
  1168. end
  1169. convertSign = memoize(convertSign) -- memoized
  1170.  
  1171. local function long2ip(addr)
  1172.     addr = tonumber(addr) or error("Invalid 32-bit Long: " .. addr)
  1173.     local a = bit32.rshift(bit32.band(addr, bit32.lshift(0xFF, 24)), 24)
  1174.     local b = bit32.rshift(bit32.band(addr, bit32.lshift(0xFF, 16)), 16)
  1175.     local c = bit32.rshift(bit32.band(addr, bit32.lshift(0xFF, 8)), 8)
  1176.     local d = bit32.band(addr, 0xFF)
  1177.     return format("%i.%i.%i.%i", convertSign(a, 255), convertSign(b, 255), convertSign(c, 255), convertSign(d, 255))
  1178. end
  1179. long2ip = memoize(long2ip) -- memoized
  1180.  
  1181. function netMatch(network, ip)
  1182.    
  1183.     network = validate_ipv4(network)
  1184.     -- if no ip to check, then just validate the network.
  1185.     if not ip then return network end
  1186.     ip = validate_ipv4(ip)
  1187.    
  1188.     local orig_network = network
  1189.     if ip == network then
  1190.         --print("used network " .. network .. " for ip " .. ip)
  1191.         return network
  1192.     end
  1193.     network = gsub(network, ' ', '')
  1194.     if find(network, '*') then
  1195.         if find(network, '/') then
  1196.             network = tokenizestring(network, '/')[1]
  1197.         end
  1198.         local nCount
  1199.         network, nCount = gsub(network, '*', '*')
  1200.         network = gsub(network, '*', '0')
  1201.         if nCount == 1 then
  1202.             network = network .. '/24'
  1203.         elseif nCount == 2 then
  1204.             network = network .. '/16'
  1205.         elseif nCount == 3 then
  1206.             network = network .. '/8'
  1207.         elseif nCount > 3 then
  1208.             return network -- if *.*.*.*, then all, so matched
  1209.         end
  1210.     end
  1211.    
  1212.     if find(ip, '*') then
  1213.         if find(ip, '/') then
  1214.             ip = tokenizestring(ip, '/')[1]
  1215.         end
  1216.         local nCount
  1217.         ip, nCount = gsub(ip, '*', '*')
  1218.         ip = gsub(ip, '*', '0')
  1219.         if nCount == 1 then
  1220.             ip = ip .. '/24'
  1221.         elseif nCount == 2 then
  1222.             ip = ip .. '/16'
  1223.         elseif nCount == 3 then
  1224.             ip = ip .. '/8'
  1225.         elseif nCount > 3 then
  1226.             return ip -- if *.*.*.*, then all, so matched
  1227.         end
  1228.     end
  1229.  
  1230.     --print("from original network " .. orig_network .. ", used network " .. network .. " for " .. ip)
  1231.  
  1232.     local d = find(network, '-')
  1233.     if not d then
  1234.         local ip_arr = tokenizestring(network, "/")
  1235.         local network_long = ip2long(ip_arr[1])
  1236.         local mask = bit32.lshift(0xFFFFFFFF, (32 - (ip_arr[2] or 32)))
  1237.         local ip_arr2 = tokenizestring(ip, "/")
  1238.         local ip_long = ip2long(ip_arr2[1])
  1239.         local mask2 = bit32.lshift(0xFFFFFFFF, (32 - (ip_arr2[2] or 32)))
  1240.         return bit32.band(network_long, mask, mask2) == bit32.band(ip_long, mask, mask2)
  1241.     else
  1242.         local from = ip2long(sub(network, 1, d-1))
  1243.         local to = ip2long(sub(network, d+1))
  1244.         ip = ip2long(ip)
  1245.         return ip >= from and ip <= to
  1246.     end
  1247. end
  1248. netMatch = memoize(netMatch) -- memoized
  1249.  
  1250. local function loadBanFile(filename, bantype)
  1251.     local file = io.open(filename)
  1252.     if file then
  1253.         local t = TM.New()
  1254.         local b
  1255.         local pos, endline, timestr, formatBantype, unique_index, count
  1256.         for line in file:lines() do
  1257.        
  1258.             -- Sometimes a rand blank line appears in the file, let's make sure not to error for those
  1259.             if match(line, "%g%g%g+") and sub(line, 1, 1) ~= "#" then
  1260.            
  1261.                 -- create a new table for the ban entry if we need to (I love ternary operator too much)
  1262.                 b = TM.New()
  1263.            
  1264.                 -- A line can ONLY have the following format: Name, HashOrIp [, IP] [, Bancount [, Time [, Bantype]]]
  1265.                 -- The exception is namebans, which will always be: Name [, Bantype] where Bantype can only be the string 'name' and nothing else
  1266.                 -- Examples of valid chat bans:
  1267.                 --  123456789abcdef123456789abcdef,127.0.0.1
  1268.                 --  wizard,123456789abcdef123456789abcdef,127.0.0.1
  1269.                 --  wizard,123456789abcdef123456789abcdef,127.0.0.1,1
  1270.                 --  wizard,123456789abcdef123456789abcdef,127.0.0.1,1,--
  1271.                 --  wizard,123456789abcdef123456789abcdef,127.0.0.1,1,--,chat
  1272.                 --  wizard,123456789abcdef123456789abcdef,127.0.0.1,1,--,chat,he was spamming
  1273.                
  1274.                 -- First half: Match chatban (name,hash,ip) or hashban (name,hash) or nameban (name [,bantype])
  1275.                
  1276.                 -- if this matches then this is a chatban
  1277.                 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+),([^,]+)(.-)$")
  1278.                 b.ip = b.ip and (b.ip == "1.2.3.4" and b.ip or validate_ipv4(b.ip))
  1279.                 if b.hash and b.ip then
  1280.                     formatBantype = "chat"
  1281.                     unique_index = b.hash .. (b.ip or "") .. "chat"
  1282.                     goto ReadSecondHalf
  1283.                 end
  1284.                
  1285.                 -- this will match a hash ban
  1286.                 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+)(.*)$")
  1287.                 if b.hash then
  1288.                     formatBantype = "hash"
  1289.                     unique_index = b.hash .. "hash"
  1290.                     goto ReadSecondHalf
  1291.                 end
  1292.                
  1293.                 -- this will match an IP ban.
  1294.                 b.name,b.ip,endline = match(line, "^(.-[^,]?)[,]([^,]+)(.-)$")
  1295.                 b.ip = b.ip and validate_ipv4(b.ip)
  1296.                 if not b.ip then
  1297.                     b.name,b.ip,b.reason = match(line, "^(.-[^:]?):([^:]+)(.-)$")
  1298.                     b.ip = b.ip and validate_ipv4(b.ip)
  1299.                 end
  1300.                 if b.ip then
  1301.                     formatBantype = "ip"
  1302.                     unique_index = b.ip .. "ip"
  1303.                     goto ReadSecondHalf
  1304.                 end
  1305.                
  1306.                 -- and lastly this will match a name ban.
  1307.                 b.name,b.type = match(line, "^(.-[^,]?),?(%w-)")
  1308.                 if b.name then
  1309.                     formatBantype = "name"
  1310.                     unique_index = b.name .. "name"
  1311.                     goto ReadSecondHalf
  1312.                 end
  1313.                
  1314.                 error(filename .. " is formatted incorrectly! Line: " .. line)
  1315.  
  1316.                 ::ReadSecondHalf::
  1317.                 -- This part matches the rest of the line. Here are some examples that it will match (starting from the end of the string)
  1318.                 --                                                           (nothing here)
  1319.                 --      ,1                                                  ,(count)
  1320.                 --      ,5,--                                               ,(count),(infinite time)
  1321.                 --      ,2,2015-06-13 05:29:51,chat                         ,(count),(time),(bantype)
  1322.                 --      ,3,-1,chat,offensive language                       ,(count),(infinite time),(bantype),(reason)
  1323.  
  1324.                 if not b.reason and endline and endline ~= "" then
  1325.                     count,timestr,b.type,b.reason = match(endline, "^,(%d+),?(.*[^,]),?(%w*),?(.-)$")
  1326.                     b.reason = b.reason and b.reason ~= "" and b.reason
  1327.                
  1328.                 -- these don't exist in a nameban
  1329.                 elseif not b.type or b.type == "" then
  1330.                     b.count = nil
  1331.                     b.type = nil
  1332.                     b.reason = nil
  1333.                     timestr = nil
  1334.                 end
  1335.  
  1336.                 -- Check if the ban types are what they should be.
  1337.                 -- I try to make my code stop using tons of checks, but this is the one time where it actually needs them
  1338.                 b.type = b.type and b.type ~= "" and b.type
  1339.                 if b.type and b.type ~= formatBantype then
  1340.                     error(filename .. " is formatted incorrectly! expected bantype " .. formatBantype .. " instead got " .. tostring(b.type) .. " on line: " .. line)
  1341.                 elseif bantype and bantype ~= formatBantype then
  1342.                     error(filename .. " should only have '" .. bantype .. "' bans. Ban of type '" .. formatBantype .. "' was found in the line: " .. line)
  1343.                 else
  1344.                     b.type = formatBantype
  1345.                 end
  1346.                
  1347.                 if timestr then
  1348.                     -- Match the time.
  1349.                     -- Time format: YYYY-MM-DD HH:MM:SS
  1350.                     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)$")
  1351.                    
  1352.                     -- convert 'ban expiration date' to 'seconds remaining until ban expires'
  1353.                     if t.sec then
  1354.                         b.time = os.time(t)
  1355.                     -- else time will become -1 (infinite) or "Unbanned"
  1356.                     else
  1357.                         b.time = find(timestr, "Unbanned") and "Unbanned" or -1
  1358.                     end
  1359.                 -- time not specified in ban file, should be indefinite.
  1360.                 else
  1361.                     b.time = -1
  1362.                 end
  1363.                
  1364.                 if formatBantype ~= "name" then
  1365.                     count = tonumber(count)
  1366.                     b.count = count and count > 0 and count or 1
  1367.                 end
  1368.                
  1369.                 -- Make sure this entry hasn't already been added before we add it.
  1370.                 if not ban_table[unique_index] then
  1371.                     b.name = b.name == "" and "Unnamed" or b.name
  1372.                     ban_table[#ban_table+1] = b
  1373.                     ban_table[unique_index] = #ban_table
  1374.                 end
  1375.             end
  1376.         end
  1377.         file:close()
  1378.     end
  1379. end
  1380.  
  1381. local function updateBanFiles(bantype)
  1382.     -- write the bans to the banned.txt file
  1383.     -- Save all bans to banned.txt
  1384.     local writetbl = TM.New()
  1385.     local ban_entry
  1386.     local file = io.open(profilepath .. defaults.banlist_file .. ".txt", "w")
  1387.     for id = 1,#ban_table do ban_entry = ban_table[id]
  1388.         if ban_entry.type == "chat" then
  1389.             writetbl[#writetbl+1] = ban_entry.name..","..ban_entry.hash..","..(ban_entry.ip or "1.2.3.4")..","..ban_entry.count..","..(ban_entry.time == "Unbanned" and "Unbanned" or ban_entry.time == -1 and "--" or os.date("%Y-%m-%d %X", ban_entry.time))..","..ban_entry.type..(ban_entry.reason and (","..ban_entry.reason) or "")
  1390.         elseif ban_entry.type == "hash" then
  1391.             writetbl[#writetbl+1] = ban_entry.name .. "," .. ban_entry.hash .. "," .. ban_entry.count .. "," .. (ban_entry.time == "Unbanned" and "Unbanned" or ban_entry.time == -1 and "--" or os.date("%Y-%m-%d %X", ban_entry.time)) .. "," .. ban_entry.type..(ban_entry.reason and (","..ban_entry.reason) or "")
  1392.         elseif ban_entry.type == "ip" then
  1393.             writetbl[#writetbl+1] = ban_entry.name..","..ban_entry.ip..","..ban_entry.count..","..(ban_entry.time == "Unbanned" and "Unbanned" or ban_entry.time == -1 and "--" or os.date("%Y-%m-%d %X", ban_entry.time))..","..ban_entry.type..(ban_entry.reason and (","..ban_entry.reason) or "")
  1394.         elseif ban_entry.type == "name" then
  1395.             writetbl[#writetbl+1] = ban_entry.name..","..ban_entry.type..(ban_entry.reason and (","..ban_entry.reason) or "")
  1396.         end
  1397.     end
  1398.     file:write(concat(writetbl, "\n"))
  1399.     file:close()
  1400. end
  1401.  
  1402. local function updateAdminFiles()
  1403.     local file = io.open(profilepath .. defaults.admin_file .. ".txt", "w")
  1404.     local writetbl = TM.New()
  1405.     for index,admin_entry in next,admin_table do
  1406.         writetbl[#writetbl+1] = admin_entry.name .. "," .. index .. "," .. admin_entry.level .. "," .. admin_entry.type
  1407.     end
  1408.     file:write(concat(writetbl, "\n"))
  1409.     file:close()
  1410. end
  1411.  
  1412. local function loadAllAdminFiles()
  1413.     local timestamp = os.date "%Y_%m_%d_%H_%M_%S"
  1414.     local file = io.open(profilepath .. "admin.txt")
  1415.     if file then
  1416.         local name, hash, level
  1417.         for line in file:lines() do
  1418.        
  1419.             -- format the line (name, hash, level)
  1420.             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*$")
  1421.             if hash then
  1422.                 admin_table[hash] = TM{name = name, level = tonumber(level), type = "hash"}
  1423.             end
  1424.         end
  1425.         file:close()
  1426.         os.rename(profilepath .. "admin.txt", profilepath .. "old_admin_" .. timestamp .. ".txt")
  1427.     end
  1428.    
  1429.     -- Now stores IP admins as well.
  1430.     file = io.open(profilepath .. defaults.admin_file .. ".txt")
  1431.     if file then
  1432.         local name, hash, ip, level, admintype
  1433.         for line in file:lines() do
  1434.             -- format the line (name, hash, level)
  1435.             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+)")
  1436.             if hash then
  1437.                 admin_table[hash] = TM{name = name, level = tonumber(level), type = "hash"}
  1438.             else
  1439.                 -- format the line (name, hash, level, ip)
  1440.                 name, ip, level = match(line, "^(%w-),(%g-),(%d+)")
  1441.                 ip = validate_ipv4(ip)
  1442.                 if ip then
  1443.                     admin_table[ip] = TM{name = name, level = tonumber(level), type = "ip"}
  1444.                 else
  1445.                     error(defaults.admin_file .. ".txt is incorrectly formatted! Line: " .. line)
  1446.                 end
  1447.             end
  1448.         end
  1449.         file:close()
  1450.     end
  1451.    
  1452.     -- IP Admins now use admins.txt, but this is here for backwards compatibility.
  1453.     file = io.open(profilepath .. "ipadmins.txt")
  1454.     if file then
  1455.         local name, level, ip
  1456.         for line in file:lines() do
  1457.  
  1458.             -- format the line (name, hash, level, ip)
  1459.             name, ip, level = match(line, "^(%w-),(%g-),(%d+)%c*$")
  1460.             ip = validate_ipv4(ip)
  1461.             if ip then
  1462.                 admin_table[ip] = TM{name = name, level = tonumber(level), type = "ip"}
  1463.             end
  1464.         end
  1465.         file:close()
  1466.         os.rename(profilepath .. "ipadmins.txt", profilepath .. "old_ipadmins_" .. timestamp .. ".txt")
  1467.     end
  1468.  
  1469.     updateAdminFiles()
  1470. end
  1471.  
  1472. -- changes 'sv_myCommand' into 'thisCommand', '/thisCommand' into 'thisCommand', and '\thisCommand' into 'thisCommand'
  1473. local function getvalidformat(command)
  1474.     local sv_found, slash_found, both_found = sub(command, 1, 3), sub(command, 1, 1), sub(command, 1, 4)
  1475.     if sv_found == "sv_" then
  1476.         return gsub(sub(command, 4), "[_ ]", "")
  1477.     elseif slash_found == "\\" or slash_found == "/" then
  1478.         return gsub(sub(command, 2), "[_ ]", "")
  1479.     elseif both_found == "\\sv_" or both_found == "/sv_" then
  1480.         return gsub(sub(command, 5), "[_ ]", "")
  1481.     end
  1482.     return gsub(command, "[_ ]", "")
  1483. end
  1484. getvalidformat = memoize(getvalidformat) -- memoized
  1485.  
  1486. local function getaccess(playerId)
  1487.     local access
  1488.     if getplayer(playerId) then
  1489.         return player_table[playerId].admin_entry and player_table[playerId].admin_entry.level
  1490.     else
  1491.         access = true
  1492.     end
  1493.     return access
  1494. end
  1495.  
  1496. local function SelectRandomPlayer(team)
  1497.     local t = TM.New()
  1498.     local size = 0
  1499.     for i = 0,15 do
  1500.         if getplayer(i) and (not team or getteam(i) == team) then
  1501.             size = size + 1
  1502.             t[size] = i
  1503.         end
  1504.     end
  1505.     if size > 0 then
  1506.         return t[rand(1, size)]
  1507.     end
  1508. end
  1509.  
  1510. -- Origstring is the string to search in, wild is the string to search for.
  1511. local function wildstring(origstring, wild, case_sensative)
  1512.  
  1513.     -- If not case sensitive then make all arguments lowercase.
  1514.     if not case_sensative then
  1515.         origstring, wild = lower(origstring), lower(wild)
  1516.     end
  1517.    
  1518.     wild = gsub(wild, "?", ".")
  1519.     wild = gsub(wild, "*", ".*")
  1520.     origstring = gsub(origstring, " ", "_")
  1521.     wild = gsub(wild, " ", "_")
  1522.    
  1523.     --[[say "-----"
  1524.     say(origstring)
  1525.     say(wild)--]]
  1526.    
  1527.     local found = match(origstring, wild)
  1528.     --say(tostring(found))
  1529.     if found and #found == #origstring then
  1530.         return true
  1531.     end
  1532.     return false
  1533. end
  1534. wildstring = memoize(wildstring) -- memoized
  1535.  
  1536. local function getvalidplayers(expression, playerId)
  1537.     local players = TM.New()
  1538.     if cur_players ~= 0 and expression then
  1539.         if expression == "*" then
  1540.             for i = 0,15 do
  1541.                 if getplayer(i) then
  1542.                     players[#players+1] = i
  1543.                 end
  1544.             end
  1545.         elseif expression == "me" then
  1546.             if playerId then
  1547.                 players[1] = playerId
  1548.             end
  1549.         elseif expression == "red" then
  1550.             for i = 0,15 do
  1551.                 if getplayer(i) and getteam(i) == 0 then
  1552.                     players[#players+1] = i
  1553.                 end
  1554.             end
  1555.         elseif expression == "blue" then
  1556.             for i = 0,15 do
  1557.                 if getplayer(i) and getteam(i) == 1 then
  1558.                     players[#players+1] = i
  1559.                 end
  1560.             end
  1561.         elseif expression == "randomred" or expression == "randred" then
  1562.             players[1] = SelectRandomPlayer(0)
  1563.         elseif expression == "randomblue" or expression == "randblue" then
  1564.             players[1] = SelectRandomPlayer(1)
  1565.         elseif (tonumber(expression) or 0) >= 1 and (tonumber(expression)) <= 16 then
  1566.             local playerId2 = tonumber(expression)
  1567.             if getplayer(rresolveplayer(playerId2)) then
  1568.                 players[1] = rresolveplayer(playerId2)
  1569.             end
  1570.         elseif expression == "rand" or expression == "random" then
  1571.             players[1] = SelectRandomPlayer()
  1572.         else
  1573.             for i = 0,15 do
  1574.                 if getplayer(i) and wildstring(getname(i), expression) then
  1575.                     players[#players+1] = i
  1576.                 end
  1577.             end
  1578.         end
  1579.         return next(players) and players or false
  1580.     end
  1581.     return false
  1582. end
  1583.  
  1584. local function LoadTags()
  1585.    
  1586.     local map_base = readdword(addresses.map_pointer)
  1587.     local tag_table_base = readdword(map_base) -- Confirmed. (0x40440028)
  1588.     local tag_table_count = readdword(map_base + 0xC) -- Confirmed. Number of tags in the tag table.
  1589.     local tag_table_size = 0x20 -- Confirmed.
  1590.  
  1591.     local reverse = string.reverse
  1592.     local tag_class, tag_id, tag_name_address, tag_name
  1593.     for i=0,(tag_table_count - 1) do
  1594.         tag_class = reverse(readstring(tag_table_base + (tag_table_size * i), 4))
  1595.         tag_id = readdword(tag_table_base + 0xC + (tag_table_size * i))
  1596.         tag_name_address = readdword(tag_table_base + 0x10 + tag_table_size * i)
  1597.         tag_name = readstring(tag_name_address)
  1598.         tag_table[tag_class] = tag_table[tag_class] or TM.New()
  1599.         tag_table[tag_class][tag_name] = tag_id
  1600.         tag_table[tag_id] = TM.New()
  1601.         tag_table[tag_id].tag_name = tag_name
  1602.         tag_table[tag_id].tag_class = tag_class
  1603.     end
  1604.  
  1605.     objects.cyborg = gettag("bipd", "characters\\cyborg_mp\\cyborg_mp")
  1606.     objects.camo = gettag("eqip", "powerups\\active camouflage")
  1607.     objects.health = gettag("eqip", "powerups\\health pack")
  1608.     objects.overshield = gettag("eqip", "powerups\\over shield")
  1609.     objects.fnade = gettag("eqip", "weapons\\frag grenade\\frag grenade")
  1610.     objects.pnade = gettag("eqip", "weapons\\plasma grenade\\plasma grenade")
  1611.     objects.shee = gettag("vehi", "vehicles\\banshee\\banshee_mp")
  1612.     objects.turret = gettag("vehi", "vehicles\\c gun turret\\c gun turret_mp")
  1613.     objects.ghost = gettag("vehi", "vehicles\\ghost\\ghost_mp")
  1614.     objects.rhog = gettag("vehi", "vehicles\\rwarthog\\rwarthog")
  1615.     objects.tank = gettag("vehi", "vehicles\\scorpion\\scorpion_mp")
  1616.     objects.hog = gettag("vehi", "vehicles\\warthog\\mp_warthog")
  1617.     objects.rifle = gettag("weap", "powerups\\assault rifle ammo\\assault rifle ammo")
  1618.     objects.ball = gettag("weap", "weapons\\ball\\ball")
  1619.     objects.flag = gettag("weap", "weapons\\flag\\flag")
  1620.     objects.flamethrower = gettag("weap", "weapons\\flamethrower\\flamethrower")
  1621.     objects.needler = gettag("weap", "weapons\\needler\\mp_needler")
  1622.     objects.pistol = gettag("weap", "weapons\\pistol\\pistol")
  1623.     objects.ppistol = gettag("weap", "weapons\\plasma pistol\\plasma pistol")
  1624.     objects.prifle = gettag("weap", "weapons\\plasma rifle\\plasma rifle")
  1625.     objects.frg = gettag("weap", "weapons\\plasma_cannon\\plasma_cannon")
  1626.     objects.rocket = gettag("weap", "weapons\\rocket launcher\\rocket launcher")
  1627.     objects.shotgun = gettag("weap", "weapons\\shotgun\\shotgun")
  1628.     objects.sniper = gettag("weap", "weapons\\sniper rifle\\sniper rifle")
  1629.     objects.sheebolt = gettag("proj", "vehicles\\banshee\\banshee bolt")
  1630.     objects.sheerod = gettag("proj", "vehicles\\banshee\\mp_banshee fuel rod")
  1631.     objects.turretbolt = gettag("proj", "vehicles\\c gun turret\\mp gun turret")
  1632.     objects.ghostbolt = gettag("proj", "vehicles\\ghost\\ghost bolt")
  1633.     objects.tankshot = gettag("proj", "vehicles\\scorpion\\bullet")
  1634.     objects.tankshell = gettag("proj", "vehicles\\scorpion\\tank shell")
  1635.     objects.hogshot = gettag("proj", "vehicles\\warthog\\bullet")
  1636.     objects.rifleshot = gettag("proj", "weapons\\assault rifle\\bullet")
  1637.     objects.flame = gettag("proj", "weapons\\flamethrower\\flame")
  1638.     objects.needlershot = gettag("proj", "weapons\\needler\\mp_needle")
  1639.     objects.pistolshot = gettag("proj", "weapons\\pistol\\bullet")
  1640.     objects.ppistolbolt = gettag("proj", "weapons\\plasma pistol\\bolt")
  1641.     objects.priflebolt = gettag("proj", "weapons\\plasma rifle\\bolt")
  1642.     objects.priflecbolt = gettag("proj", "weapons\\plasma rifle\\charged bolt")
  1643.     objects.rocketproj = gettag("proj", "weapons\\rocket launcher\\rocket")
  1644.     objects.shottyshot = gettag("proj", "weapons\\shotgun\\pellet")
  1645.     objects.snipershot = gettag("proj", "weapons\\sniper rifle\\sniper bullet")
  1646.     objects.fuelrodshot = gettag("proj", "weapons\\plasma_cannon\\plasma_cannon")
  1647. end
  1648.  
  1649. function votekickTimer(id, count)
  1650.     say("The VoteKick on " .. getname(votekickPlayerId) .. " has expired!")
  1651.     votekicktimer = nil
  1652.     votekickPlayerId = nil
  1653.     votekick_counter = -defaults.votekick_timeout
  1654.     for i = 0,15 do
  1655.         ip_table[getip(i)].used_votekick = false
  1656.     end
  1657.     return false
  1658. end
  1659.  
  1660. local function WriteLog(filename, logStr)
  1661.     local file = io.open(filename, "a")
  1662.     if file then
  1663.         file:write(format("%s\t%s\n", os.date "%Y/%m/%d %H:%M:%S", logStr))
  1664.         file:close()
  1665.     end
  1666. end
  1667.  
  1668. local function cmdlog(message)
  1669.     WriteLog(profilepath .. "logs\\" .. defaults.commands_file .. ".log", message)
  1670. end
  1671.  
  1672. -- This local function makes sure that we never have any commands that output more than 8 lines
  1673. -- We need this because Halo only lets you see 8 lines of text at a time in the chat
  1674. -- This local function will also split lines into more lines if a line is too long.
  1675. -- 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.
  1676. -- Arguments are output, maximum number of lines to use (MIGHT go over maxlines if the line length is already too long)
  1677. -- maxlinesize is the maximum number of characters a line can have
  1678. -- 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.
  1679. local function formatOutput(output, maxlines, maxlinesize)
  1680.     -- error if the arguments were passed incorrectly.
  1681.     if type(output) ~= "string" and type(output) ~= "table" then
  1682.         error("bad argument #1 to 'formatOutput' (expected table or string, got " .. type(output) .. ")" .. " Value: " .. tostring(output))
  1683.     elseif maxlines and type(maxlines) ~= "number" then
  1684.         error("bad argument #2 to 'formatOutput' (expected number, got " .. type(maxlines) .. " Value: " .. tostring(maxlines))
  1685.     elseif maxlinesize and type(maxlinesize) ~= "number" then
  1686.         error("bad argument #3 to 'formatOutput' (expected number, got " .. type(maxlinesize) .. " Value: " .. tostring(maxlinesize))
  1687.     end
  1688.    
  1689.     -- handle our arguments
  1690.     local newOutput = type(output) == "string" and tokenizestring(output, "\n") or output
  1691.     maxlines = maxlines or 9001
  1692.     maxlinesize = maxlinesize or 9001
  1693.    
  1694.     local header = newOutput.header
  1695.     local numOfLines = #newOutput
  1696.     local linesCombined = ceil((numOfLines + (header and 1 or 0))/maxlines)
  1697.     -- duplicate the header by linesCombined times.
  1698.     if header then
  1699.         if type(header) ~= "string" then
  1700.             error("Output header needs to be a string, got " .. type(header))
  1701.         end
  1702.        
  1703.         for i = 1,linesCombined do
  1704.             insert(newOutput, 1, header)
  1705.             cmdreply.index = cmdreply.index + 1
  1706.             numOfLines = numOfLines + 1
  1707.         end
  1708.     end
  1709.    
  1710.     -- If we have no more output, then we don't need to do anything more.
  1711.     if numOfLines == 1 and header or numOfLines == 0 then
  1712.         return newOutput[1]
  1713.     end
  1714.    
  1715.     if newOutput.align then
  1716.    
  1717.         local delimiter = newOutput.delim or "|"
  1718.         local separator = newOutput.separator or delimiter
  1719.        
  1720.         local mins = TM.New()
  1721.         local length, lineParts
  1722.         for i = 1,numOfLines do
  1723.             lineParts = tokenizestring(newOutput[i], delimiter)
  1724.             for j = 1,#lineParts do
  1725.                 -- Format every string to the biggest length possible for that entry.
  1726.                 length = #(lineParts[j])
  1727.                 if not mins[j] or length > mins[j] then
  1728.                     mins[j] = length
  1729.                 end
  1730.             end
  1731.         end
  1732.  
  1733.         local numOfLineParts
  1734.         for i = 1,numOfLines do
  1735.             lineParts = tokenizestring(newOutput[i], delimiter)
  1736.             numOfLineParts = #lineParts
  1737.             for j = 1,numOfLineParts do
  1738.                 lineParts[j] = format("%-" .. mins[j] .. "s", lineParts[j])
  1739.             end
  1740.             lineParts[numOfLineParts] = sub(lineParts[numOfLineParts], 1, -1) -- removes the last delimiter in the line
  1741.             newOutput[i] = concat(lineParts, separator)
  1742.         end
  1743.     end
  1744.  
  1745.     -- If our output uses too many lines. We now need to combine lines until we are within maxlines
  1746.     local lineIter = 1
  1747.     local numOfLinesToCombine = floor(numOfLines / linesCombined)
  1748.     while numOfLines > maxlines do
  1749.    
  1750.         for i = 2,linesCombined do -- should be 1,linesCombined-1 but 2,linesCombined works fine
  1751.             if lineIter+1 > numOfLines then break end
  1752.             newOutput[lineIter] = newOutput[lineIter] .. " - " .. newOutput[lineIter+1]
  1753.             remove(newOutput, lineIter+1)
  1754.             numOfLines = numOfLines - 1
  1755.             cmdreply.index = cmdreply.index - 1
  1756.         end
  1757.         lineIter = lineIter + 1
  1758.        
  1759.         if numOfLinesToCombine == 1 then
  1760.             linesCombined = linesCombined - 1
  1761.             if linesCombined < 2 then break end
  1762.             numOfLinesToCombine = floor(numOfLines / linesCombined)
  1763.         end
  1764.            
  1765.         numOfLinesToCombine = numOfLinesToCombine - 1
  1766.     end
  1767.    
  1768.     -- Make sure the line isn't too long.
  1769.     -- If it is, we put the part that's too long into a new table which we will put back into output later.
  1770.     lineIter = 1
  1771.     local line, length
  1772.     while newOutput[lineIter] do
  1773.         line = newOutput[lineIter]
  1774.         length = #line
  1775.         if length > maxlinesize then
  1776.             newOutput[lineIter] = sub(line, 1, maxlinesize) -- first part of line
  1777.             insert(newOutput, lineIter+1, sub(line, maxlinesize)) -- insert a new line right after this one with the second part
  1778.             numOfLines = numOfLines + 1
  1779.             cmdreply.index = cmdreply.index + 1
  1780.         end
  1781.         lineIter = lineIter + 1
  1782.     end
  1783.     return concat(newOutput, "\n", 1, numOfLines)
  1784. end
  1785.  
  1786. function delayMsg(id, count, arguments)
  1787.     local msg, playerId = arguments[1], arguments[2]
  1788.     msg = type(msg) == "table" and concat(msg, "\n") or msg
  1789.     if playerId then
  1790.         if output_environment == 2 then
  1791.             say(msg)
  1792.         elseif output_environment == 3 then
  1793.             privatesay(playerId, msg)
  1794.         end
  1795.     end
  1796.     return false
  1797. end
  1798.  
  1799. local function sendresponse(message, playerId, log)
  1800.     if not message then
  1801.         -- this will reset all the properties of cmdreply
  1802.         cmdreply(true)
  1803.         return
  1804.     end
  1805.    
  1806.     local playerCheck = getplayer(playerId)
  1807.     local tempmessage = message
  1808.    
  1809.     if not playerCheck then
  1810.         message = formatOutput(message)
  1811.         hprintf(message)
  1812.     elseif output_environment == 1 then
  1813.         message = formatOutput(message, 20, 76)
  1814.         sendconsoletext(playerId, message)
  1815.     elseif output_environment == 2 or output_environment == 3 then
  1816.         message = formatOutput(message, 6, 100)
  1817.         registertimer(0, "delayMsg", TM{message, playerId})
  1818.     end
  1819.     if log and playerCheck then
  1820.         cmdlog("Response to " .. getname(playerId) .. " (" .. player_table[playerId].admin_entry.name .. "): " .. message)
  1821.     end
  1822.    
  1823.     -- this will reset all the properties of cmdreply
  1824.     if tempmessage == cmdreply then cmdreply(true) end
  1825. end
  1826.  
  1827. local function setscore(playerId, score)
  1828.     if gametype == 1 then
  1829.         local m_player = getplayer(playerId)
  1830.         writeshort(m_player+0xC8, score)
  1831.     elseif gametype == 2 then
  1832.         writeint(addresses.slayer_globals + 0x40 + playerId*4, score)
  1833.     elseif gametype == 3 then
  1834.         local oddball_game = readbyte(addresses.gametype_base + 0x8C)
  1835.         if oddball_game == 0 or oddball_game == 1 then
  1836.             writeint(addresses.oddball_globals + 0x84 + playerId*4, score * 30)
  1837.         else
  1838.             writeint(addresses.oddball_globals + 0x84 + playerId*4, score)
  1839.         end
  1840.     elseif gametype == 4 then
  1841.         local m_player = getplayer(playerId)
  1842.         writeshort(m_player + 0xC4, score * 30)
  1843.     elseif gametype == 5 then
  1844.         local m_player = getplayer(playerId)
  1845.         writeshort(m_player + 0xC6, score)
  1846.     end
  1847. end
  1848.  
  1849. local function WriteChangeLog()
  1850.     local file = io.open("changelog_" .. script_version .. ".txt", "w")
  1851.     local changelog = TM.New()
  1852.     changelog[#changelog+1] = "Changelog for Commands Script"
  1853.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1854.     changelog[#changelog+1] = "Commands Version 5.13 The 'Nimbus' Release (Released Released February 21th, 2015)"
  1855.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1856.     changelog[#changelog+1] = "--Fixed a few minor bugs, there was a couple of issues with the banlist saving/reloading that happened in rare situations"
  1857.     changelog[#changelog+1] = "--Revamped even more code for optimization, and added lots of memoizing."
  1858.     changelog[#changelog+1] = "Changelog for Commands Script"
  1859.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1860.     changelog[#changelog+1] = "Commands Version 5.01 The 'Nimbus' Release (Released Released February 20th, 2015)"
  1861.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1862.     changelog[#changelog+1] = "--Fixed a very minor issue with banlist reloading. (was still loading from unused_banlist.txt, not a major problem)"
  1863.     changelog[#changelog+1] = "--Found out that the 'tbag' feature Aelite added was only supposed to apply to kills, so that is now a thing"
  1864.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1865.     changelog[#changelog+1] = "Commands Version 5.0 The 'Nimbus' Release (**WIZARD IS BACK** Released February 19, 2015)"
  1866.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1867.     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"
  1868.     changelog[#changelog+1] = "--This script will no longer load the defaults.txt if this script was loaded from the persistent folder (Phasor Only)"
  1869.     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."
  1870.     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."
  1871.     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)"
  1872.     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)"
  1873.     changelog[#changelog+1] = "--This script will now load sapp's 'ipbans.txt' file."
  1874.     changelog[#changelog+1] = "--Loading/saving of admins/ban_table are much more reliable now, the script will error if your file is formatted incorrectly"
  1875.     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"
  1876.     changelog[#changelog+1] = "--Kick/Ban/Mute commands now let you pass reason and time normally, you don't have to use _ for reasons anymore."
  1877.     changelog[#changelog+1] = "--All structures now follow a global naming scheme that I plan to use in all my scripts from now on"
  1878.     changelog[#changelog+1] = "--All code now uses my phasor functions to get addresses (getplayerobject, getplayerweapon, etc) for increased performance"
  1879.     changelog[#changelog+1] = "--This script now uses local variables to optimize performance."
  1880.     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."
  1881.     changelog[#changelog+1] = "--Added a /disconnect and sv_disconnect command which will give a player a 'lost network connection' screen"
  1882.     changelog[#changelog+1] = "--Removed a few useless commands that never did work but somehow people found out about (probably because of /list lol)"
  1883.     changelog[#changelog+1] = "--Gethelp added. Usage: sv_gethelp (command) or /help (command) without ()"
  1884.     changelog[#changelog+1] = "--Global rcons functionality updated (see guide for details)"
  1885.     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"
  1886.     changelog[#changelog+1] = "--Organized all commands by table so now all commands are fully documented with help notes and everything"
  1887.     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."
  1888.     changelog[#changelog+1] = "--Commands now uses admins.txt for both hash admins and IP admins, ipadmins.txt will still be read for backwards compatibility."
  1889.     changelog[#changelog+1] = "--The old deprecated ban files will now have 'archived_' in front of them. Same goes for the admin files."
  1890.     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."
  1891.     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."
  1892.     changelog[#changelog+1] = "--Anyone joining with a hacked hash (like hash 'myfakehashtrollu') will not be allowed into the server"
  1893.     changelog[#changelog+1] = "--Chat commands now directly execute server commands (/e is now deprecated) and the script is much smaller because of it"
  1894.     changelog[#changelog+1] = "--Rewrote BOS functionality"
  1895.     changelog[#changelog+1] = "--Rewrote the Spawn functionality and made the code 10x smaller by using better and more efficient coding"
  1896.     changelog[#changelog+1] = "--I've fixed things here and there, added things that were removed from my original Commands."
  1897.     changelog[#changelog+1] = "--Fixed /read (it never worked). Also accepts number structs."
  1898.     changelog[#changelog+1] = "--Fixed /write to not break on invalid syntax. Also accepts number structs.."
  1899.     changelog[#changelog+1] = "--Added randomred and randomblue to expressions list."
  1900.     changelog[#changelog+1] = "--Added a control command (FINALLY)"
  1901.     changelog[#changelog+1] = "--Fixed sending negative numbers to setplasmas and setfrags"
  1902.     changelog[#changelog+1] = "--Fixed occasional glitches with setammo."
  1903.     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"
  1904.     changelog[#changelog+1] = "--Script also tells you if your access.ini is not formatted correctly and why and then raises an error."
  1905.     changelog[#changelog+1] = "--Changed sv_status to sv_status_more as to not interfere with normal sv_status"
  1906.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1907.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1908.     changelog[#changelog+1] = "Commands Version 4.2(Released August 3rd, 2013)"
  1909.     changelog[#changelog+1] = "--Update Reason: Bug fixes and Added Features"
  1910.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1911.         changelog[#changelog+1] = ""
  1912.     changelog[#changelog+1] = "--Added the time limit address thanks to wizard. sv_time_cur is now compatible with Halo CE"
  1913.     changelog[#changelog+1] = "--Added the sendconsoletext overload to the command scripts. Thank you Nuggetz."
  1914.     changelog[#changelog+1] = "--Added 'sv_hash_duplicates' command which enables/disables the checking of duplicate keys in the server."
  1915.     changelog[#changelog+1] = "--Added 'sv_multiteam_vehicles' Enables/Disables the ability to enter a vehicle with another playerId in FFA."
  1916.         changelog[#changelog+1] = ""
  1917.     changelog[#changelog+1] = "--Modified all tables that used the hash for identication, and changed it to IP"
  1918.         changelog[#changelog+1] = ""
  1919.     changelog[#changelog+1] = "--Fixed minor bug with votekick"
  1920.     changelog[#changelog+1] = "--Fixed issue with sv_superban"
  1921.     changelog[#changelog+1] = "--Fixed AntiCaps command. WARNING: If you use a chatfilter script. Load that script before this one."
  1922.     changelog[#changelog+1] = "--Fixed issue with team play detection"
  1923.     changelog[#changelog+1] = "--Fixed minor bugs."
  1924.         changelog[#changelog+1] = ""
  1925.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1926.     changelog[#changelog+1] = "Commands Version 4.1(Released July 23rd, 2013)"
  1927.     changelog[#changelog+1] = "--Update Reason: Bug fixes"
  1928.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1929.         changelog[#changelog+1] = ""
  1930.     changelog[#changelog+1] = "--Fixed minor bugs"
  1931.         changelog[#changelog+1] = ""
  1932.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1933.     changelog[#changelog+1] = "Commands Version 4.0(Released July 21st, 2013)"
  1934.     changelog[#changelog+1] = "--Update Reason: make it compatible with new Phasor"
  1935.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1936.         changelog[#changelog+1] = ""
  1937.     changelog[#changelog+1] = "--Added 'sv_addrcon' This gives you the ability to have more than one rcon."
  1938.     changelog[#changelog+1] = "--Added 'sv_delrcon' Removes rcons from the rcon list."
  1939.     changelog[#changelog+1] = "--Added 'sv_rconlist' Displays all available rcons"
  1940.     changelog[#changelog+1] = "--Added 'sv_iprangeban' ban_table entire IP Range"
  1941.     changelog[#changelog+1] = "--Added 'sv_iprangeunban' Removes an IP from the banlist"
  1942.     changelog[#changelog+1] = "--Added 'sv_iprangebanlist' Shows all IP's banned"
  1943.     changelog[#changelog+1] = "--Added 'sv_read' command."
  1944.     changelog[#changelog+1] = "--Added 'sv_load' shortcut for sv_script_load."
  1945.     changelog[#changelog+1] = "--Added 'sv_unload' shortcut for sv_script_unload."
  1946.     changelog[#changelog+1] = "--Added 'sv_resetplayer' and '/resetplayer' removes all troll command settings."
  1947.     changelog[#changelog+1] = "--Added 'sv_damage' Increases playerId damage."
  1948.     changelog[#changelog+1] = "--Added reason to sv_textban"
  1949.     changelog[#changelog+1] = "--Added Command_Balance local function since sv_team_balance is not a command anymore for the moment."
  1950.         changelog[#changelog+1] = ""
  1951.     changelog[#changelog+1] = "--Modified Reason is said to the public"
  1952.     changelog[#changelog+1] = "--Modified Adminblocker the admin is notified if a command is being executed on them."
  1953.     changelog[#changelog+1] = "--Modified AntiSpam changed from boolean to a type: all, players, off"
  1954.     changelog[#changelog+1] = "--Modified 'sv_commands' -> 'sv_cmds'"
  1955.     changelog[#changelog+1] = "--Modified 'sv_ipban' now accepts IP's'"
  1956.     changelog[#changelog+1] = "--Modified AFK detection. Works better"
  1957.     changelog[#changelog+1] = "--Modified NameBan. Banned names are changed to 'playerId' on join."
  1958.     changelog[#changelog+1] = "--Modified Tbag Detection: Detects victim location. You must be near the victims death to be able to tbag him/her."
  1959.         changelog[#changelog+1] = ""
  1960.     changelog[#changelog+1] = "--Fixed most bugs with the new phasor"
  1961.     changelog[#changelog+1] = "--Fixed 'sv_scrimmode'"
  1962.     changelog[#changelog+1] = "--Fixed @ bug"
  1963.     changelog[#changelog+1] = "--Fixed AccessMerging bug when -1 was given to any other level other than 0"
  1964.     changelog[#changelog+1] = "--Fixed minor Bos Bug"
  1965.     changelog[#changelog+1] = "--Fixed setscore bug"
  1966.         changelog[#changelog+1] = ""
  1967.     changelog[#changelog+1] = "--Removed sv_pinglist command"
  1968.     changelog[#changelog+1] = "--Removed sv_hash_check, sv_version, and sv_version_check. Phasor has them built in."
  1969.     changelog[#changelog+1] = "--Removed Portal Blocking"
  1970.     changelog[#changelog+1] = "--Removed /setname until further notice"
  1971.         changelog[#changelog+1] = ""
  1972.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1973.     changelog[#changelog+1] = "Commands Version 3.0.1 (Released February 28th, 2013)"
  1974.     changelog[#changelog+1] = "--Update Reason: Mainly Bug Fixes"
  1975.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1976.             changelog[#changelog+1] = ""
  1977.     changelog[#changelog+1] = "--Added sv_scrimmode"
  1978.             changelog[#changelog+1] = ""
  1979.     changelog[#changelog+1] = "--Modified ipadminadd now accepts IP's"
  1980.     changelog[#changelog+1] = "--Modified 'sv_admin_add: Combined sv_admin_add and sv_admin_addh"
  1981.             changelog[#changelog+1] = ""
  1982.     changelog[#changelog+1] = "--Fixed /e bug"
  1983.     changelog[#changelog+1] = "--Fixed spam_max and spam_timeout bugs"
  1984.     changelog[#changelog+1] = "--Fixed textban bugs"
  1985.     changelog[#changelog+1] = "--Fixed superban bugs"
  1986.     changelog[#changelog+1] = "--Fixed ipban bug"
  1987.         changelog[#changelog+1] = ""
  1988.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1989.     changelog[#changelog+1] = "Commands Version 3.0.0 (released February 11th, 2013)"
  1990.     changelog[#changelog+1] = "--Update Reason: Bug Fixes and New Features"
  1991.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  1992.         changelog[#changelog+1] = ""
  1993.     changelog[#changelog+1] = "--Added safe guards for the admin system."
  1994.     changelog[#changelog+1] = "--Added Ping List command. Displays the Players ID, Name and Ping level."
  1995.     changelog[#changelog+1] = "--Added System for no Hash and/or IP admins"
  1996.     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"
  1997.     changelog[#changelog+1] = "--Added a sv_status command. It will show the current status of defaults.txt commands."
  1998.     changelog[#changelog+1] = "--Added info shown to the sv_info command"
  1999.     changelog[#changelog+1] = "--Added 'sv_chatcommands' to enable or disable admin chat commands"
  2000.     changelog[#changelog+1] = "--Added 'sv_adminblocker' enables,disables or limits the abiliy of an admin to kick/ban another admin"
  2001.     changelog[#changelog+1] = "--Added 'sv_anticaps'  Enables or Disables the use of caps in the server"
  2002.     changelog[#changelog+1] = "--Added 'sv_antispam' Enables or Disables the antispam system of the script"
  2003.     changelog[#changelog+1] = "--Added 'sv_spammax' Changes the max amount of messages that can be sent in 1 minute"
  2004.     changelog[#changelog+1] = "--Added 'sv_spamtimeout' Changes the time you are muted for spamming"
  2005.     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."
  2006.     changelog[#changelog+1] = "--Added a way to use any command without the 'sv_' Ex: 'sv_admin_add' can be written as 'admin_add' "
  2007.     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."
  2008.     changelog[#changelog+1] = "--Added 'sv_bosplayers' to see the available players that can be banned on sight."
  2009.         changelog[#changelog+1] = ""
  2010.     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."
  2011.     changelog[#changelog+1] = "--Modified Tbag function"
  2012.     changelog[#changelog+1] = "--Modified ban, you are now able to send reason(s) for the ban which will be written a file."
  2013.     changelog[#changelog+1] = "--Modified kick, you are now able to send reason(s) for the kick which will be written a file."
  2014.     changelog[#changelog+1] = "--Modified Ipban, you are now able to send reason(s) for the ipban which will be written a file."
  2015.     changelog[#changelog+1] = "--Modified Superban, you are now able to send reason(s) for the superban which will be written a file."
  2016.     changelog[#changelog+1] = "--Modified Votekick. You can only votekick again after 1 minute has passed since last votekick."
  2017.     changelog[#changelog+1] = "--Modified ChangeLevel. The coding for this command has been improved."
  2018.     changelog[#changelog+1] = "--Modified GetHelp"
  2019.         changelog[#changelog+1] = ""
  2020.     changelog[#changelog+1] = "--Fixed Ipban bug"
  2021.     changelog[#changelog+1] = "--Fixed the '/e' command."
  2022.     changelog[#changelog+1] = "--Fixed the 'sv_unmute' command."
  2023.         changelog[#changelog+1] = ""
  2024.     changelog[#changelog+1] = "--Removed sv_command_type and all content related to it"
  2025.     changelog[#changelog+1] = "--Removed redundant code."
  2026.     changelog[#changelog+1] = "--Renamed 'sv_sa_message' to 'sv_serveradmin_message'"
  2027.     changelog[#changelog+1] = "--Renamed 'sv_fj_message' to 'sv_firstjoin_message'"
  2028.     changelog[#changelog+1] = "--Renamed 'sv_wb_message' to 'sv_welcomeback_message'"
  2029.         changelog[#changelog+1] = ""
  2030.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2031.     changelog[#changelog+1] = "Commands Version 2.4.3 (released September 23rd,2012"
  2032.     changelog[#changelog+1] = "--Update Reason: Fixed issues with ServerChat Function."
  2033.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2034.         changelog[#changelog+1] = ""
  2035.     changelog[#changelog+1] = "--Fixed OnServerChat local function error caused Chat Commands to fail."
  2036.         changelog[#changelog+1] = ""
  2037.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2038.     changelog[#changelog+1] = "Commands Version 2.4.2 (released August 29th,2012"
  2039.     changelog[#changelog+1] = "--Update Reason: Fixed issues from version 2.4.1 and new commands."
  2040.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2041.         changelog[#changelog+1] = ""
  2042.     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'"
  2043.     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'"
  2044.     changelog[#changelog+1] = "--Added a Command Type command to the default.txt"
  2045.         changelog[#changelog+1] = ""
  2046.     changelog[#changelog+1] = "--ReAdded Private say command"
  2047.     changelog[#changelog+1] = "--ReAdded '/e' command."
  2048.     changelog[#changelog+1] = "--ReAdded Nuke Command."
  2049.     changelog[#changelog+1] = "--ReAdded SetName Command."
  2050.         changelog[#changelog+1] = ""
  2051.     changelog[#changelog+1] = "--Modified Tbag function"
  2052.         changelog[#changelog+1] = ""
  2053.     changelog[#changelog+1] = "--Fixed 'sv_info' command error"
  2054.     changelog[#changelog+1] = "--Fixed OnServerChat, now you wont get 'You are not allowed to use this command' every time you type."
  2055.         changelog[#changelog+1] = ""
  2056.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2057.     changelog[#changelog+1] = "Commands Version 2.4.1 (released August 22nd,2012"
  2058.     changelog[#changelog+1] = "--Update Reason: Fixed issues from version 2.4"
  2059.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2060.         changelog[#changelog+1] = ""
  2061.     changelog[#changelog+1] = "--Fixed 'sv_players_more' issue."
  2062.     changelog[#changelog+1] = "--Fixed 'sv_players' issue."
  2063.     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."
  2064.     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."
  2065.         changelog[#changelog+1] = ""
  2066.     changelog[#changelog+1] = "--Removed Restriction of Portal Blocking. Warning: Modded Maps with portals might cause the server to crash. Hope to fix soon."
  2067.         changelog[#changelog+1] = ""
  2068.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2069.     changelog[#changelog+1] = "Commands Version 2.4 (released August 19th,2012"
  2070.     changelog[#changelog+1] = "--Update Reason: New Features, Fix minor bugs, Remove non-working commands(will be re-add later), and Organize the Script"
  2071.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2072.         changelog[#changelog+1] = ""
  2073.     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."
  2074.     changelog[#changelog+1] = "--Added a Portal Blocking Command. If someone is blocking a portal they will be killed. 'sv_pbdet'"
  2075.     changelog[#changelog+1] = "--Added a Private Messaging boolean for the @ in chat. 'sv_pvtmessage'"
  2076.     changelog[#changelog+1] = "--Added Private Messaging to the default.txt"
  2077.     changelog[#changelog+1] = "--Added a Tbagging function."
  2078.     changelog[#changelog+1] = "--Added a Tbagging Boolean Command. 'sv_tbagdet'"
  2079.     changelog[#changelog+1] = "--Added Tbagging Command to the default.txt"
  2080.     changelog[#changelog+1] = "--Added Killing spree Notifications"
  2081.     changelog[#changelog+1] = "--Added a Killing spree Notification command 'sv_killspree'"
  2082.     changelog[#changelog+1] = "--Added Killing spree Notification to the default.txt"
  2083.     changelog[#changelog+1] = "--Added a 'Welcome back' message in OnPlayerJoin. It will only say it if you are not an IP/Hash Admin"
  2084.     changelog[#changelog+1] = "--Added a Welcome back message command. 'sv_welcomeback_message'"
  2085.     changelog[#changelog+1] = "--Added Welcome Back Message to the default.txt"
  2086.     changelog[#changelog+1] = "--Added a 'This is the players first time joining the server' message in OnPlayerJoin"
  2087.     changelog[#changelog+1] = "--Added a Command for Server Admin Message. 'sv_sa_message'"
  2088.     changelog[#changelog+1] = "--Added Server Admin message to the default.txt"
  2089.     changelog[#changelog+1] = "--Added a Command for First Joining Message 'sv_firstjoin_message'"
  2090.     changelog[#changelog+1] = "--Added First Joining Message to the default.txt"
  2091.     changelog[#changelog+1] = "--Added a Command for Unique Counting. 'sv_uniques_enabled'"
  2092.     changelog[#changelog+1] = "--Added Unique Counting to the default.txt"
  2093.     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."
  2094.     changelog[#changelog+1] = "--Added IP to the info Command."
  2095.         changelog[#changelog+1] = ""
  2096.     changelog[#changelog+1] = "--Fixed RTV Enabled Command "
  2097.     changelog[#changelog+1] = "--Fixed VoteKick Enabled Command "
  2098.     changelog[#changelog+1] = "--Fixed info command. "
  2099.     changelog[#changelog+1] = "--Fixed time current command. "
  2100.     changelog[#changelog+1] = "--Fixed Set Teleport Shortcut. 'sv_st' "
  2101.     changelog[#changelog+1] = "--Fixed Teleport Delete Shortcut. 'sv_t del'"
  2102.         changelog[#changelog+1] = ""
  2103.     changelog[#changelog+1] = "--Modified 'sv_players' command. Now it only gives you playerId ID, playerId Name, and playerId Team."
  2104.     changelog[#changelog+1] = "--Modified 'sv_count' command. Now disables if 'sv_uniques_enabled' is disabled."
  2105.     changelog[#changelog+1] = "--Modified Chat Commands: all commands can now be used in chat. Note: Some shortcuts have been transfered but not all."
  2106.     changelog[#changelog+1] = "--Modified GetHelp Commnad"
  2107.     changelog[#changelog+1] = "--Modified List Command"
  2108.         changelog[#changelog+1] = ""
  2109.     changelog[#changelog+1] = "--Removed 'sv_unban' command from the script. Caused the OnSeverCommand local function to crash."
  2110.     changelog[#changelog+1] = "--Removed Private say command"
  2111.     changelog[#changelog+1] = "--Removed '/e' command."
  2112.     changelog[#changelog+1] = "--Removed Nuke Command."
  2113.     changelog[#changelog+1] = "--Removed SetName Command."
  2114.         changelog[#changelog+1] = ""
  2115.     changelog[#changelog+1] = "--Access level crash fixes and a few other features"
  2116.     changelog[#changelog+1] = "--Organized all of the Functions"
  2117.     changelog[#changelog+1] = "--Commented all Main Functions. This will only show on the Commented version of the script"
  2118.         changelog[#changelog+1] = ""
  2119.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2120.     changelog[#changelog+1] = "Commands Version 2.3 (released June 13th 2012"
  2121.     changelog[#changelog+1] = "Mainly fixed up the admin system"
  2122.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2123.         changelog[#changelog+1] = ""
  2124.     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..."
  2125.     changelog[#changelog+1] = "--Added a /scorelimit and a sv_scorelimit command"
  2126.     changelog[#changelog+1] = "--Added a /a del command."
  2127.     changelog[#changelog+1] = "--Added sv_ipadminadd to the rcon"
  2128.     changelog[#changelog+1] = "--Added a patch that will allow new gametypes to be added without restarting the server"
  2129.     changelog[#changelog+1] = "--Added textbanning. It's like the mute command except it's a permanent"
  2130.         changelog[#changelog+1] = ""
  2131.     changelog[#changelog+1] = "--Modified the AdminList command. Shows a lot more now."
  2132.         changelog[#changelog+1] = ""
  2133.     changelog[#changelog+1] = "--Fixed rcon commands so that the responses show up with the /e command"
  2134.     changelog[#changelog+1] = "--Fixed the ipban command (whoops)"
  2135.     changelog[#changelog+1] = "--Fixed a very small problem with the setcolor command."
  2136.     changelog[#changelog+1] = "--Fixed up the timelimit command :)"
  2137.     changelog[#changelog+1] = "--Fixed ipadmins. They can now use the rcon."
  2138.         changelog[#changelog+1] = ""
  2139.     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"
  2140.     changelog[#changelog+1] = "turned into admins.txt, don't worry, it's supposed to do that."
  2141.     changelog[#changelog+1] = "--This script enables CE devmode commands (cheat_deathless_player, cheat_medusa, etc)"
  2142.     changelog[#changelog+1] = "--IP admins no longer get removed when you unload the commands script"
  2143.         changelog[#changelog+1] = ""
  2144.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2145.     changelog[#changelog+1] = "Commands Version 2.201 (released on June 5th 2012)"
  2146.     changelog[#changelog+1] = "This is mainly just a bug fix version"
  2147.     changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2148.         changelog[#changelog+1] = ""
  2149.     changelog[#changelog+1] = "--Added a /setscore and sv_setscore command."
  2150.     changelog[#changelog+1] = "--Added New functionality to /hax and /unhax"
  2151.         changelog[#changelog+1] = ""
  2152.     changelog[#changelog+1] = "--Modified setkills, setassists, and setdeaths to work a little cleaner"
  2153.         changelog[#changelog+1] = ""
  2154.     changelog[#changelog+1] = "--Fixed /commands to show all of the commands."
  2155.     changelog[#changelog+1] = "--Fixed a weird problem with the /enter command (when you ejected it would crash your game)"
  2156.     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)"
  2157.     changelog[#changelog+1] = "--Fixed falldamage (and also made it so longer falls don't kill you)"
  2158.     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)"
  2159.     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)"
  2160.         changelog[#changelog+1] = ""
  2161.     changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2162.     changelog[#changelog+1] = "Commands Version 2.2 (Released on June 1st 2012)"
  2163.     changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2164.         changelog[#changelog+1] = ""
  2165.     changelog[#changelog+1] = "--Added unique playerId tracking. It will keep track of the number of unique players who joined the server"
  2166.     changelog[#changelog+1] = "--Added '/count' Get the number of unique players"
  2167.     changelog[#changelog+1] = "--Added /balance, it executes sv_teams_balance in console"
  2168.     changelog[#changelog+1] = "--Added sv_privatesay. Looks like i forgot the sv_command for that"
  2169.     changelog[#changelog+1] = "--Added private chat. Use @(playerId expression) to message someone"
  2170.     changelog[#changelog+1] = "--Added /setcolor. Only works in FFA gametypes."
  2171.     changelog[#changelog+1] = "--Added namebanning to superban."
  2172.     changelog[#changelog+1] = "--Added a \ameban command."
  2173.     changelog[#changelog+1] = "--Added ipadmin deleting"
  2174.         changelog[#changelog+1] = ""
  2175.     changelog[#changelog+1] = "--Modifed 'sv_map' made it so that the sv_map and /m loads the commands script by default"
  2176.     changelog[#changelog+1] = "--Modified the AdminList local function to be a lot more useful"
  2177.         changelog[#changelog+1] = ""
  2178.     changelog[#changelog+1] = "--Fixed Bugs"
  2179.     changelog[#changelog+1] = "--Fixed votekick."
  2180.     changelog[#changelog+1] = "--Fixed /privatesay. It would only let you message one word before"
  2181.     changelog[#changelog+1] = "--Fixed access levels for the script. It kind of worked, but not really."
  2182.     changelog[#changelog+1] = "--Fixed an issue with /timelimit and sv_time_cur"
  2183.     changelog[#changelog+1] = "--Fixed deathless glitch"
  2184.         changelog[#changelog+1] = ""
  2185.     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)"
  2186.         changelog[#changelog+1] = ""
  2187.     changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2188.     changelog[#changelog+1] = "Commands Version 2.001"
  2189.     changelog[#changelog+1] = "--Fixed /ipadminadd "
  2190.     changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2191.     changelog[#changelog+1] = "Commands Version 2.0(Released April 22nd, 2012)"
  2192.     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:"
  2193.     changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2194.         changelog[#changelog+1] = ""
  2195.     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)."
  2196.     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."
  2197.     changelog[#changelog+1] = "--Added /os, this will give you an Overshield (syntax is /os [playerId])"
  2198.     changelog[#changelog+1] = "--Added a command to view all admins on the server, syntax is: /a list"
  2199.     changelog[#changelog+1] = "--Added a command to view the current admins in the server. Syntax is: /viewadmins"
  2200.     changelog[#changelog+1] = "--Added a command to view the server specs (processor speed, model name, manufacturer). Syntax is /specs, or sv_specs in console"
  2201.     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"
  2202.     changelog[#changelog+1] = "--Added version changing. You can change to any version of Halo. Syntax is: /version {version} or sv_version {version} in console."
  2203.     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)"
  2204.     changelog[#changelog+1] = "--Added a defaults.txt. This text file gets called on server startup."
  2205.     changelog[#changelog+1] = "--Added a sv_commands and a /commands. This will show all the commands that exist for this script."
  2206.     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."
  2207.     changelog[#changelog+1] = "--Added a parameter to '/spd'. Syntax is /spd [playerId] {speed}. Doing /spd [playerId] will show you their current speed."
  2208.     changelog[#changelog+1] = "--Added another parameter to '/t'. Syntax is '/t list', this will show you the list of teleports for the map."
  2209.     changelog[#changelog+1] = "--Added infinite nades to sv_infinite_ammo"
  2210.     changelog[#changelog+1] = "--Added a '/banlist' command to chat. This will show you the banlist."
  2211.     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."
  2212.     changelog[#changelog+1] = "--Added sv_rtv_needed [decimal 0 to 1]"
  2213.     changelog[#changelog+1] = "--Added sv_votekick_needed [decimal 0 to 1]"
  2214.     changelog[#changelog+1] = "--Added sv_rtv_enabled [true or false, 1 or 0]"
  2215.     changelog[#changelog+1] = "--Added sv_votekick_enabled [true or false, 1 or 0]"
  2216.     changelog[#changelog+1] = "--Added ipbanning. Syntax is sv_ipban, sv_ipbanlist, sv_ipunban, and for chat: /ipban, /ipbanlist, /ipunban."
  2217.     changelog[#changelog+1] = "--Added 'sv_launch' and '/launch'. Syntax is 'sv_launch [playerId]' or '/launch [playerId]'"
  2218.     changelog[#changelog+1] = "--Added a control command. Syntax is 'sv_control [victim] [controller]' or '/c [victim] [controller]' in chat."
  2219.     changelog[#changelog+1] = "--Added a privatesay command. Syntax is 'sv_privatesay [playerId] [message]' or '/privatesay [playerId] [message]' in chat"
  2220.     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)"
  2221.     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."
  2222.     changelog[#changelog+1] = "--Added: Now includes logging. This will log directly to commands.log in the log folder"
  2223.     changelog[#changelog+1] = "--Added: If you do not have an access file, this script will make one for you."
  2224.     changelog[#changelog+1] = "--Added '/e' command."
  2225.         changelog[#changelog+1] = ""
  2226.     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."
  2227.     changelog[#changelog+1] = "--Modified sv_afk was changed to 'sv_setafk'. Thought it was a better name for the command."
  2228.         changelog[#changelog+1] = ""
  2229.     changelog[#changelog+1] = "--Fixed /setname, it will change your name, but for others to see it it requires a rejoin."
  2230.     changelog[#changelog+1] = "--Fixed the admin system, before you had to do sv_reloadscripts after you added someone, that's been fixed."
  2231.     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."
  2232.     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."
  2233.     changelog[#changelog+1] = "--Fixed smiley's BOS commands, thanks to bvigil for telling me what it was supposed to do."
  2234.     changelog[#changelog+1] = "--Fixed a bug with /tp and sv_teleport_pl, which were crashing when the other playerId was dead."
  2235.     changelog[#changelog+1] = "--Fixed /setplasmas, thank you sanity for the notice..."
  2236.     changelog[#changelog+1] = "--Fixed a reported bug with /noweapons... I was never able to reproduce it, so I must have indirectly fixed it."
  2237.     changelog[#changelog+1] = "--Fixed /info which would crash when you used a playerId expression that was not a number."
  2238.     changelog[#changelog+1] = "--Fixed a couple of bugs with rtv and votekick (whoops)"
  2239.     changelog[#changelog+1] = "--Fixed a bug with 'sv_mute' and '/mute'. You can no longer mute admins."
  2240.     changelog[#changelog+1] = "--Fixed /st. This will set a teleport location to wherever you are standing. Syntax is: /st [teleport name]"
  2241.     changelog[#changelog+1] = "--Fixed the spawngun. Syntax is /setmode (playerId) spawngun (object)"
  2242.     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."
  2243.         changelog[#changelog+1] = ""
  2244.     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."
  2245.         changelog[#changelog+1] = ""
  2246.     changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2247.     changelog[#changelog+1] = "Commands Version 1.0"
  2248.     changelog[#changelog+1] = "First Official Release (January or something)"
  2249.     changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
  2250.         changelog[#changelog+1] = ""
  2251.     changelog[#changelog+1] = "--Script Created"
  2252.     file:write(concat(changelog, "\n"))
  2253.     file:close()
  2254. end
  2255.  
  2256. function tempBanPlayer(id, count, playerIndex)
  2257.     halo_svcmd("sv_ban " .. playerIndex .. " 1s")
  2258.     return false
  2259. end
  2260.  
  2261. local function addBan(player_name, player_hash, player_ip, ban_time, bantype, reason)
  2262.    
  2263.     local banid, ban_entry
  2264.    
  2265.     -- check if they've already been banned before
  2266.     for id = 1,#ban_table do ban_entry = ban_table[id]
  2267.         if bantype == ban_entry.type then
  2268.             if player_hash and player_hash == ban_entry.hash then
  2269.                 banid = id
  2270.                 break
  2271.             elseif player_ip and ban_entry.ip and netMatch(ban_entry.ip, player_ip) then
  2272.                 banid = id
  2273.                 break
  2274.             end
  2275.         end
  2276.     end
  2277.     banid = banid or #ban_table+1
  2278.     ban_table[banid] = ban_table[banid] or TM.New()
  2279.     local bancount = (ban_table[banid].count or 0) + 1
  2280.     ban_table[banid].count = bancount
  2281.     ban_table[banid].name = player_name
  2282.     ban_table[banid].hash = player_hash
  2283.     ban_table[banid].ip = player_ip
  2284.     ban_table[banid].time = ban_time == -1 and -1 or ban_time > 0 and ban_time + os.time() or ban_penalty[bancount]
  2285.     ban_table[banid].type = bantype
  2286.     ban_table[banid].reason = reason
  2287.    
  2288.     updateBanFiles(bantype)
  2289. end
  2290.  
  2291. local function checkaccess(thisCommand, access)
  2292.     local allow = false
  2293.     local command_access = access_table[access]
  2294.     if command_access == -1 or command_access and command_access[thisCommand] then
  2295.         allow = true
  2296.     end
  2297.     return allow
  2298. end
  2299.  
  2300. -- This local function will only work if admins are organized by lowest level = highest admin.
  2301. -- If lvl 5 is the most powerful admin and lvl 0 is the least powerful, this local function will not work.
  2302. local function checkAdminBlockerAccess(executorPlayerId, playerId, access, type)
  2303.     access = access or getaccess(executorPlayerId)
  2304.     local player_access = getaccess(playerId)
  2305.     if player_access then
  2306.         if defaults.adminblocker == 1 and access > player_access then
  2307.             return false
  2308.         elseif defaults.adminblocker == 2 and access >= player_access then
  2309.             return false
  2310.         elseif defaults.adminblocker == 3 and access_table[access] == -1 then
  2311.             return false
  2312.         end
  2313.     end
  2314.     return true
  2315. end
  2316.  
  2317. local function Say(message)
  2318.     for i = 0,15 do
  2319.         if getplayer(i) then
  2320.             sendconsoletext(i, message)
  2321.         end
  2322.     end
  2323. end
  2324.  
  2325. local function capitalizeWords(str, amount)
  2326.     return gsub(str, '(%a)(%a+)', function(cap, rest) return ('%1'):upper() .. '%2' end)
  2327. end
  2328. capitalizeWords = memoize(capitalizeWords) -- memoized
  2329.  
  2330. local function trim(str)
  2331.     return gsub(str, "^%s*(.-)%s*$", "%1")
  2332. end
  2333. trim = memoize(trim) -- memoized
  2334.  
  2335. local function tokenizecmdstring(str, tblToReuse)
  2336.     local strParts = type(tblToReuse) == "table" and tblToReuse:deleteEntries() and tblToReuse or TM.New()
  2337.    
  2338.     --remove spaces at beginning and end
  2339.     str = trim(str) .. " "
  2340.    
  2341.     -- return if no delims found
  2342.     if not find(str, '[%s"]') then strParts[1] = str return strParts end
  2343.    
  2344.     local strPart, newPos, pos
  2345.     repeat
  2346.         strPart,newPos = match(str, '^"(.-)"%s+()', pos)
  2347.         if not strPart then
  2348.             strPart,newPos = match(str, '([^%s]+)%s+()', pos)
  2349.         end
  2350.         pos = newPos
  2351.         strParts[#strParts+1] = strPart
  2352.     until not strPart
  2353.    
  2354.     ::returnSplits::
  2355.    
  2356.     return strParts
  2357. end
  2358. --tokenizecmdstring = memoize(tokenizecmdstring) -- memoized
  2359.  
  2360. local function tokenizestring(str, ...)
  2361.  
  2362.     local tblToReuse = select(-1, ...)
  2363.     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
  2364.    
  2365.     local subs = type(tblToReuse) == "table" and tblToReuse or TM.New()
  2366.     if (...) == "" then
  2367.         for i = 1,#str do
  2368.             subs[#subs+1] = sub(str, i, i)
  2369.         end
  2370.         return subs
  2371.     end
  2372.  
  2373.     local strPart = ""
  2374.     local char, iter, delim
  2375.     for i = 1,#str do
  2376.         char = sub(str, i, i)
  2377.         iter = 1
  2378.         delim = select(iter, ...)
  2379.         repeat
  2380.             if delim == char then
  2381.                 strPart = sub(strPart, 1, -1)
  2382.                 if strPart ~= "" then
  2383.                     subs[#subs+1] = strPart
  2384.                     strPart = ""
  2385.                     goto continue
  2386.                 end
  2387.             end
  2388.             iter = iter + 1
  2389.             delim = select(iter, ...)
  2390.         until not delim or delim == select(-1, ...)
  2391.         strPart = strPart .. char
  2392.         ::continue::
  2393.     end
  2394.    
  2395.     if strPart ~= "" then
  2396.         subs[#subs+1] = strPart
  2397.     end
  2398.  
  2399.     return subs
  2400. end
  2401. --tokenizestring = memoize(tokenizestring) -- memoized
  2402.  
  2403. function Commands.Create(cmdName, commandInfo, ...)
  2404.    
  2405.     -- Display errors if a command was created incorrectly.
  2406.     if not commandInfo.help then error("NO HELP INFO IN COMMAND CREATION") end
  2407.     local thisCmdFunc
  2408.     for i = 1,select("#", ...) do
  2409.         thisCmdFunc = select(i, ...)
  2410.         if not thisCmdFunc.arguments then error("NO ARGUMENTS IN COMMAND CREATION") end
  2411.         if not thisCmdFunc.arguments.minArgs then error("NO MINIMUM ARGUMENTS IN COMMAND CREATION") end
  2412.         if not thisCmdFunc.arguments.maxArgs then error("NO MAXIMUM ARGUMENTS IN COMMAND CREATION") end
  2413.         if type(thisCmdFunc.func) ~= "function" then error("BAD FUNCTION IN COMMAND CREATION: " .. type(thisCmdFunc.func)) end
  2414.     end
  2415.    
  2416.     --stupid tabs...
  2417.     commandInfo.help = gsub(commandInfo.help, "\t", "")
  2418.    
  2419.     -- Create this command with properties from the Commands class.
  2420.     local newCommand = {name = cmdName, commandInfo, ...}
  2421.     setmetatable(newCommand, Commands)
  2422.  
  2423.     -- set command aliases
  2424.     local aliases = commandInfo.aliases
  2425.     if aliases then
  2426.         local commandAliases = Commands.commandAliases
  2427.         local alias_name
  2428.         for i = 1,#aliases do alias_name = aliases[i]
  2429.             commandAliases[alias_name] = cmdName
  2430.             Commands[alias_name] = newCommand
  2431.         end
  2432.     end
  2433.    
  2434.     -- Add this command to the Command list.
  2435.     Commands[cmdName] = newCommand
  2436.     Commands[#Commands+1] = cmdName
  2437. end
  2438.  
  2439. function Commands.Execute(thisCommand, arguments, command, executorPlayerId)
  2440.     local parsedArguments, newErr
  2441.     local err = ""
  2442.     -- Loop through all overloaded functions for this command.
  2443.     for i = 2,#thisCommand do
  2444.         -- Validate and parse all arguments
  2445.         parsedArguments, newErr = thisCommand:validateArguments(arguments, thisCommand[i].arguments, command, executorPlayerId)
  2446.         -- have they passed the correct arguments for this overloaded command?
  2447.         if parsedArguments == true then
  2448.             sendresponse(newErr, executorPlayerId)
  2449.             goto endCommand
  2450.         elseif newErr == "" then
  2451.             -- call the command, and stop looping.
  2452.             thisCommand[i].func(executorPlayerId, thisCommand:unpackArguments(parsedArguments))
  2453.             goto endCommand
  2454.         else
  2455.             err = err .. "\n" .. newErr
  2456.         end
  2457.     end
  2458.     sendresponse(err .. gsub(thisCommand[1].help, ".-Syntax: %%s(.-)", "\nInvalid Syntax: " .. command .. "%1"), executorPlayerId)
  2459.     ::endCommand::
  2460. end
  2461.  
  2462. -- Needed because I need to pass a specific amount of arguments to command functions.
  2463. function Commands:unpackArguments(myTable)
  2464.     for i = 1,#myTable do
  2465.         if myTable[i] == nil then
  2466.             myTable[i] = false
  2467.         end
  2468.     end
  2469.     return table.unpack(myTable, 1, #myTable)
  2470. end
  2471.  
  2472. -- Validates and parses an argument table --
  2473. function Commands:validateArguments(arguments, argumentTypes, command, executorPlayerId)
  2474.     local err = ""
  2475.     local minArgs, maxArgs = argumentTypes.minArgs, argumentTypes.maxArgs
  2476.    
  2477.     -- Make sure they are actually passing a second argument.
  2478.     if not arguments[1] and minArgs > 0 then
  2479.         return true, gsub(self[1].help, "^.-Syntax:.-%%s(.-)$", "\nCorrect Syntax: " .. command .. "%1")
  2480.     end
  2481.    
  2482.     local argument, argType, length
  2483.     local parsedArguments = TM.New()
  2484.    
  2485.     for i = 1,#argumentTypes do argument = arguments[i]
  2486.         argType = argumentTypes[i]
  2487.         if not argument then
  2488.             if #parsedArguments < minArgs then
  2489.                 err = err .. "\nToo few arguments passed to this command! Expected " .. minArgs  .. " - " .. maxArgs .. " got " .. #parsedArguments
  2490.                 goto ReturnArgs
  2491.             end
  2492.         else
  2493.             length = #argument
  2494.         end
  2495.         if argType == "Boolean" then
  2496.             if argument == "true" or argument == "1" then
  2497.                 argument = true
  2498.             elseif argument == "false" or argument == "0" then
  2499.                 argument = false
  2500.             elseif arguments[i] then
  2501.                 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"
  2502.             end
  2503.         elseif argType == "Percent" then
  2504.             argument = tonumber(argument)
  2505.             argument = argument and (argument <= 1 and argument >= 0 and argument * 100 or argument <= 100 and argument)
  2506.             err = not argument and "Invalid Percentage. Percent arguments must be between 0 and 100." or err
  2507.         elseif argType == "Player" then
  2508.             local players = getvalidplayers(argument, executorPlayerId)
  2509.             if players then
  2510.                 argument = players
  2511.             elseif argument == nil and #arguments >= minArgs and executorPlayerId then
  2512.                 argument = TM{executorPlayerId}
  2513.             elseif not argument then
  2514.                 err = err .. "\nYou did not specify a player!"
  2515.             else
  2516.                 err = err .. "\n'" .. arguments[i] .. "' is not a valid Player!"
  2517.             end
  2518.         elseif argType == "Single Player" then
  2519.             local players = getvalidplayers(argument, executorPlayerId)
  2520.             if players then
  2521.                 argument = players[1]
  2522.                 err = players[2] and err .. "\n'" .. argument[i] .. "' cannot reference more than one player in this command!" or err
  2523.             elseif argument == nil and #arguments >= minArgs and executorPlayerId then
  2524.                 argument = executorPlayerId
  2525.             elseif not argument then
  2526.                 err = err .. "\nYou did not specify a player!"
  2527.             else
  2528.                 err = err .. "\n'" .. arguments[i] .. "' is not a valid player!"
  2529.             end
  2530.         elseif argType == "Hash" then
  2531.             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+")
  2532.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid Hash!" or err
  2533.         elseif argType == "IP Address" then
  2534.             argument = validate_ipv4(argument)
  2535.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid IP Address!" or err
  2536.         elseif argType == "Team" then
  2537.             argument = team_play and ("Red" and 0 or "Blue" and 1) or tonumber(argument)
  2538.             argument = argument and argument >= 0 and argument <= 15 and argument
  2539.             err = not argument and "The '" .. arguments[i] .. "' team does not exist!" or err
  2540.         elseif argType == "Time And Reason" then
  2541.             argument, parsedArguments[i+1] = getTimeAndReason(concat(arguments, " ", i), self.usesBanCounts and (player_table[parsedArguments[i-1]].bancount or 0) or nil)
  2542.         elseif argType == "Time" then
  2543.             local temp
  2544.             argument, temp = getTimeAndReason(concat(arguments, " ", i), self.usesBanCounts and (player_table[parsedArguments[i-1]].bancount or 0) or nil)
  2545.             err = temp ~= "None Given" and err .. "\n'" ..  concat(arguments, " ", i) .. "' is an Incorrect Time!\nCorrect Examples: 5d 2h 3m 4s" or err
  2546.         elseif argType == "Time String" then
  2547.             local timeErr = not argument and "'" .. argument .. "' is an Incorrect Time!\nCorrect Examples: 5d 2h 3m 4s"
  2548.             if timeErr then goto TimeStringEnd end
  2549.             for j = i+1,#arguments do
  2550.                 timeErr = not arguments[j] and "'" .. arguments[j] .. "' is an Incorrect Time!\nCorrect Examples: 5d 2h 3m 4s"
  2551.                 if timeErr then break end
  2552.                 argument = argument .. " " .. arguments[j]
  2553.             end
  2554.             ::TimeStringEnd::
  2555.             err = timeErr and err .. "\n" .. timeErr or err
  2556.         elseif argType == "Remaining Arguments" then
  2557.             argument = concat(arguments, " ", i)
  2558.         elseif argType == "Access Level" then
  2559.             argument = tonumber(argument)
  2560.             argument = argument and access_table[argument] and argument
  2561.             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
  2562.         elseif argType == "Whole Number" then
  2563.             argument = tonumber(argument)
  2564.             argument = argument and argument >= 0 and argument
  2565.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a Whole (Non-Negative) Number!" or err
  2566.         elseif argType == "Positive Number" then
  2567.             argument = tonumber(argument)
  2568.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a Positive Number!" or err
  2569.         elseif argType == "Number" then
  2570.             argument = tonumber(argument)
  2571.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a Number!" or err
  2572.         elseif argType == "Password" then
  2573.             argument = length and length >= 4 and length <= 8 and argument
  2574.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a Password between 4 and 8 characters!" or err
  2575.         elseif argType == "Map" then
  2576.             argument = valid_maps[argument] and argument
  2577.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid Map!" or err
  2578.         elseif argType == "Gametype" then
  2579.             argument = valid_gametypes[argument] and argument
  2580.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid GameType!" or err
  2581.         elseif argType == "String" then
  2582.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid argument for this command!" or err
  2583.         elseif argType == "AdminBlocker Type" then
  2584.             argument = tonumber(argument) or argument
  2585.             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
  2586.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid AdminBlocker Type!" or err
  2587.         elseif argType == "Datatype" then
  2588.             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
  2589.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid DataType!" or err
  2590.         elseif argType == "Struct" then
  2591.             argument = (argument == "player" or argument == "object" or argument == "weapon" or argument == "vehicle") and argument
  2592.             err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid Struct!" or err
  2593.         elseif argType == "Bit" then
  2594.             if argument == "true" or argument == "1" then
  2595.                 argument = 1
  2596.             elseif argument == "false" or argument == "0" then
  2597.                 argument = 0
  2598.             else
  2599.                 err = err .. "\n'" .. arguments[i] .. "' is not a valid Bit!\nBits must be one of the following: true or 1, false or 0"
  2600.             end
  2601.         end
  2602.  
  2603.         parsedArguments[i] = argument
  2604.     end
  2605.    
  2606.     if #parsedArguments > maxArgs and #arguments > maxArgs then
  2607.         err = err .. "\nToo many Arguments passed to this command! Expected " .. minArgs  .. " - " .. maxArgs .. " got " .. #parsedArguments
  2608.     end
  2609.    
  2610.     ::ReturnArgs::
  2611.     return parsedArguments, err
  2612. end
  2613.  
  2614. function Commands:AliasToCommand(cmd)
  2615.     return self.realname
  2616. end
  2617.  
  2618. -- Script Validation
  2619. function Commands:validscripts(...)
  2620.  
  2621. end
  2622.  
  2623. Commands.Create(
  2624.     "rconadd",
  2625.     {
  2626.         aliases = {"addrcon"},
  2627.         help = [[-- Add Rcon Password
  2628.         -- Syntax: %s [Password] {Level}
  2629.         -- Adds a global Rcon password to the list.
  2630.         -- These RCon passwords are different from the normal sv_rcon_password
  2631.         -- The difference is non-admins can use these, while sv_rcon_password only admins can use]]
  2632.     },
  2633.     {
  2634.         arguments = {"Password", "Access Level", minArgs = 1, maxArgs = 2},
  2635.         func = function(executorPlayerId, password, level)
  2636.  
  2637.             if rcon_passwords[password] then
  2638.                 sendresponse(password .. " is already a rcon password", executorPlayerId)
  2639.                 return
  2640.             end
  2641.            
  2642.             rcon_passwords[password] = level or 0
  2643.             sendresponse(password .. " has been added as a rcon password", executorPlayerId)
  2644.         end
  2645.     }
  2646. )
  2647.  
  2648. Commands.Create(
  2649.     "adminadd",
  2650.     {
  2651.         aliases = {"a", "addadmin"},
  2652.         help = [[-- Admin Add
  2653.         -- Syntax: %s [Player or Hash or IP Address] [Nickname] {Level} {Admin Type 'Hash' or 'IP'}
  2654.         -- Adds a person to the admin list.
  2655.         -- This command can take a Hash, IP, or Player as an argument.
  2656.         -- If you do not pass a level, they will automatically be added as a level 0 admin.
  2657.         -- The default for Admin Type is 'hash'. This argument is also case insensitive.]]
  2658.     },
  2659.     {
  2660.         arguments = {"Single Player", "String", "Access Level", "String", minArgs = 2, maxArgs = 4},
  2661.         func = function(executorPlayerId, playerId, nickname, level, admin_type)
  2662.            
  2663.             admin_type = admin_type and lower(admin_type) or "hash"
  2664.             if admin_type ~= "hash" and admin_type ~= "ip" then
  2665.                 sendresponse("'" .. admin_type .. "' is not a valid Admin Type!", executorPlayerId)
  2666.                 return
  2667.             end
  2668.            
  2669.             if not match(nickname, "[%l%u]+") then
  2670.                 sendresponse("Admin nicknames must only contain letters.", executorPlayerId)
  2671.                 return
  2672.             end
  2673.  
  2674.             if player_table[playerId].admin_entry then
  2675.                 sendresponse(getname(playerId) .. " is already a " .. admin_type .. " admin", executorPlayerId)
  2676.                 return
  2677.             end
  2678.            
  2679.             -- Create a new admin entry
  2680.             local newAdmin = TM.New()
  2681.             newAdmin.name = nickname
  2682.             newAdmin.level = level or 0
  2683.             newAdmin.type = admin_type
  2684.  
  2685.             -- Add the admin entry to the admin table.
  2686.             admin_table[admin_type == "hash" and gethash(playerId) or (getip(playerId) .. "/24")] = newAdmin
  2687.             player_table[playerId].admin_entry = newAdmin
  2688.             updateAdminFiles()
  2689.             sendresponse(getname(playerId) .. " is now a " .. admin_type .. " admin!", executorPlayerId)
  2690.         end
  2691.     },
  2692.     {
  2693.         arguments = {"Hash", "String", "Access Level", minArgs = 2, maxArgs = 3},
  2694.         func = function(executorPlayerId, hash, nickname, level)
  2695.        
  2696.             if not match(nickname, "%l+") then
  2697.                 sendresponse("Admin nicknames must only contain letters.", executorPlayerId)
  2698.                 return
  2699.             end
  2700.        
  2701.             for i = 1,#sharedhashes do
  2702.                 if hash == sharedhashes[i] then
  2703.                     sendresponse("This is a shared hash, and therefore cannot become an admin.", executorPlayerId)
  2704.                     return
  2705.                 end
  2706.             end
  2707.            
  2708.             if admin_table[hash] then
  2709.                 sendresponse("That Hash is already an admin.", executorPlayerId)
  2710.                 return
  2711.             end
  2712.            
  2713.             -- Create a new admin entry
  2714.             local newAdmin = TM.New()
  2715.             newAdmin.name = nickname
  2716.             newAdmin.level = level or 0
  2717.             newAdmin.type = "hash"
  2718.  
  2719.             -- Add the admin entry to the admin table.
  2720.             admin_table[hash] = newAdmin
  2721.             for i = 0,15 do
  2722.                 if gethash(i) == hash then
  2723.                     player_table[i].admin_entry = newAdmin
  2724.                 end
  2725.             end
  2726.             updateAdminFiles()
  2727.             sendresponse("That hash has been successfully added to the admin list.", executorPlayerId)
  2728.         end
  2729.     },
  2730.     {
  2731.         arguments = {"IP Address", "String", "Access Level", minArgs = 2, maxArgs = 3},
  2732.         func = function(executorPlayerId, ip_address, nickname, level)
  2733.  
  2734.             if not match(nickname, "%l+") then
  2735.                 sendresponse("Admin nicknames must only contain letters.", executorPlayerId)
  2736.                 return
  2737.             end
  2738.            
  2739.             for index,thisAdmin in next,admin_table do
  2740.                 if thisAdmin.type == "ip" and netMatch(index, ip_address) then
  2741.                     sendresponse("That IP Address is already an admin.", executorPlayerId)
  2742.                     return
  2743.                 end
  2744.             end
  2745.            
  2746.             -- Create a new admin entry
  2747.             local newAdmin = TM.New()
  2748.             newAdmin.name = nickname
  2749.             newAdmin.level = level or 0
  2750.             newAdmin.type = "ip"
  2751.  
  2752.             -- Add the admin entry to the admin table.
  2753.             admin_table[ip_address] = newAdmin
  2754.             for i = 0,15 do
  2755.                 if getplayer(i) then
  2756.                     if netMatch(ip_address, getip(i)) then
  2757.                         player_table[i].admin_entry = newAdmin
  2758.                     end
  2759.                 end
  2760.             end
  2761.             updateAdminFiles()
  2762.            
  2763.             sendresponse("That IP Address has been successfully added to the admin list.", executorPlayerId)
  2764.         end
  2765.     }
  2766. )
  2767.  
  2768. Commands.Create(
  2769.     "admindel",
  2770.     {
  2771.         aliases = {"deladmin", "revoke", "a del", "adminrevoke", "revokeadmin"},
  2772.         help = [[-- Admin Delete
  2773.         -- Syntax: %s [Player or Admin Nickname]
  2774.         -- Removes an admin from the admin list by index number.
  2775.         -- Use 'sv_admin_list' to get a list of admins for their index.
  2776.         -- You can also pass a player to this command.]]
  2777.     },
  2778.     {
  2779.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  2780.         func = function(executorPlayerId, players)
  2781.             local playerId, ip
  2782.             for i = 1,#players do playerId = players[i]
  2783.            
  2784.                 if not player_table[playerId].admin_entry then
  2785.                     cmdreply[cmdreply()] = getname(playerId) .. " was never an admin"
  2786.                     goto continue
  2787.                 end
  2788.                
  2789.                 admin_table[gethash(playerId)] = nil
  2790.                
  2791.                 for index,thisAdmin in next,admin_table do
  2792.                     if thisAdmin.type == "ip" and netMatch(index, ip) then
  2793.                         admin_table[index] = nil
  2794.                     end
  2795.                 end
  2796.                
  2797.                 player_table[playerId].admin_entry = nil
  2798.                    
  2799.                 updateAdminFiles()
  2800.                 cmdreply[cmdreply()] = getname(playerId) .. " is no longer an admin"
  2801.                
  2802.                 ::continue::
  2803.             end
  2804.            
  2805.             sendresponse(cmdreply, playerId)
  2806.         end
  2807.     },
  2808.     {
  2809.         arguments = {"String", minArgs = 1, maxArgs = 1},
  2810.         func = function(executorPlayerId, nickname)
  2811.            
  2812.             if not next(admin_table) then
  2813.                 sendresponse("There are no admins on this server.", executorPlayerId)
  2814.                 return
  2815.             end
  2816.  
  2817.             for k,thisAdmin in next,admin_table do
  2818.                 if thisAdmin.name == nickname then
  2819.                     admin_table[k] = nil
  2820.                     sendresponse(nickname .. " is no longer an admin", executorPlayerId)
  2821.                     updateAdminFiles()
  2822.                    
  2823.                     for i = 0,15 do
  2824.                         if player_table[i].admin_entry == thisAdmin then
  2825.                             player_table[i].admin_entry = nil
  2826.                         end
  2827.                     end
  2828.                    
  2829.                     return
  2830.                 end
  2831.             end
  2832.            
  2833.             sendresponse("There are no admins with a nickname of '" .. nickname .. "'", executorPlayerId)
  2834.         end
  2835.     }
  2836. )
  2837.  
  2838. Commands.Create(
  2839.     "setafk",
  2840.     {
  2841.         aliases = {"afk"},
  2842.         help = [[-- Set AFK Player
  2843.         -- Syntax: %s [Player]
  2844.         -- Sets the specified player to the AFK status.]]
  2845.     },
  2846.     {
  2847.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  2848.         func = function(executorPlayerId, players)
  2849.            
  2850.             local playerId
  2851.             for i = 1,#players do playerId = players[i]
  2852.                 player_table[playerId].afk = true
  2853.                 cmdreply[cmdreply()] = getname(playerId) .. " is now afk"
  2854.             end
  2855.            
  2856.             sendresponse(cmdreply, executorPlayerId)
  2857.         end
  2858.     }
  2859. )
  2860.  
  2861. Commands.Create(
  2862.     "adminlist",
  2863.     {
  2864.         aliases = {"admins", "listadmins", "alist"},
  2865.         help = [[-- Admin List
  2866.         -- Syntax: %s {Type}
  2867.         -- Shows a list of all Admins
  2868.         -- Type can be either 'IP', 'Hash', or 'Temp' for filtering.]]
  2869.     },
  2870.     {
  2871.         arguments = {"String", minArgs = 0, maxArgs = 1},
  2872.         func = function(executorPlayerId, admin_type)
  2873.             cmdreply.header = "[Name | Level | Admin Type]"
  2874.             cmdreply.align = true
  2875.             cmdreply.delim = "|"
  2876.             local hash_admin, ip_admin
  2877.             for index,thisAdmin in next,admin_table do
  2878.                 cmdreply[cmdreply()] = thisAdmin.name .. " | " .. thisAdmin.level .. " | " .. thisAdmin.type .. " Admin"
  2879.             end
  2880.            
  2881.             sendresponse(cmdreply, executorPlayerId)
  2882.         end
  2883.     }
  2884. )
  2885.  
  2886. Commands.Create(
  2887.     "alias",
  2888.     {
  2889.         help = [[-- Alias
  2890.         -- Syntax: %s [player]
  2891.         -- Shows all names used with the hash]]
  2892.     },
  2893.     {
  2894.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  2895.         func = function(executorPlayerId, players)
  2896.             local playerId
  2897.             for i = 1,#players do playerId = players[i]
  2898.                 halo_svcmdplayer("sv_alias_hash " .. resolveplayer(playerId), executorPlayerId)
  2899.             end
  2900.         end
  2901.     }
  2902. )
  2903.  
  2904. -- 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.
  2905. local function ReturnScriptBooleanCheck(boolName, boolCheck, argBool)
  2906.     local are_is = sub(boolName, -1, -1) == "s" and "are" or "is" -- lol
  2907.     if argBool == nil then
  2908.         return nil, boolName .. " is currently " .. (boolCheck == true and "On" or boolCheck == false and "Off" or tostring(boolCheck))
  2909.     end
  2910.    
  2911.     local response
  2912.  
  2913.     if argBool then
  2914.         if not boolCheck then
  2915.             response = boolName .. " " .. are_is .. " now on"
  2916.         else
  2917.             argBool = nil
  2918.             response = "(*) " .. boolName .. " " .. are_is .. " already enabled"
  2919.         end
  2920.     elseif not argBool then
  2921.         if boolCheck then
  2922.             response = boolName .. " " .. are_is .. " now off"
  2923.         else
  2924.             argBool = nil
  2925.             response = "(*) " .. boolName .. " " .. are_is .. " already off"
  2926.         end
  2927.     end
  2928.    
  2929.     return argBool, response
  2930. end
  2931.  
  2932. -- Scripted Game Boolean Commands
  2933.  
  2934. Commands.Create(
  2935.     "anticaps",
  2936.     {
  2937.         aliases = {"disablecaps", "nocaps"},
  2938.         help = [[-- AntiCaps
  2939.         -- Syntax: %s {Boolean}
  2940.         -- Enables or Disables the use of caps in the server]]
  2941.     },
  2942.     {
  2943.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  2944.         func = function(executorPlayerId, strBool)
  2945.             local newBool, response = ReturnScriptBooleanCheck("Anticaps", defaults.anticaps, strBool)
  2946.             sendresponse(response, executorPlayerId)
  2947.             if newBool ~= nil then
  2948.                 defaults.anticaps = newBool
  2949.             end
  2950.         end
  2951.     }
  2952. )
  2953.  
  2954. Commands.Create(
  2955.     "chatcommands",
  2956.     {
  2957.         help = [[-- ChatCommands
  2958.         -- Syntax: %s {Boolean}
  2959.         -- Enable/Disable Chat Commands for Admins]]
  2960.     },
  2961.     {
  2962.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  2963.         func = function(executorPlayerId, strBool)
  2964.             local newBool, response = ReturnScriptBooleanCheck("Chat Commands", defaults.chatcommands, strBool)
  2965.             sendresponse(response, executorPlayerId)
  2966.             if newBool ~= nil then
  2967.                 defaults.chatcommands = newBool
  2968.             end
  2969.         end
  2970.     }
  2971. )
  2972.  
  2973. Commands.Create(
  2974.     "chatids",
  2975.     {
  2976.         aliases = {"chatid", "showplayernumbers"},
  2977.         help = [[-- Show Player IDs In Chat
  2978.         -- Syntax: %s {Boolean}
  2979.         -- Enable/Disable the showing of Player IDs in the chat.]]
  2980.     },
  2981.     {
  2982.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  2983.         func = function(executorPlayerId, strBool)
  2984.             local newBool, response = ReturnScriptBooleanCheck("Chat IDs", defaults.chatids, strBool)
  2985.             sendresponse(response, executorPlayerId)
  2986.             if newBool ~= nil then
  2987.                 defaults.chatids = newBool
  2988.             end
  2989.         end
  2990.     }
  2991. )
  2992.  
  2993. Commands.Create(
  2994.     "crouchcamo",
  2995.     {
  2996.         aliases = {"tigermode", "ninja", "ninjamode"},
  2997.         help = [[--Enable or Disable Crouch Camo
  2998.         -- Syntax: %s {Boolean}
  2999.         -- Enables or Disables the use of crouch camo]],
  3000.     },
  3001.     {
  3002.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3003.         func = function(executorPlayerId, players, strBool)
  3004.             local newBool, response = ReturnScriptBooleanCheck("Crouch Camo", defaults.crouch_camo, strBool)
  3005.             if newBool ~= nil then
  3006.                 defaults.crouch_camo = newBool
  3007.             end
  3008.             sendresponse(response)
  3009.         end
  3010.     }
  3011. )
  3012.  
  3013. Commands.Create(
  3014.     "uniquesenabled",
  3015.     {
  3016.         aliases = {"uniqueplayercounting"},
  3017.         help = [[-- Unique Player Counting
  3018.         -- Syntax: %s {Boolean}
  3019.         -- Enables/Disables the Unique Player Counting feature.]]
  3020.     },
  3021.     {
  3022.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3023.         func = function(executorPlayerId, strBool)
  3024.             local newBool, response = ReturnScriptBooleanCheck("Unique Player Counting", defaults.uniques_enabled, strBool)
  3025.            
  3026.             sendresponse(response, executorPlayerId)
  3027.            
  3028.             if newBool then
  3029.                
  3030.                 local file = io.open(profilepath .. "uniques.txt")
  3031.                 if not file then
  3032.                     return
  3033.                 end
  3034.                
  3035.                 local index,ip,joincount,names
  3036.                 for line in file:lines() do
  3037.                     -- ignore blank lines
  3038.                     if match(line, "%g%g%g+") then
  3039.                         unique_table.total = unique_table.total + 1
  3040.                         index,joincount,names = match(line, "^(.+),(%d+),(.-)$")
  3041.                         if index then
  3042.                             names = tokenizestring(names, ",")
  3043.                             unique_table[index] = TM{joincount = joincount, names = names}
  3044.                         else
  3045.                             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+),(.-)$")
  3046.                             if names and validate_ipv4(ip) then
  3047.                                 joincount = 1
  3048.                                 unique_table[ip] = TM{joincount = 1, names = TM{names}}
  3049.                                 unique_table[match(ip, "%d+%.%d+%.%d+%.")] = TM{joincount = 1, names = TM{names}}
  3050.                             end
  3051.                         end
  3052.                     end
  3053.                 end
  3054.                 file:close()
  3055.             elseif newBool ~= nil then
  3056.                 defaults.uniques_enabled = false
  3057.             end
  3058.         end
  3059.     }
  3060. )
  3061.  
  3062. Commands.Create(
  3063.     "deathless",
  3064.     {
  3065.         aliases = {"deathlessplayer", "deathlessmode", "cheatdeathlessplayer"},
  3066.         scrimBlock = true,
  3067.         help = [[-- Deathless Players
  3068.         -- Syntax: %s {Boolean}
  3069.         -- Enables/Disables the Deathless Players mode.
  3070.         -- Players cannot die while this mode is enabled (obviously).
  3071.         -- The default for this command is (obviously) Off]]
  3072.     },
  3073.     {
  3074.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3075.         func = function(executorPlayerId, strBool)
  3076.             local newBool, response = ReturnScriptBooleanCheck("Deathless Player", defaults.deathless, strBool)
  3077.            
  3078.             sendresponse(response, executorPlayerId)
  3079.            
  3080.             if newBool ~= nil then
  3081.                 defaults.deathless = newBool
  3082.             end
  3083.         end
  3084.     }
  3085. )
  3086.  
  3087. Commands.Create(
  3088.     "falldamage",
  3089.     {
  3090.         scrimBlock = true,
  3091.         help = [[-- Fall Damage
  3092.         -- Syntax: %s [Boolean]
  3093.         -- Enable/Disable the damage players receive from falling.
  3094.         -- The default for this command is: Enabled]]
  3095.     },
  3096.     {
  3097.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3098.         func = function(executorPlayerId, strBool)
  3099.             local newBool, response = ReturnScriptBooleanCheck("Falldamage", defaults.falldamage, strBool)
  3100.            
  3101.             sendresponse(response, executorPlayerId)
  3102.            
  3103.             if newBool ~= nil then
  3104.                 defaults.falldamage = newBool
  3105.             end
  3106.         end
  3107.     }
  3108. )
  3109.  
  3110. Commands.Create(
  3111.     "firstjoinmessage",
  3112.     {
  3113.         help = [[-- First Join Message
  3114.         -- Syntax: %s [Boolean]
  3115.         -- Enable/Disable the First Join Message.
  3116.         -- The default for this command is: Enabled.]]
  3117.     },
  3118.     {
  3119.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3120.         func = function(executorPlayerId, strBool)
  3121.             local newBool, response = ReturnScriptBooleanCheck("First Join Message", defaults.firstjoin_message, strBool)
  3122.            
  3123.             sendresponse(response, executorPlayerId)
  3124.            
  3125.             if newBool ~= nil then
  3126.                 defaults.firstjoin_message = newBool
  3127.             end
  3128.         end
  3129.     }
  3130. )
  3131.  
  3132. Commands.Create(
  3133.     "hashduplicates",
  3134.     {
  3135.         help = [[-- Hash Duplicate Checking
  3136.         -- Syntax: %s {Boolean}
  3137.         -- Allows/Deny's multiple players with the same hash to join the server
  3138.         -- The default for this command is: Enabled.]]
  3139.     },
  3140.     {
  3141.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3142.         func = function(executorPlayerId, strBool)
  3143.             local newBool, response = ReturnScriptBooleanCheck("Hash Duplicate Checking", defaults.hash_duplicates, strBool)
  3144.            
  3145.             sendresponse(response, executorPlayerId)
  3146.            
  3147.             if newBool then
  3148.                 writebit(addresses.hash_duplicate_patch, 0, 0)
  3149.                 defaults.hash_duplicates = true
  3150.             elseif newBool ~= nil then
  3151.                 writebit(addresses.hash_duplicate_patch, 0, 1)
  3152.                 defaults.hash_duplicates = false
  3153.             end
  3154.         end
  3155.     }
  3156. )
  3157.  
  3158. Commands.Create(
  3159.     "infiniteammo",
  3160.     {
  3161.         aliases = {"infammo"},
  3162.         scrimBlock = true,
  3163.         help = [[-- Infinite Ammo
  3164.         -- Syntax: %s [Boolean]
  3165.         -- Enable or disable infinite ammo"]]
  3166.     },
  3167.     {
  3168.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3169.         func = function(executorPlayerId, strBool)
  3170.             local newBool, response = ReturnScriptBooleanCheck("Infinite Ammo", defaults.infinite_ammo, strBool)
  3171.            
  3172.             sendresponse(response, executorPlayerId)
  3173.            
  3174.             if newBool then
  3175.                 defaults.infinite_ammo = true
  3176.                 local ptable, m_weaponObj, weaponObjId
  3177.                 infammo_timer = registertimer(500, "playerWeaponCheckTimer")
  3178.                 for playerId = 0,15 do
  3179.                     if not getplayer(playerId) then
  3180.                         goto continue
  3181.                     end
  3182.                    
  3183.                     local m_playerObj, playerObjId = getplayerobject(playerId)
  3184.                     if not m_playerObj then
  3185.                         goto continue
  3186.                     end
  3187.  
  3188.                     ptable = player_table[playerId]
  3189.                     local m_weaponObj, weaponObjId
  3190.                     for slot = 1,4 do
  3191.                         weaponObjId = ptable.weapons[slot]
  3192.                         m_weaponObj = getobject(weaponObjId)
  3193.                         if m_weaponObj then
  3194.                             writeshort(m_weaponObj + 0x2B6, 0x7CFF)
  3195.                             writeshort(m_weaponObj + 0x2B8, 0x7CFF)
  3196.                             updateammo(weaponObjId)
  3197.                             ptable.weapons = weaponObjId
  3198.                         end
  3199.                     end
  3200.                     ::continue::
  3201.                 end
  3202.             elseif newBool ~= nil then
  3203.                 local m_playerObj, m_weaponObj, weaponObjId, mapId, tag_address, tag_data_address, address_magazines, rounds_total_initial, rounds_loaded_maximum
  3204.                 for i = 0,15 do
  3205.                
  3206.                     m_playerObj = getplayerobject(i)
  3207.                     if not m_playerObj then
  3208.                         goto continue
  3209.                     end
  3210.                    
  3211.                     for x = 1,4 do
  3212.                         m_weaponObj, weaponObjId = getplayerweapon(i, x)
  3213.                         if not m_weaponObj then
  3214.                             goto continue2
  3215.                         end
  3216.                        
  3217.                         mapId = readdword(m_weaponObj)
  3218.                         tag_address = gettagaddress(mapId)
  3219.                         tag_data_address = readdword(tag_address + 0x14)
  3220.                         address_magazines = readdword(tag_data_address + 0x4F0 + 0x4)
  3221.                         rounds_total_initial = readshort(address_magazines + 0x8)
  3222.                         rounds_loaded_maximum = readshort(address_magazines + 0xA)
  3223.  
  3224.                         writeshort(m_weaponObj + 0x2B6, rounds_total_initial or 0)
  3225.                         writeshort(m_weaponObj + 0x2B8, rounds_loaded_maximum or 0)
  3226.                         updateammo(weaponObjId)
  3227.                        
  3228.                         ::continue2::
  3229.                     end
  3230.                    
  3231.                     ::continue::
  3232.                 end
  3233.                 if infammo_timer then removetimer(infammo_timer) end
  3234.                 defaults.infinite_ammo = false
  3235.             end
  3236.         end
  3237.     }
  3238. )
  3239.  
  3240. Commands.Create(
  3241.     "killspree",
  3242.     {
  3243.         aliases = {"killingspree"},
  3244.         help = [[-- Killing Spree Detection
  3245.         -- Syntax: %s [Boolean]
  3246.         -- Enable/Disable Killing Spree Notifications]]
  3247.     },
  3248.     {
  3249.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3250.         func = function(executorPlayerId, strBool)
  3251.             local newBool, response = ReturnScriptBooleanCheck("Killing Spree Notifications", defaults.killing_spree, strBool)
  3252.            
  3253.             sendresponse(response, executorPlayerId)
  3254.            
  3255.             if newBool ~= nil then
  3256.                 defaults.killing_spree = newBool
  3257.             end
  3258.         end
  3259.     }
  3260. )
  3261.  
  3262. Commands.Create(
  3263.     "multiteamvehicles",
  3264.     {
  3265.         help = [[-- Multi Team Vehicles
  3266.         -- Syntax: %s {Boolean}
  3267.         -- Allows/Deny's players to enter enemy vehicles.
  3268.         -- Note: This command only works on Free-For-All GameTypes.
  3269.         -- The default for this command is: Disabled.]]
  3270.     },
  3271.     {
  3272.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3273.         func = function(executorPlayerId, strBool)
  3274.             local newBool, response = ReturnScriptBooleanCheck("Multi-Team Vehicles", defaults.multiteam_vehicles, strBool)
  3275.            
  3276.             sendresponse(response, executorPlayerId)
  3277.            
  3278.             if newBool then
  3279.                 local m_player
  3280.                 for i = 0,15 do
  3281.                     m_player = getplayer(i)
  3282.                     if m_player then
  3283.                         writebyte(m_player + 0x20, 0)
  3284.                     end
  3285.                 end
  3286.                 defaults.multiteam_vehicles = true
  3287.             elseif newBool ~= nil then
  3288.                 local m_player
  3289.                 for i = 0,15 do
  3290.                     m_player = getplayer(i)
  3291.                     if m_player then
  3292.                         writebyte(m_player + 0x20, readbyte(m_player + 0x66))
  3293.                     end
  3294.                 end
  3295.                 defaults.multiteam_vehicles = false
  3296.             end
  3297.         end
  3298.     }
  3299. )
  3300.  
  3301. Commands.Create(
  3302.     "noweapons",
  3303.     {
  3304.         help = [[-- No Weapons
  3305.         -- Syntax: %s {Boolean}
  3306.         -- Enables/Disables the use of weapons in a server.]]
  3307.     },
  3308.     {
  3309.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3310.         func = function(executorPlayerId, strBool)
  3311.             local newBool, response = ReturnScriptBooleanCheck("No-Weapons mode", defaults.noweapons, strBool)
  3312.            
  3313.             sendresponse(response, executorPlayerId)
  3314.            
  3315.             if newBool then
  3316.                 local m_playerObj, m_weaponObj, weaponObjId
  3317.                 for playerId = 0,15 do
  3318.                     m_playerObj = getplayerobject(playerId)
  3319.                     if m_playerObj then
  3320.                         for j = 1,4 do
  3321.                             m_weaponObj, weaponObjId = getplayerweapon(playerId, j)
  3322.                             if m_weaponObj then
  3323.                                 destroyobject(weaponObjId)
  3324.                             end
  3325.                         end
  3326.                     end
  3327.                 end
  3328.                 defaults.noweapons = true
  3329.             elseif newBool ~= nil then
  3330.                 for playerId = 0,15 do
  3331.                     if getplayer(playerId) then
  3332.                         resetweapons(playerId)
  3333.                     end
  3334.                 end
  3335.                 defaults.noweapons = false
  3336.             end
  3337.         end
  3338.     }
  3339. )
  3340.  
  3341. Commands.Create(
  3342.     "pmenabled",
  3343.     {
  3344.         aliases = {"pvtmessage", "privatemessage"},
  3345.         help = [[-- Private Messaging
  3346.         -- Syntax: %s {Boolean}
  3347.         -- Enable/Disable Private Messaging
  3348.         -- To use private messaging, type @(playerIndex) (message) in the chat, without the ( )]]
  3349.     },
  3350.     {
  3351.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3352.         func = function(executorPlayerId, strBool)
  3353.             local newBool, response = ReturnScriptBooleanCheck("Private Messaging", defaults.pm_enabled, strBool)
  3354.            
  3355.             sendresponse(response, executorPlayerId)
  3356.            
  3357.             if newBool ~= nil then
  3358.                 defaults.pm_enabled = newBool
  3359.             end
  3360.         end
  3361.     }
  3362. )
  3363.  
  3364. Commands.Create(
  3365.     "rtvenabled",
  3366.     {
  3367.         help = [[-- RockTheVote
  3368.         -- Syntax: %s {Boolean}
  3369.         -- Enables or disables the use of RockTheVote in the server
  3370.         -- To initiate a rtv, type 'skip' or 'rtv' in the chat.]]
  3371.     },
  3372.     {
  3373.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3374.         func = function(executorPlayerId, strBool)
  3375.             local newBool, response = ReturnScriptBooleanCheck("RockTheVote", defaults.rtv_enabled, strBool)
  3376.            
  3377.             sendresponse(response, executorPlayerId)
  3378.            
  3379.             if newBool ~= nil then
  3380.                 defaults.rtv_enabled = newBool
  3381.             end
  3382.         end
  3383.     }
  3384. )
  3385.  
  3386. Commands.Create(
  3387.     "serveradminmessage",
  3388.     {
  3389.         aliases = {"samessage"},
  3390.         help = [[-- Server Admin Message
  3391.         -- Syntax: %s {Boolean}
  3392.         -- Enable/Disable Server Admin join notification.]]
  3393.     },
  3394.     {
  3395.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3396.         func = function(executorPlayerId, strBool)
  3397.             local newBool, response = ReturnScriptBooleanCheck("Server Admin Message", defaults.sa_message, strBool)
  3398.            
  3399.             sendresponse(response, executorPlayerId)
  3400.            
  3401.             if newBool ~= nil then
  3402.                 defaults.sa_message = newBool
  3403.             end
  3404.         end
  3405.     }
  3406. )
  3407.  
  3408. Commands.Create(
  3409.     "scrimmode",
  3410.     {
  3411.         help = [[-- Scrim mode
  3412.         -- Syntax: %s {Boolean}
  3413.         -- Enables/Disables Scrim Mode
  3414.         -- This mode will disable certain commands, so people can't cheat during scrims.]]
  3415.     },
  3416.     {
  3417.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3418.         func = function(executorPlayerId, strBool)
  3419.             local newBool, response = ReturnScriptBooleanCheck("Scrim mode", defaults.scrim_mode, strBool)
  3420.            
  3421.             sendresponse(response, executorPlayerId)
  3422.            
  3423.             if newBool then
  3424.                 for i = 0,15 do
  3425.                     ResetPlayer(i)
  3426.                 end
  3427.                
  3428.                 controllers:deleteEntries()
  3429.                 slaving:deleteEntries()
  3430.                
  3431.                 defaults.falldamage = true
  3432.                 defaults.deathless = false
  3433.                 defaults.infinite_ammo = false
  3434.                
  3435.                 defaults.scrim_mode = true
  3436.             elseif newBool ~= nil then
  3437.                 defaults.scrim_mode = false
  3438.             end
  3439.         end
  3440.     }
  3441. )
  3442.  
  3443. Commands.Create(
  3444.     "tbagdet",
  3445.     {
  3446.         aliases = {"tbagdetection"},
  3447.         help = [[-- Tbag Detection
  3448.         -- Syntax: %s [Boolean]
  3449.         -- Enable/Disable Tbag announcement]]
  3450.     },
  3451.     {
  3452.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3453.         func = function(executorPlayerId, strBool)
  3454.             local newBool, response = ReturnScriptBooleanCheck("Tbag Detection", defaults.tbag_detection, strBool)
  3455.            
  3456.             sendresponse(response, executorPlayerId)
  3457.            
  3458.             if newBool ~= nil then
  3459.                 defaults.tbag_detection = newBool
  3460.             end
  3461.         end
  3462.     }
  3463. )
  3464.  
  3465. Commands.Create(
  3466.     "votekickenabled",
  3467.     {
  3468.         help = [[-- VoteKick
  3469.         -- Syntax: %s [Boolean]
  3470.         -- Enables/Disables the use of VoteKick in a server
  3471.         -- Once enabled, people can type 'votekick [player]' in the chat to start a votekick on that player.]]
  3472.     },
  3473.     {
  3474.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3475.         func = function(executorPlayerId, strBool)
  3476.             local newBool, response = ReturnScriptBooleanCheck("VoteKick", defaults.votekick_enabled, strBool)
  3477.            
  3478.             sendresponse(response, executorPlayerId)
  3479.            
  3480.             if newBool ~= nil then
  3481.                 defaults.votekick_enabled = newBool
  3482.             end
  3483.         end
  3484.     }
  3485. )
  3486.  
  3487. Commands.Create(
  3488.     "defaultspawnweapons",
  3489.     {
  3490.         aliases = {"spawnweapons", "weaponsonspawn", "chooseweapons", "selectweapons", "poontang"},
  3491.         help = [[-- Choose Default Spawn Weapons
  3492.         -- Syntax: %s {Primary Weapon} {Secondary Weapon} {Tertiary Weapon} {Quaternary Weapon}
  3493.         -- Will allow you to change the default]]
  3494.     },
  3495.     {
  3496.         arguments = {"Object", "Object", "Object", "Object", minArgs = 0, maxArgs = 4},
  3497.         func = function(executorPlayerId, primary_weap_tagname, secondary_weap_tagname, tertiary_weap_tagname, quaternary_weap_tagname)
  3498.             if primary_weap_tagname then
  3499.                 spawnWeapons[1] = primary_weap_tagname
  3500.                 spawnWeapons[2] = secondary_weap_tagname
  3501.                 spawnWeapons[3] = tertiary_weap_tagname
  3502.                 spawnWeapons[4] = quaternary_weap_tagname
  3503.             else
  3504.                 sendresponse("The current default spawn weapons are displayed below", executorPlayerId)
  3505.                 local weap
  3506.                 for i = 1,4 do weap = spawnWeapons[i]
  3507.                     if weap then
  3508.                         sendresponse("Spawn Weapon #" .. i .. ": " .. weap)
  3509.                     end
  3510.                 end
  3511.             end
  3512.         end
  3513.     }
  3514. )
  3515.  
  3516. Commands.Create(
  3517.     "welcomebackmessage",
  3518.     {
  3519.         aliases = {"wbmessage"},
  3520.         help = [[-- Welcome Back Message
  3521.         -- Syntax: %s [boolean]
  3522.         -- Enable/Disable Welcome Back Message]]
  3523.     },
  3524.     {
  3525.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  3526.         func = function(executorPlayerId, strBool)
  3527.             local newBool, response = ReturnScriptBooleanCheck("Welcome Back Message", defaults.wb_message, strBool)
  3528.            
  3529.             sendresponse(response, executorPlayerId)
  3530.            
  3531.             if newBool ~= nil then
  3532.                 defaults.wb_message = newBool
  3533.             end
  3534.         end
  3535.     }
  3536. )
  3537.  
  3538. -- Scripted Game non-boolean Commands
  3539.  
  3540. Commands.Create(
  3541.     "adminblocker",
  3542.     {
  3543.         help = [[-- Admin Blocker
  3544.         -- Syntax: %s {type}
  3545.         -- Enables, disables or limits the abiliy of an admin to kick/ban ]]
  3546.     },
  3547.     {
  3548.         arguments = {"AdminBlocker Type", minArgs = 0, maxArgs = 1},
  3549.         func = function(executorPlayerId, abtype)
  3550.             if abtype > 3 then
  3551.                 sendresponse([[Invalid AdminBlocker Type!
  3552. Type 0: Admins can kick/ban another admin.
  3553. Type 1: Admins can't kick/ban other admins with higher level.
  3554. Type 2: Admins can't kick/ban other admins with higher or equal level.
  3555. Type 3: Admins can't kick/ban other admins unless they can do all commands.]], executorPlayerId)
  3556.                 return
  3557.             end
  3558.  
  3559.             if abtype == 0 then
  3560.                 defaults.adminblocker = "Unsafe"
  3561.                 sendresponse("Admins now can kick/ban other admins", executorPlayerId)
  3562.             elseif abtype == 1 then
  3563.                 defaults.adminblocker = "Lenient"
  3564.                 sendresponse("Admins now cannot kick/ban other admins with higher levels.", executorPlayerId)
  3565.             elseif abtype == 2 then
  3566.                 defaults.adminblocker = "Moderate"
  3567.                 sendresponse("Admins now cannot kick/ban other admins with higher or equal levels.", executorPlayerId)
  3568.             elseif abtype == 3 then
  3569.                 defaults.adminblocker = "Strict"
  3570.                 sendresponse("Admins now cannot kick/ban other admins unless they can do all commands.", executorPlayerId)
  3571.             elseif defaults.adminblocker == "Unsafe" then
  3572.                 sendresponse("Admins currently can kick/ban other admins", executorPlayerId)
  3573.             elseif defaults.adminblocker == "Lenient" then
  3574.                 sendresponse("Admins currently cannot kick/ban other admins with higher levels.", executorPlayerId)
  3575.             elseif defaults.adminblocker == "Moderate" then
  3576.                 sendresponse("Admins currently cannot kick/ban other admins with higher or equal levels.", executorPlayerId)
  3577.             elseif defaults.adminblocker == "Strict" then
  3578.                 sendresponse("Admins currently cannot kick/ban another admins unless they have full access.", executorPlayerId)
  3579.             end
  3580.         end
  3581.     }
  3582. )
  3583.  
  3584. Commands.Create(
  3585.     "antispam",
  3586.     {
  3587.         help = [[-- AntiSpam
  3588.         -- Syntax: %s {all | players | off}
  3589.         -- All = All Players cannot spam in the chat.
  3590.         -- Players = All Players EXCEPT Admins cannot spam in the chat.
  3591.         -- Off = Disables AntiSpam functionality]]
  3592.     },
  3593.     {
  3594.         arguments = {"String", minArgs = 0, maxArgs = 1},
  3595.         func = function(executorPlayerId, mode)
  3596.             if mode ~= "all" and mode ~= "players" and mode ~= "off" then
  3597.                 sendresponse("Invalid mode. Valid modes are 'all', 'players' and 'off'", executorPlayerId)
  3598.                 return
  3599.             end
  3600.            
  3601.             if mode then
  3602.                 defaults.antispam = mode
  3603.                 sendresponse("AntiSpam now set to " .. defaults.antispam, executorPlayerId)
  3604.             else
  3605.                 sendresponse("AntiSpam is set to " .. defaults.antispam, executorPlayerId)
  3606.             end
  3607.         end
  3608.     }
  3609. )
  3610.  
  3611. Commands.Create(
  3612.     "balance",
  3613.     {
  3614.         help = [[-- Balance Teams
  3615.         -- Syntax: %s
  3616.         -- Balances the number of players on each team.
  3617.         -- This command can ONLY be executed on Teamplay GameTypes like CTF.]]
  3618.     },
  3619.     {
  3620.         arguments = {minArgs = 0, maxArgs = 0},
  3621.         func = function(executorPlayerId)
  3622.             if not team_play then
  3623.                 sendresponse("This command is disabled since it is not a team based game.", executorPlayerId)
  3624.                 return
  3625.             end
  3626.            
  3627.             local msg = "Balancing Teams"
  3628.             local redsize = getteamsize(0)
  3629.             local bluesize = getteamsize(1)
  3630.             if bluesize > redsize and cur_players % 2 ~= 1 then
  3631.                 changeteam(SelectRandomPlayer(1), true)
  3632.             elseif bluesize < redsize and cur_players % 2 ~= 1 then
  3633.                 changeteam(SelectRandomPlayer(0), true)
  3634.             else
  3635.                 msg = "Teams are balanced."
  3636.             end
  3637.            
  3638.             say(msg)
  3639.             sendresponse("The teams have now been balanced", executorPlayerId)
  3640.         end
  3641.     }
  3642. )
  3643.  
  3644. Commands.Create(
  3645.     "banpenalty",
  3646.     {
  3647.         help = [[-- Ban Penalty
  3648.         -- Syntax: %s {1st Bantime} {2nd Bantime} {3rd Bantime} etc..
  3649.         -- Determines how much time a player can be banned when the time argument '0' is used in a ban command.]]
  3650.     },
  3651.     {
  3652.         arguments = {"Time String", minArgs = 0, maxArgs = 1},
  3653.         func = function(executorPlayerId, times)
  3654.             if not times then
  3655.                 for i = 1,#ban_penalty do
  3656.                     cmdreply[cmdreply()] = "Ban Penalty #" .. i .. ": " .. ban_penalty[i]
  3657.                 end
  3658.                
  3659.                 sendresponse(cmdreply, executorPlayerId)
  3660.             else
  3661.                 local i = 1
  3662.                 local length = #ban_penalty
  3663.                 for time in string.gmatch(times, "%d+[cywdhms]") do time = wordtotime(time)
  3664.                     ban_penalty[i] = time
  3665.                     i = i + 1
  3666.                 end
  3667.                 while length >= i do
  3668.                     ban_penalty[i] = nil
  3669.                     i = i + 1
  3670.                 end
  3671.                 sendresponse("The Ban Penalties have been changed to: " .. times, executorPlayerId)
  3672.             end
  3673.         end
  3674.     }
  3675. )
  3676. Commands.Create(
  3677.     "ban",
  3678.     {
  3679.         aliases = {"hashban", "b", "playerban", "banplayer"},
  3680.         usesBanCounts = true,
  3681.         help = [[-- Ban
  3682.         -- Syntax: %s [Player, Hash, or IP Address] {Time} {Reason}
  3683.         -- Bans the Player/Hash/IP Address from the server with a reason written to the BanReasons log file]]
  3684.     },
  3685.     {
  3686.         arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3},
  3687.         func = function(executorPlayerId, players, time, reason)
  3688.             local exname = executorPlayerId and getname(executorPlayerId) or "the Server"
  3689.             local playerId, name, hash
  3690.             for i = 1,#players do playerId = players[i]
  3691.            
  3692.                 name = getname(playerId)
  3693.                 if not checkAdminBlockerAccess(executorPlayerId, playerId) then
  3694.                     sendresponse("You cannot use this command on " .. name, executorPlayerId)
  3695.                     privatesay(playerId, exname .. " attemped to use Ban on you!")
  3696.                     goto continue
  3697.                 end
  3698.            
  3699.                 hash = gethash(playerId)
  3700.                 for i = 1,#sharedhashes do
  3701.                     if hash == sharedhashes[i] then
  3702.                         cmdreply[cmdreply()] = name .. " has a shared hash, and therefore cannot be hashbanned. Try an IP Ban instead."
  3703.                         goto continue
  3704.                     end
  3705.                 end
  3706.                 addBan(name, gethash(playerId), nil, time, "hash", reason)
  3707.                 WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was banned by " .. exname .. " Reason: " .. reason .. " Type: Hash Ban")
  3708.                 say(name .. " has been banned by " .. exname .. " Reason: " .. reason)
  3709.                 cmdreply[cmdreply()] = name .. " has been banned from the server"
  3710.                 registertimer(0, "tempBanPlayer", resolveplayer(playerId))
  3711.                 updateBanFiles()
  3712.                
  3713.                 ::continue::
  3714.             end
  3715.            
  3716.             sendresponse(cmdreply, executorPlayerId)
  3717.         end
  3718.     },
  3719.     {
  3720.         arguments = {"Hash", "Time And Reason", minArgs = 1, maxArgs = 3},
  3721.         func = function(executorPlayerId, hash, time, reason)
  3722.             local exname = executorPlayerId and getname(executorPlayerId) or "the Server"
  3723.            
  3724.             for i = 1,#sharedhashes do
  3725.                 if hash == sharedhashes[i] then
  3726.                     sendresponse("That is a shared hash, and therefore cannot be hashbanned. Try an IP Ban instead.", executorPlayerId)
  3727.                     return
  3728.                 end
  3729.             end
  3730.            
  3731.             -- Check if a person in this server has this hash.
  3732.             for i = 0,15 do
  3733.                 if getplayer(i) and gethash(i) == hash then
  3734.                     registertimer(0, "tempBanPlayer", resolveplayer(playerId))
  3735.                 end
  3736.             end
  3737.             addBan("manual_ban" .. #ban_table, hash, nil, time, "hash", reason)
  3738.             WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", "Hash '" .. hash .. "' was banned by " .. exname .. " Reason: " .. reason .. " Type: Hash Ban")
  3739.             updateBanFiles()
  3740.             sendresponse("That hash has been banned from the server successfully", executorPlayerId)
  3741.         end
  3742.     },
  3743.     {
  3744.         arguments = {"IP Address", "Time And Reason", minArgs = 1, maxArgs = 3},
  3745.         func = function(executorPlayerId, ip_address, time, reason)
  3746.             local exname = executorPlayerId and getname(executorPlayerId) or "the Server"
  3747.            
  3748.             -- Check if a person in this server has this IP Address.
  3749.             for i = 0,15 do
  3750.                 if getplayer(i) and netMatch(ip_address, getip(i)) then
  3751.                     registertimer(0, "tempBanPlayer", resolveplayer(playerId))
  3752.                 end
  3753.             end
  3754.             addBan("manual_ban" .. #ban_table, nil, ip_address, time, "ip", reason)
  3755.             WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", "IP Address '" .. ip_address .. "' was banned by " .. exname .. " Reason: " .. reason .. " Type: IP Ban")
  3756.             updateBanFiles()
  3757.             sendresponse("That IP Address has been banned from the server successfully", executorPlayerId)
  3758.         end
  3759.     }
  3760. )
  3761.  
  3762. Commands.Create(
  3763.     "bos",
  3764.     {
  3765.         help = [[Ban on Sight
  3766.         -- Syntax: %s [Bosplayer Index]
  3767.         -- Add the specified player to the Ban On Sight (BOS) list.
  3768.         -- The next time this person joins the server, they will be banned.
  3769.         -- This command explicitly requires a number for an index.
  3770.         -- This index must be the player index of a player who has left the server.
  3771.         -- Use 'sv_bosplayers' to get a list of players to add to the BOS list.]]
  3772.     },
  3773.     {
  3774.         arguments = {"String", minArgs = 1, maxArgs = 1},
  3775.         func = function(executorPlayerId, playerId)
  3776.  
  3777.             local leave_entry = leave_table[playerId]
  3778.             if not leave_entry then
  3779.                 sendresponse("Invalid Player", executorPlayerId)
  3780.                 return
  3781.             end
  3782.            
  3783.             local found, bos_entry
  3784.             for i = 1,#bos_table do bos_entry = bos_table[i]
  3785.                 if leave_entry.hash == bos_entry.hash or leave_entry.ip == bos_entry.ip then
  3786.                 found = true
  3787.             end
  3788.             end
  3789.             if found then
  3790.                 sendresponse(leave_entry.name .. " is already on the BoS", executorPlayerId)
  3791.             else
  3792.                 cmdreply[cmdreply()] = "Adding " .. leave_entry.name .. " to BoS."
  3793.                 cmdreply[cmdreply()] = "Entry: " .. leave_entry.name .. " - " .. leave_entry.hash .. " - " .. leave_entry.ip
  3794.                 sendresponse(cmdreply, executorPlayerId)
  3795.                 bos_table[#bos_table+1] = leave_entry
  3796.             end
  3797.         end
  3798.     }
  3799. )
  3800.  
  3801. Commands.Create(
  3802.     "kickbansfile",
  3803.     {
  3804.         help = [[-- Kicks and Bans Log File Name
  3805.         -- Syntax: %s {Filename}
  3806.         -- Allows the executor to view and change the name of the 'BanReasons.log' file.]],
  3807.     },
  3808.     {
  3809.         arguments = {"String", minArgs = 0, maxArgs = 1},
  3810.         func = function(executorPlayerId, filename)
  3811.             if not filename then
  3812.                 sendresponse("The current KickBans file name is " .. defaults.kickbans_file .. ".log", executorPlayerId)
  3813.             elseif match(filename, "%w+") then
  3814.                 defaults.kickbans_file = filename
  3815.                 sendresponse("The KickBans file has been changed to " .. defaults.kickbans_file .. ".log", executorPlayerId)
  3816.             else
  3817.                 sendresponse("File names must contain alphanumerical characters only!", executorPlayerId)
  3818.             end
  3819.         end
  3820.     }
  3821. )
  3822.  
  3823. Commands.Create(
  3824.     "commandsfile",
  3825.     {
  3826.         help = [[-- Commands Log File Name
  3827.         -- Syntax: %s {Filename}
  3828.         -- Allows the executor to view and change the name of the 'commands.log' file.]],
  3829.     },
  3830.     {
  3831.         arguments = {"String", minArgs = 0, maxArgs = 1},
  3832.         func = function(executorPlayerId, filename)
  3833.             if not filename then
  3834.                 sendresponse("The current KickBans file name is " .. defaults.commands_file .. ".log", executorPlayerId)
  3835.             elseif match(filename, "%w+") then
  3836.                 defaults.commands_file = filename
  3837.                 sendresponse("The KickBans file has been changed to " .. defaults.commands_file .. ".log", executorPlayerId)
  3838.             else
  3839.                 sendresponse("File names must contain alphanumerical characters only!", executorPlayerId)
  3840.             end
  3841.         end
  3842.     }
  3843. )
  3844.  
  3845. Commands.Create(
  3846.     "adminfile",
  3847.     {
  3848.         help = [[-- Admins Text File Name
  3849.         -- Syntax: %s {Filename}
  3850.         -- Allows the executor to view and change the name of the 'admins.txt' file.]],
  3851.     },
  3852.     {
  3853.         arguments = {"String", minArgs = 0, maxArgs = 1},
  3854.         func = function(executorPlayerId, filename)
  3855.             if not filename then
  3856.                 sendresponse("The current Admins file name is " .. defaults.admin_file .. ".txt", executorPlayerId)
  3857.             elseif match(filename, "%w+") then
  3858.                 defaults.admin_file = filename
  3859.                 sendresponse("The Admins file has been changed to " .. defaults.admin_file .. ".txt", executorPlayerId)
  3860.             else
  3861.                 sendresponse("File names must contain alphanumerical characters only!", executorPlayerId)
  3862.             end
  3863.         end
  3864.     }
  3865. )
  3866.  
  3867. Commands.Create(
  3868.     "sharedhashfile",
  3869.     {
  3870.         help = [[-- Shared Hashes Text File Name
  3871.         -- Syntax: %s {Filename}
  3872.         -- Allows the executor to view and change the name of the 'sharedhashes.txt' file.
  3873.         -- The Shared Hashes file contain hashes that cannot be banned, because they are used by lots of different players.]],
  3874.     },
  3875.     {
  3876.         arguments = {"String", minArgs = 0, maxArgs = 1},
  3877.         func = function(executorPlayerId, filename)
  3878.             if not filename then
  3879.                 sendresponse("The current Shared Hashes file name is " .. defaults.sharedhash_file .. ".txt", executorPlayerId)
  3880.             elseif match(filename, "%w+") then
  3881.                 defaults.sharedhash_file = filename
  3882.                 sendresponse("The Shared Hashes file has been changed to " .. defaults.sharedhash_file .. ".txt", executorPlayerId)
  3883.             else
  3884.                 sendresponse("File names must contain alphanumerical characters only!", executorPlayerId)
  3885.             end
  3886.         end
  3887.     }
  3888. )
  3889.  
  3890. Commands.Create(
  3891.     "banlistfile",
  3892.     {
  3893.         help = [[-- Kicks and Bans Log File Name
  3894.         -- Syntax: %s {Filename}
  3895.         -- Allows the executor to view and change the name of the 'banned.txt' file.]],
  3896.     },
  3897.     {
  3898.         arguments = {"String", minArgs = 0, maxArgs = 1},
  3899.         func = function(executorPlayerId, filename)
  3900.             if not filename then
  3901.                 sendresponse("The current Banlist File Name is " .. defaults.banlist_file .. ".txt", executorPlayerId)
  3902.             elseif match(filename, "%w+") then
  3903.                 defaults.banlist_file = filename
  3904.                 sendresponse("The Banlist file has been changed to " .. defaults.banlist_file .. ".txt", executorPlayerId)
  3905.             else
  3906.                 sendresponse("File names must contain alphanumerical characters only!", executorPlayerId)
  3907.             end
  3908.         end
  3909.     }
  3910. )
  3911.  
  3912. Commands.Create(
  3913.     "banlist",
  3914.     {
  3915.         aliases = {"ipbanlist", "namebanlist", "hashbanlist", "textbanlist"},
  3916.         help = [[-- Ban List
  3917.         -- Syntax: %s {ip | hash | chat | name}
  3918.         -- Displays all players banned from the server.
  3919.         -- Specifying a second argument will filter the list by the specified bantype.]]
  3920.     },
  3921.     {
  3922.         arguments = {"String", minArgs = 0, maxArgs = 1},
  3923.         func = function(executorPlayerId, bantype)
  3924.  
  3925.             -- Don't need to do anything if the banlist is empty.
  3926.             if not ban_table[1] then
  3927.                 sendresponse("The Banlist is empty", executorPlayerId)
  3928.                 return
  3929.             end
  3930.            
  3931.             if bantype and bantype ~= "name" and bantype ~= "chat" and bantype ~= "hash" and bantype ~= "ip" then
  3932.                 sendresponse("Invalid Bantype. Valid bantypes are ip, hash, name, and chat", executorPlayerId)
  3933.                 return
  3934.             end
  3935.            
  3936.             cmdreply.header = "[ID | Name | Bans | Expires | Reason]"
  3937.             cmdreply.delim = "|"
  3938.             cmdreply.align = true
  3939.             local ban_entry, time, timeleft
  3940.             for id = 1,#ban_table do ban_entry = ban_table[id]
  3941.                 if ban_entry.time ~= "Unbanned" then
  3942.                     -- the only time a ban entry's time can be nil is if it expired, and if so don't display it
  3943.                     time = ban_entry.time
  3944.                     timeleft = time ~= "Unbanned" and time ~= -1 and time - os.time() or 0
  3945.                     if time == -1 or timeleft > 0 then
  3946.                         if not bantype or bantype == ban_entry.type then
  3947.                             cmdreply[cmdreply()] = format("[%u | %s | %s | %s | %s]", id, ban_entry.name, ban_entry.count or "N/A", time ~= -1 and formatTime(timeleft) or "Never", ban_entry.reason or "None")
  3948.                         end
  3949.                     end
  3950.                 end
  3951.             end
  3952.            
  3953.             sendresponse(cmdreply, executorPlayerId)
  3954.         end
  3955.     }
  3956. )
  3957.  
  3958. Commands.Create(
  3959.     "unban",
  3960.     {
  3961.         aliases = {"ipunban", "hashunban", "textunban", "nameunban"},
  3962.         help = [[-- Unban
  3963.         -- Syntax: %s [ID]
  3964.         -- Unbans the specified player.]]
  3965.     },
  3966.     {
  3967.         arguments = {"Positive Number", minArgs = 1, maxArgs = 1},
  3968.         func = function(executorPlayerId, ID)
  3969.             local entry = ban_table[ID]
  3970.             if not entry then
  3971.                 sendresponse("Invalid ID", executorPlayerId)
  3972.                 return
  3973.             end
  3974.            
  3975.             local index = (entry.ip or "") .. ":" .. (entry.hash or "") .. ":" .. entry.name
  3976.             if entry.type == "chat" then
  3977.                 -- unmute them if they are currently in the game.
  3978.                 for i = 0,15 do
  3979.                     if getplayer(i) and netMatch(entry.ip, getip(i)) then
  3980.                         ip_table[getip(i)].muted = false
  3981.                     end
  3982.                 end
  3983.             end
  3984.             local bantype = entry.type
  3985.             entry.time = "Unbanned"
  3986.             updateBanFiles(bantype) -- update banlist file.
  3987.             sendresponse(bantype .. " ban '" .. index .. "' has been unbanned from the banlist!", executorPlayerId)
  3988.         end
  3989.     }
  3990. )
  3991.  
  3992. Commands.Create(
  3993.     "boslist",
  3994.     {
  3995.         help = [[-- Ban on Sight List
  3996.         -- Syntax: %s
  3997.         -- Display the Ban On Sight list]]
  3998.     },
  3999.     {
  4000.         arguments = {minArgs = 0, maxArgs = 0},
  4001.         func = function(executorPlayerId)
  4002.    
  4003.             if not bos_table[1] then
  4004.                 sendresponse("The Ban on Sight list is empty!", executorPlayerId)
  4005.                 return
  4006.             end
  4007.  
  4008.             cmdreply.header = "[ID | Name | Hash | IP]"
  4009.             cmdreply.delim = "|"
  4010.             cmdreply.align = true
  4011.             local bos_entry
  4012.             for id = 1,#bos_table do bos_entry = bos_table[id]
  4013.                 cmdreply[cmdreply()] = format("[%u | %s | %s | %s]", id, bos_entry.name, bos_entry.hash, bos_entry.ip)
  4014.             end
  4015.             sendresponse(cmdreply, executorPlayerId)
  4016.             end
  4017.     }
  4018. )
  4019.  
  4020.  
  4021. Commands.Create(
  4022.     "bosplayers",
  4023.     {
  4024.         aliases = {"bosableplayers"},
  4025.         help = [[-- Bosable Players List
  4026.         -- Syntax: %s
  4027.         -- Shows the available players that can be banned on sight.]]
  4028.     },
  4029.     {
  4030.         arguments = {minArgs = 0, maxArgs = 0},
  4031.         func = function(executorPlayerId)
  4032.    
  4033.             if not next(leave_table) then
  4034.                 sendresponse("There are no players that can be added as a BOS right now", executorPlayerId)
  4035.                 return
  4036.             end
  4037.            
  4038.             cmdreply.header = "[ID | Name]"
  4039.             cmdreply.delim = "|"
  4040.             cmdreply.align = true
  4041.             local leave_entry
  4042.             for i = 1,16 do leave_entry = leave_table[i]
  4043.                 if leave_entry then
  4044.                     cmdreply[cmdreply()] = "[" .. i .. " | " .. leave_entry.name .. " | " .. leave_entry.ip .. "]"
  4045.                 end
  4046.             end
  4047.            
  4048.             sendresponse(cmdreply, executorPlayerId)
  4049.            
  4050.         end
  4051.     }
  4052. )
  4053.  
  4054. Commands.Create(
  4055.     "changelevel",
  4056.     {
  4057.         aliases = {"adminlevel", "levelchange", "level", "modifylevel"},
  4058.         help = [[-- Change Level Command
  4059.         -- Syntax: %s [nickname] {level}
  4060.         -- Change the specified admins' level]]
  4061.     },
  4062.     {
  4063.         arguments = {"String", "Access Level", minArgs = 1, maxArgs = 1},
  4064.         func = function(executorPlayerId, nickname, level)
  4065.    
  4066.             if not next(admin_table) then
  4067.                 sendresponse("There are no admins on this server" , executorPlayerId)
  4068.                 return
  4069.             end
  4070.            
  4071.             local found
  4072.             for k,thisAdmin in next,admin_table do
  4073.                 if thisAdmin.name == nickname then
  4074.                     if level then
  4075.                         thisAdmin.level = level
  4076.                         cmdreply[cmdreply()] = nickname .. " is now a level " .. level .. (thisAdmin.type == "ip" and " IP Admin" or " Hash Admin")
  4077.                     else
  4078.                         cmdreply[cmdreply()] = nickname .. " is a level " .. thisAdmin.level .. (thisAdmin.type == "ip" and " IP Admin" or " Hash Admin")
  4079.                     end
  4080.                     found = true
  4081.                     break
  4082.                 end
  4083.             end
  4084.             if not found then
  4085.                 sendresponse("Invalid Nickname" , executorPlayerId)
  4086.             end
  4087.            
  4088.             sendresponse(cmdreply, executorPlayerId)
  4089.            
  4090.         end
  4091.     }
  4092. )
  4093.  
  4094. Commands.Create(
  4095.     "changeteam",
  4096.     {
  4097.         aliases = {"ts", "teamchange"},
  4098.         help = [[-- Change team Command
  4099.         -- Syntax: %s [player]
  4100.         -- Change the specified players team]]
  4101.     },
  4102.     {
  4103.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  4104.         func = function(executorPlayerId, players)
  4105.    
  4106.             local playerId
  4107.             for i = 1,#players do playerId = players[i]
  4108.                 changeteam(playerId, true)
  4109.                 cmdreply[cmdreply()] = getname(playerId) .. " has been forced to change teams"
  4110.             end
  4111.            
  4112.             sendresponse(cmdreply, executorPlayerId)
  4113.         end
  4114.     }
  4115. )
  4116.  
  4117. Commands.Create(
  4118.     "disconnect",
  4119.     {
  4120.         aliases = {"losenetworkconnection", "dc"},
  4121.         help = [[-- Disconnect Player
  4122.         -- Syntax: %s [player]
  4123.         -- Will forcibly cause the player to lose connection to the server,
  4124.         -- This will not affect the server]]
  4125.     },
  4126.     {
  4127.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  4128.         func = function(executorPlayerId, players)
  4129.  
  4130.             local machine_base = readdword(addresses.network_struct) -- Confirmed.
  4131.             local machine_table = machine_base + 0xAA0 -- Confirmed. Player machine table
  4132.             local playerId, m_player, player_machine_index, machine_struct, machine_network
  4133.             for i = 1,#players do playerId = players[i]
  4134.                 m_player = getplayer(playerId)
  4135.                 player_machine_index = readbyte(m_player + 0x64)
  4136.                 machine_struct = readdword(machine_table + player_machine_index*4)
  4137.                 machine_network = readdword(readdword(machine_struct))
  4138.                 writebyte(machine_network, 0)
  4139.                 halo_svcmd("sv_kick " .. resolveplayer(playerId)) -- just because it takes ages for the server to figure out they quit
  4140.                 cmdreply[cmdreply()] = getname(playerId) .. " has lost connection successfully."
  4141.             end
  4142.            
  4143.             sendresponse(cmdreply, executorPlayerId)
  4144.  
  4145.         end
  4146.     }
  4147. )
  4148.  
  4149. Commands.Create(
  4150.     "count",
  4151.     {
  4152.         aliases = {"uniques", "uniqueplayers"},
  4153.         help = [[-- Count
  4154.         -- Syntax: %s
  4155.         -- It will display the number of unique users.]]
  4156.     },
  4157.     {
  4158.         arguments = {minArgs = 0, maxArgs = 0},
  4159.         func = function(executorPlayerId)
  4160.        
  4161.             if not defaults.uniques_enabled then
  4162.                 sendresponse("'sv_uniques_enabled' is currently disabled.", executorPlayerId)
  4163.                 return
  4164.             end
  4165.            
  4166.             sendresponse("There are " .. unique_table.total .. " unique users that have been to this server", executorPlayerId)
  4167.         end
  4168.     }
  4169. )
  4170.  
  4171. Commands.Create(
  4172.     "commands",
  4173.     {
  4174.         aliases = {"cmds", "commandlist", "list"},
  4175.         help = [[-- Commands
  4176.         --Syntax %s
  4177.         -- Lists the commands you are allowed to executed]]
  4178.     },
  4179.     {
  4180.         arguments = {minArgs = 0, maxArgs = 0},
  4181.         func = function(executorPlayerId)
  4182.  
  4183.             if not executorPlayerId then
  4184.                 sendresponse("All Commands: " .. concat(Commands, ", "), executorPlayerId)
  4185.                 return
  4186.             end
  4187.            
  4188.             local level = player_table[executorPlayerId].admin_entry.level
  4189.             if access_table[level] == -1 then
  4190.                 sendresponse("All Commands: " .. concat(Commands, ", "), executorPlayerId)
  4191.             else
  4192.                 sendresponse(access_table[level], executorPlayerId)
  4193.             end
  4194.         end
  4195.     }
  4196. )
  4197.  
  4198. Commands.Create(
  4199.     "crash",
  4200.     {
  4201.         scrimBlock = true,
  4202.         help = [[-- Crash Player's Game
  4203.         -- Syntax: %s [player]
  4204.         -- This command will crash the players game,
  4205.         -- This will not affect the server]]
  4206.     },
  4207.     {
  4208.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  4209.         func = function(executorPlayerId, players)
  4210.                    
  4211.             if gameend then
  4212.                 sendresponse("You cannot crash a player while the game is ended. Wait until next game.", executorPlayerId)
  4213.                 return
  4214.             end
  4215.            
  4216.             local exname = getname(executorPlayerId)
  4217.            
  4218.             local playerId, objectId, name
  4219.             for i = 1,#players do playerId = players[i]
  4220.            
  4221.                 name = getname(playerId)
  4222.                 if not checkAdminBlockerAccess(executorPlayerId, playerId) then
  4223.                     sendresponse("You cannot use this command on " .. name, executorPlayerId)
  4224.                     privatesay(playerId, exname .. " attemped to use Crash on you!")
  4225.                     goto continue
  4226.                 end
  4227.            
  4228.                 objectId = createobject(gettag("vehi", "vehicles\\warthog\\mp_warthog"), 0, 1, false, 0, 1, 2)
  4229.                 entervehicle(playerId, objectId, 5)
  4230.                 destroyobject(objectId)
  4231.                 cmdreply[cmdreply()] = name .. " had their game crashed by an admin"
  4232.                
  4233.                 ::continue::
  4234.             end
  4235.            
  4236.             sendresponse(cmdreply, executorPlayerId)
  4237.         end
  4238.     }
  4239. )
  4240.  
  4241. Commands.Create(
  4242.     "damage",
  4243.     {
  4244.         aliases = {"dmg", "setdmg", "setdmgmulti", "setdamage"},
  4245.         scrimBlock = true,
  4246.         help = [[-- Damage Multiplier
  4247.         -- Syntax: %s [player] [damage multiplier]
  4248.         -- Increases the amount of damage the player does.]]
  4249.     },
  4250.     {
  4251.         arguments = {"Player", "Number", minArgs = 1, maxArgs = 1},
  4252.         func = function(executorPlayerId, players, value)
  4253.             local playerId
  4254.             for i = 1,#players do playerId = players[i]
  4255.                 if value then
  4256.                     player_table[playerId].dmgmultiplier = value
  4257.                     cmdreply[cmdreply()] = getname(playerId) .. " now has a damage multiplier of " .. value
  4258.                 else
  4259.                     cmdreply[cmdreply()] = getname(playerId) .. " has a damage multiplier of " .. player_table[playerId].dmgmultiplier
  4260.                 end
  4261.             end
  4262.            
  4263.             sendresponse(cmdreply, executorPlayerId)
  4264.         end
  4265.     }
  4266. )
  4267.  
  4268. Commands.Create(
  4269.     "delrcon",
  4270.     {
  4271.         aliases = {"rcondel"},
  4272.         help = [[-- Delete Rcon Password
  4273.         -- Syntax: %s {password}
  4274.         -- Deletes the rcon password.]]
  4275.     },
  4276.     {
  4277.         arguments = {"String", minArgs = 1, maxArgs = 1},
  4278.         func = function(executorPlayerId, password)
  4279.            
  4280.             if not rcon_passwords[password] then
  4281.                 sendresponse(password .. " is not an rcon password", executorPlayerId)
  4282.                 return
  4283.             end
  4284.            
  4285.             rcon_passwords[password] = nil
  4286.             sendresponse(password .. " is no longer an rcon password", executorPlayerId)
  4287.         end
  4288.     }
  4289. )
  4290.  
  4291. Commands.Create(
  4292.     "eject",
  4293.     {
  4294.         aliases = {"playereject", "ejectplayer"},
  4295.         scrimBlock = true,
  4296.         help = [[-- Eject
  4297.         -- Syntax: %s [player]
  4298.         -- Force the specified players to exit their vehicle]]
  4299.     },
  4300.     {
  4301.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  4302.         func = function(executorPlayerId, players)
  4303.    
  4304.             local playerId, m_playerObj
  4305.             for i = 1,#players do playerId = players[i]
  4306.                 m_playerObj = getplayerobject(playerId)
  4307.                 if m_playerObj then
  4308.                     if isinvehicle(playerId) then
  4309.                         exitvehicle(playerId)
  4310.                         cmdreply[cmdreply()] = "Ejecting " .. getname(playerId) .. " from their vehicle"
  4311.                     else
  4312.                         cmdreply[cmdreply()] = getname(playerId) .. " is not in a vehicle"
  4313.                     end
  4314.                 else
  4315.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  4316.                 end
  4317.             end
  4318.            
  4319.             sendresponse(cmdreply, executorPlayerId)
  4320.         end
  4321.     }
  4322. )
  4323.  
  4324. Commands.Create(
  4325.     "gethash",
  4326.     {
  4327.         aliases = {"hash", "gethash"},
  4328.         help = [[-- Get Player Hash
  4329.         -- Syntax: %s [Player]
  4330.         -- Gets the specified player's hash]]
  4331.     },
  4332.     {
  4333.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  4334.         func = function(executorPlayerId, players)
  4335.            
  4336.             local playerId
  4337.             for i = 1,#players do playerId = players[i]
  4338.                 cmdreply[cmdreply()] = getname(playerId) .. ": " .. gethash(playerId)
  4339.             end
  4340.            
  4341.             sendresponse(cmdreply, executorPlayerId)
  4342.         end
  4343.     }
  4344. )
  4345.  
  4346. Commands.Create(
  4347.     "getip",
  4348.     {
  4349.         help = [[-- Get IP
  4350.         -- Syntax: %s [Player]
  4351.         -- Get the specified playersIP address]]
  4352.     },
  4353.     {
  4354.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  4355.         func = function(executorPlayerId, players)
  4356.    
  4357.             local playerId
  4358.             for i = 1,#players do playerId = players[i]
  4359.                 cmdreply[cmdreply()] = getname(playerId) .. ": " .. getip(playerId)
  4360.             end
  4361.            
  4362.             sendresponse(cmdreply, executorPlayerId)
  4363.         end
  4364.     }
  4365. )
  4366.  
  4367. Commands.Create(
  4368.     "getloc",
  4369.     {
  4370.         aliases = {"getplayerlocation", "getplayerloc", "getplayercoords", "getcoords", "coords", "playerloc", "playercoords"},
  4371.         help = [[-- Get Location
  4372.         -- Syntax: %s [Player]
  4373.         -- Get the specified players' coordinates in the server]]
  4374.     },
  4375.     {
  4376.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  4377.         func = function(executorPlayerId, players)
  4378.  
  4379.             local playerId
  4380.             for i = 1,#players do playerId = players[i]
  4381.                 local m_playerObj, playerObjId = getplayerobject(playerId)
  4382.                 if m_playerObj then
  4383.                     local x,y,z = getobjectcoords(playerObjId, m_playerObj)
  4384.                     x,y,z = round(x, 2),round(y, 2),round(z, 2)
  4385.                     cmdreply[cmdreply()] = getname(playerId) .. "'s coords are: X: " .. x .. "  Y: " .. y .. "  Z: " .. z
  4386.                 else
  4387.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  4388.                 end
  4389.             end
  4390.            
  4391.             sendresponse(cmdreply, executorPlayerId)
  4392.         end
  4393.     }
  4394. )
  4395.  
  4396. Commands.Create(
  4397.     "setgod",
  4398.     {
  4399.         aliases = {"god", "godmode", "godset"},
  4400.         scrimBlock = true,
  4401.         help = [[-- Set God
  4402.         -- Syntax: %s [Player]
  4403.         -- Gives you lots of health]]
  4404.     },
  4405.     {
  4406.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  4407.         func = function(executorPlayerId, players)
  4408.  
  4409.             if defaults.deathless then
  4410.                 sendresponse("Deathless is now enabled You cannot give out godmode", executorPlayerId)
  4411.                 return
  4412.             end
  4413.            
  4414.             local playerId, ptable, m_playerObj
  4415.             for i = 1,#players do playerId = players[i]
  4416.                 m_playerObj = getplayerobject(playerId)
  4417.                 if m_playerObj then
  4418.                     ptable = player_table[playerId]
  4419.                     if not ptable.godmode then
  4420.                         cmdreply[cmdreply()] = getname(playerId) .. " has been given godmode"
  4421.                         ptable.godmode = true
  4422.                     else
  4423.                         cmdreply[cmdreply()] = getname(playerId) .. " is already in godmode"
  4424.                     end
  4425.                 else
  4426.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  4427.                 end
  4428.             end
  4429.            
  4430.             sendresponse(cmdreply, executorPlayerId)
  4431.         end
  4432.     }
  4433. )
  4434.  
  4435. Commands.Create(
  4436.     "cheathax",
  4437.     {
  4438.         aliases = {"hax", "haxolu", "haxor", "1337"},
  4439.         scrimBlock = true,
  4440.         help = [[-- Cheat Hax
  4441.         -- Syntax: %s [Player]
  4442.         -- I will never tell]]
  4443.     },
  4444.     {
  4445.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  4446.         func = function(executorPlayerId, players)
  4447.  
  4448.             local playerId, m_player
  4449.             for i = 1,#players do playerId = players[i]
  4450.                 m_player = getplayer(playerId)
  4451.                 setscore(playerId, 9999)
  4452.                 writeshort(m_player + 0x9C, 9999)
  4453.                 writeshort(m_player + 0xA4, 9999)
  4454.                 writeshort(m_player + 0xAC, 9999)
  4455.                 writeshort(m_player + 0xAE, 9999)
  4456.                 writeshort(m_player + 0xB0, 9999)
  4457.                 cmdreply[cmdreply()] = getname(playerId) .. " has been haxed"
  4458.             end
  4459.  
  4460.             sendresponse(cmdreply, executorPlayerId)
  4461.         end
  4462.     }
  4463. )
  4464.  
  4465. Commands.Create(
  4466.     "heal",
  4467.     {
  4468.         aliases = {"healplayer", "playerheal"},
  4469.         scrimBlock = true,
  4470.         help = [[-- Heal
  4471.         -- Syntax: %s [Player]
  4472.         -- Heal the specified players]]
  4473.     },
  4474.     {
  4475.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  4476.         func = function(executorPlayerId, players)
  4477.  
  4478.             local playerId, m_playerObj, playerObjId, obj_health, m_vehicleObj, x, y, z, healthpack
  4479.             for i = 1,#players do playerId = players[i]
  4480.                 m_playerObj, playerObjId = getplayerobject(playerId)
  4481.                 if m_playerObj then
  4482.                     obj_health = readfloat(m_playerObj + 0xE0)
  4483.                     if obj_health < 1 then
  4484.                         m_vehicleObj = getplayervehicle(playerId)
  4485.                         if not m_vehicleObj then
  4486.                             x,y,z = getobjectcoords(playerObjId)
  4487.                             healthpack = getobject(createobject(gettag("eqip", "powerups\\health pack"), 0, 0, false, x, y, z+0.5))
  4488.                             if healthpack then writefloat(healthpack + 0x70, -2) end
  4489.                         else
  4490.                             writefloat(m_playerObj + 0xE0, 1)
  4491.                         end
  4492.                         cmdreply[cmdreply()] = getname(playerId) .. " has been healed"
  4493.                     else
  4494.                         cmdreply[cmdreply()] = getname(playerId) .. " is already at full health"
  4495.                     end
  4496.                 else
  4497.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  4498.                 end
  4499.             end
  4500.            
  4501.             sendresponse(cmdreply, executorPlayerId)
  4502.         end
  4503.     }
  4504. )
  4505.  
  4506. Commands.Create(
  4507.     "hide",
  4508.     {
  4509.         aliases = {"hideplayer", "playerhide"},
  4510.         scrimBlock = true,
  4511.         help = [[-- Hide
  4512.         -- Syntax: %s [Player]
  4513.         -- You are invisible. Not Camo.]]
  4514.     },
  4515.     {
  4516.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  4517.         func = function(executorPlayerId, players)
  4518.  
  4519.             local playerId, ptable
  4520.             for i = 1,#players do playerId = players[i]
  4521.                 ptable = player_table[playerId]
  4522.                 if not ptable.hidden then
  4523.                     cmdreply[cmdreply()] = getname(playerId) .. " is now hidden"
  4524.                     ptable.hidden = true
  4525.                 else
  4526.                     cmdreply[cmdreply()] = getname(playerId) .. " is already hidden"
  4527.                 end
  4528.             end
  4529.            
  4530.             sendresponse(cmdreply, executorPlayerId)
  4531.         end
  4532.     }
  4533. )
  4534.  
  4535. Commands.Create(
  4536.     "hitler",
  4537.     {
  4538.         aliases = {"genocide", "killall"},
  4539.         scrimBlock = true,
  4540.         help = [[-- Hitler
  4541.         -- Syntax: %s [Player]
  4542.         -- A lethal injection is given to the specified player.]]
  4543.     },
  4544.     {
  4545.         arguments = {minArgs = 0, maxArgs = 0},
  4546.         func = function(executorPlayerId)
  4547.    
  4548.             for i = 0,15 do
  4549.                 if getplayer(i) then
  4550.                     kill(i)
  4551.                     say(getname(i) .. " was shoved into an oven!")
  4552.                 end
  4553.             end
  4554.             sendresponse("The server has been purified.", executorPlayerId)
  4555.         end
  4556.     }
  4557. )
  4558.  
  4559. Commands.Create("info",
  4560.     {
  4561.         aliases = {"i", "playerinfo", "infoplayer"},
  4562.         help = [[-- Info
  4563.         Syntax: %s [Player]
  4564.         -- Returns a lot of info of the specified player]]
  4565.     },
  4566.     {
  4567.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  4568.         func = function(executorPlayerId, players)
  4569.    
  4570.             local gametype_maximum_health = readfloat(addresses.gametype_base + 0x54)
  4571.             local playerId
  4572.             for i = 1,#players do playerId = players[i]
  4573.                 local m_player = getplayer(playerId)
  4574.                 local ip = getip(playerId)
  4575.                 local ptable = player_table[playerId]
  4576.                 local iptable = ip_table[ip]
  4577.  
  4578.                 local team = getteam(playerId)
  4579.                 local teamsize = getteamsize(team)
  4580.                 team = team_play and (team == 0 and "Red" or team == 1 or "Blue" or "Hidden") or "FFA " .. team
  4581.                
  4582.                
  4583.                 local respawntime = round(readdword(m_player + 0x2C) * 0.033, 2)
  4584.                 local invis_time = round(readword(m_player + 0x68) * 0.033, 2)
  4585.                 local speed = readfloat(m_player + 0x6C)
  4586.                 local objective_mode = readbyte(m_player + 0x74)
  4587.                 local objective_mode2 = readbyte(m_player + 0x7A)
  4588.                 local killstreak = readword(m_player + 0x96)
  4589.                 local kills = readshort(m_player + 0x9C)
  4590.                 local assists = readshort(m_player + 0xA4)
  4591.                 local suicides = readshort(m_player + 0xB0)
  4592.                 local betrays = readshort(m_player + 0xAC) + suicides
  4593.                 local deaths = readshort(m_player + 0xAE)
  4594.                 local ping = readword(m_player + 0xDC)
  4595.                
  4596.                 local m_playerObj, playerObjId = getplayerobject(playerId)
  4597.  
  4598.                 local invis_info,crouch,health_info,objective_mode,flashlight_mode,flashlight_level
  4599.                 local x,y,z
  4600.                 local primary_weap_heat, primary_weap_age, primary_weap_ammo, primary_weap_clip, primary_weap_info
  4601.                 local secondary_weap_heat, secondary_weap_age, secondary_weap_ammo, secondary_weap_clip, secondary_weap_info
  4602.                 local primary_weap_info = "Primary: Empty"
  4603.                 local secondary_weap_info = "Secondary: Empty"
  4604.                 local weap_slot, nade_info
  4605.                 if m_playerObj then
  4606.                     local m_vehicleObj = getplayervehicle(playerId)
  4607.                     x,y,z = getobjectcoords(playerObjId)
  4608.                     x,y,z = round(x, 2),round(y, 2),round(z, 2)
  4609.                    
  4610.                     local health = round(readfloat(m_playerObj + 0xE0) * 100)
  4611.                     local shields = round(readfloat(m_playerObj + 0xE4) * 100)
  4612.                     local max_health = round(health * readfloat(m_playerObj + 0xD8) / 100)
  4613.                     local max_shields = round(shields * readfloat(m_playerObj + 0xDC) / 100)
  4614.                     flashlight_mode = readbit(m_playerObj + 0x204, 19) and "On" or "Off"
  4615.                     crouch = readbyte(m_playerObj + 0x2A0)
  4616.                     weap_slot = readbyte(m_playerObj + 0x2F2)
  4617.                     local nade_type = readbyte(m_playerObj + 0x31C)
  4618.                     local primary_nades = readbyte(m_playerObj + 0x31E)
  4619.                     local secondary_nades = readbyte(m_playerObj + 0x31F)
  4620.                     flashlight_level = round(readfloat(m_playerObj + 0x344) * 100)
  4621.                    
  4622.                     local invis_scale = round(readfloat(m_playerObj + 0x37C) * 100, 2)
  4623.                     invis_scale = invis_scale == 0 and "No" or invis_scale .. "%"
  4624.                     invis_info = invis_scale ~= "No" and "Invis: " .. invis_scale .. " (" .. invis_time .. " secs)" or "Invis: " .. invis_scale
  4625.  
  4626.                     local m_primaryWeapObj, m_secondaryWeapObj
  4627.                     if m_vehicleObj then
  4628.                         m_primaryWeapObj = getobject(readdword(m_vehicleObj + 0x2F8))
  4629.                     elseif weap_slot == 1 then
  4630.                         m_primaryWeapObj = getobject(readdword(m_playerObj + 0x2FC))
  4631.                         m_secondaryWeapObj = getobject(readdword(m_playerObj + 0x2F8))
  4632.                     else
  4633.                         m_primaryWeapObj = getobject(readdword(m_playerObj + 0x2F8))
  4634.                         m_secondaryWeapObj = getobject(readdword(m_playerObj + 0x2FC))
  4635.                     end
  4636.  
  4637.                     if m_primaryWeapObj then
  4638.                         local primary_weap_heat = round(readfloat(m_primaryWeapObj + 0x23C) * 100)
  4639.                         local primary_weap_age = round((1 - readfloat(m_primaryWeapObj + 0x240)) * 100)
  4640.                         local primary_weap_ammo = readword(m_primaryWeapObj + 0x2B6)
  4641.                         local primary_weap_clip = readword(m_primaryWeapObj + 0x2B8)
  4642.                         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
  4643.                     end
  4644.                     if m_secondaryWeapObj then
  4645.                         local secondary_weap_heat = round(readfloat(m_secondaryWeapObj + 0x23C) * 100)
  4646.                         local secondary_weap_age = round((1 - readfloat(m_secondaryWeapObj + 0x240)) * 100)
  4647.                         local secondary_weap_ammo = readword(m_secondaryWeapObj + 0x2B6)
  4648.                         local secondary_weap_clip = readword(m_secondaryWeapObj + 0x2B8)
  4649.                         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
  4650.                     end
  4651.                    
  4652.                     if crouch == 0 then
  4653.                         crouch = "Warthog: Driver"
  4654.                     elseif crouch == 1 then
  4655.                         crouch = "Warthog: Gunner"
  4656.                     elseif crouch == 2 then
  4657.                         crouch = "Warthog: Passenger"
  4658.                     elseif crouch == 3 then
  4659.                         crouch = "Stance: Crouching"
  4660.                     elseif crouch == 4 then
  4661.                         crouch = "Stance: Standing"
  4662.                     elseif crouch == 5 then
  4663.                         crouch = "Ghost: Driver"
  4664.                     elseif crouch == 6 then
  4665.                         crouch = "Banshee: Pilot"
  4666.                     elseif crouch == 13 then
  4667.                         crouch = "Scorpion: Driver"
  4668.                     elseif crouch == 17 then
  4669.                         crouch = "Shade: Gunner"
  4670.                     elseif crouch == 20 or crouch == 21 or crouch == 22 or crouch == 23 then
  4671.                         crouch = "Scorpion: Passenger"
  4672.                     end
  4673.                    
  4674.                     nade_info = "Frag Grenades: " .. primary_nades .. " | " .. "Plasma Grenades: " .. secondary_nades
  4675.                     nade_info = nade_type == 1 and "Plasma Grenades: " .. secondary_nades .. " | " .. "Frag Grenades: " .. primary_nades or nade_info
  4676.                    
  4677.                     if crouch == "Stance: Crouching" or crouch == "Stance: Standing" then
  4678.                         if readbyte(m_playerObj + 0x4CC) == 1 then
  4679.                             crouch = "Stance: Airborne"
  4680.                         end
  4681.                     end
  4682.                     if iptable.suspended then
  4683.                         health_info = "Respawn: Player is Suspended"
  4684.                     else
  4685.                         health_info = format("Health: %s%% (%s) | Shields: %s%% (%s)", health, max_health, shields, max_shields)
  4686.                     end
  4687.                 else
  4688.                     crouch = "Stance: Dead"
  4689.                     health_info = respawntime == 1 and "Respawn: " .. respawntime .. " sec" or "Respawn: " .. respawntime .. " secs"
  4690.                 end
  4691.                
  4692.                 if objective_mode == 0x22 and objective_mode2 == 0x71 then
  4693.                     objective_mode = "Hill"
  4694.                 elseif objective_mode == 0x23 and objective_mode2 == 0x71 then
  4695.                     objective_mode = "Juggernaut"
  4696.                 elseif objective_mode == 0x23 and objective_mode2 == 0x72 then
  4697.                     objective_mode = "It"
  4698.                 elseif objective_mode == 0x29 and objective_mode2 == 0x70 then
  4699.                     objective_mode = "Ball"
  4700.                 elseif weap_slot == 2 then
  4701.                     objective_mode = "Flag"
  4702.                 else
  4703.                     objective_mode = "None"
  4704.                 end
  4705.                
  4706.                 cmdreply.delim = "|"
  4707.                 cmdreply[cmdreply()] = "----------"
  4708.                 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)
  4709.                 cmdreply[cmdreply()] = format("Hash: %s | IP: %s", gethash(playerId), ip)
  4710.                 cmdreply[cmdreply()] = format("Admin: %s | Ping: %s | %s", ptable.admin_entry and "YES" or "NO", ping, crouch)
  4711.                 cmdreply[cmdreply()] = format("Kills: %s (%s) | Assists: %s | Betrays %s | Suicides %s | Deaths %s", kills, killstreak, assists, betrays, suicides, deaths)
  4712.                 cmdreply[cmdreply()] = format("%s | %s | Light: %s (%s%%)", health_info, invis_info, flashlight_mode, flashlight_level)
  4713.                 cmdreply[cmdreply()] = format("%s | %s | Objective: %s", primary_weap_info, secondary_weap_info, objective_mode)
  4714.                 cmdreply[cmdreply()] = nade_info
  4715.                 cmdreply[cmdreply()] = format("Hidden: %s | God: %s | AFK: %s", ptable.hidden, ptable.godmode, ptable.afk)
  4716.                 cmdreply[cmdreply()] = "----------"
  4717.                    
  4718.             end
  4719.            
  4720.             sendresponse(cmdreply, executorPlayerId)
  4721.         end
  4722.     }
  4723. )
  4724.  
  4725. Commands.Create(
  4726.     "ipban",
  4727.     {
  4728.         aliases = {"banip"},
  4729.         help = [[-- IP Ban
  4730.         -- Syntax: %s [Player or IP] {Time} {Reason}
  4731.         -- Will ban a player/ip from the server.]],
  4732.         usesBanCounts = true,
  4733.     },
  4734.     {
  4735.         arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3},
  4736.         func = function(executorPlayerId, players, time, reason)
  4737.  
  4738.             local exname = getname(executorPlayerId)
  4739.             local playerId, name
  4740.             for i = 1,#players do playerId = players[i]
  4741.            
  4742.                 name = getname(playerId)
  4743.                 if not checkAdminBlockerAccess(executorPlayerId, playerId) then
  4744.                     sendresponse("You cannot use this command on " .. name, executorPlayerId)
  4745.                     privatesay(playerId, exname .. " attemped to IPBan you!")
  4746.                     goto continue
  4747.                 end
  4748.                 addBan(name, nil, getip(playerId) .. "/24", time, "ip", reason)
  4749.                 WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was banned by " .. exname .. " Reason: " .. reason .. " Type: IP Ban")
  4750.                 if defaults.sa_message then
  4751.                     say(name .. " was IP banned by " .. exname .. " Reason: " .. reason)
  4752.                 else
  4753.                     say(name .. " was IP banned! Reason: " .. reason)
  4754.                 end
  4755.                 registertimer(0, "tempBanPlayer", resolveplayer(playerId))
  4756.                 cmdreply[cmdreply()] = name .. " has been IP banned"
  4757.                 sendresponse(cmdreply, executorPlayerId)
  4758.                
  4759.                 ::continue::
  4760.             end
  4761.         end
  4762.     },
  4763.     {
  4764.         arguments = {"IP Address", "Time And Reason", minArgs = 1, maxArgs = 3},
  4765.         func = function(executorPlayerId, ip_address, time, reason)
  4766.             local exname = getname(executorPlayerId)
  4767.             addBan("manual_ban" .. #ban_table+1, nil, ip_address, time, "ip", reason)
  4768.             WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", "The IP: " .. ip_address .. " was banned by " .. exname .. " Reason: " .. reason .. " Type: IP Ban")
  4769.             sendresponse(ip_address .. " has been IP banned successfully.", executorPlayerId)
  4770.         end
  4771.     }
  4772. )
  4773.  
  4774. Commands.Create(
  4775.     "invis",
  4776.     {
  4777.         aliases = {"camo", "camouflage", "setcamo"},
  4778.         help = [[-- Invis
  4779.         -- Syntax: %s [Player] {Time}
  4780.         -- Will camo the specified player.]]
  4781.     },
  4782.     {
  4783.         arguments = {"Player", "Time", minArgs = 1, maxArgs = 2},
  4784.         func = function(executorPlayerId, players, time)
  4785.    
  4786.             local playerId, m_playerObj, playerObjId, ptable
  4787.             for i = 1,#players do playerId = players[i]
  4788.                 m_playerObj, playerObjId = getplayerobject(playerId)
  4789.                 if not m_playerObj then
  4790.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  4791.                     goto continue
  4792.                 end
  4793.                
  4794.                 ptable = player_table[playerId]
  4795.                 if ptable.invisible then
  4796.                     cmdreply[cmdreply()] = getname(playerId) .. " is already invisible"
  4797.                     goto continue
  4798.                 end
  4799.                
  4800.                 ptable.invisible = time
  4801.                 cmdreply[cmdreply()] = getname(playerId) .. " is now invisible"
  4802.                
  4803.                 ::continue::
  4804.             end
  4805.            
  4806.             sendresponse(cmdreply, executorPlayerId)
  4807.         end
  4808.     }
  4809. )
  4810.  
  4811. Commands.Create(
  4812.     "kick",
  4813.     {
  4814.         aliases = {"k", "kickplayer", "playerkick"},
  4815.         help = [[-- Kick
  4816.         -- Syntax: %s [Player] {Message}
  4817.         -- Kicks the player out of the server with a reason written to the KicksAndBans.log]]
  4818.     },
  4819.     {
  4820.         arguments = {"Player", "Remaining Arguments", minArgs = 1, maxArgs = 2},
  4821.         func = function(executorPlayerId, players, reason)
  4822.             reason = reason or "None Given"
  4823.             local exname = getname(executorPlayerId)
  4824.             local playerId, name
  4825.             for i = 1,#players do playerId = players[i]
  4826.            
  4827.                 name = getname(playerId)
  4828.                 if not checkAdminBlockerAccess(executorPlayerId, playerId) then
  4829.                     sendresponse("You cannot use this command on " .. name, executorPlayerId)
  4830.                     privatesay(playerId, exname .. " attemped to use Kick on you!")
  4831.                     goto continue
  4832.                 end
  4833.                
  4834.                 WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was kicked by " .. exname .. " Reason: " .. reason)
  4835.                 say(name .. " has been kicked! Reason: " .. reason)
  4836.                 sendresponse(name .. " has been kicked from the server", executorPlayerId)
  4837.                 halo_svcmd("sv_kick " .. resolveplayer(playerId))
  4838.                
  4839.                 ::continue::
  4840.             end
  4841.         end
  4842.     }
  4843. )
  4844.  
  4845. Commands.Create(
  4846.     "kill",
  4847.     {
  4848.         aliases = {"killplayer", "playerkill"},
  4849.         scrimBlock = true,
  4850.         help = [[-- Kill Player
  4851.         -- Syntax: %s [Player]
  4852.         -- Kills the specified player, and forces them to respawn.]]
  4853.     },
  4854.     {
  4855.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  4856.         func = function(executorPlayerId, players)
  4857.  
  4858.             local playerId
  4859.             for i = 1,#players do playerId = players[i]
  4860.                 if not getplayerobject(playerId) then
  4861.                     sendresponse(getname(playerId) .. " is already dead!", executorPlayerId)
  4862.                     goto continue
  4863.                 end
  4864.                
  4865.                 kill(playerId)
  4866.                 sendresponse(getname(playerId) .. " has been killed", executorPlayerId)
  4867.                
  4868.                 ::continue::
  4869.             end
  4870.         end
  4871.     }
  4872. )
  4873.  
  4874. Commands.Create(
  4875.     "launch",
  4876.     {
  4877.         help = [[-- Launch
  4878.         -- Syntax: %s [Player]
  4879.         -- Launches the person in a random direction.]]
  4880.     },
  4881.     {
  4882.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  4883.         func = function(executorPlayerId, players)
  4884.    
  4885.             local playerId, m_vehicleObj, vehicleObjId
  4886.             for i = 1,#players do playerId = players[i]
  4887.                 m_vehicleObj, vehicleObjId = getplayervehicle(playerId)
  4888.                 if not m_vehicleObj then
  4889.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead/not in a vehicle"
  4890.                     goto continue
  4891.                 end
  4892.                
  4893.                 local x_or_y = rand(1, 3)
  4894.                 if x_or_y == 1 then
  4895.                     local x_rand_vel = rand(6, 11)
  4896.                     writefloat(m_vehicleObj + 0x94, x_rand_vel)
  4897.                     writefloat(m_vehicleObj + 0x90, 0)
  4898.                     writefloat(m_vehicleObj + 0x8C, 0)
  4899.                 elseif x_or_y == 2 then
  4900.                     local y_rand_vel = rand(6, 11)
  4901.                     writefloat(m_vehicleObj + 0x8C, y_rand_vel)
  4902.                     writefloat(m_vehicleObj + 0x90, 0)
  4903.                     writefloat(m_vehicleObj + 0x94, 0)
  4904.                 else
  4905.                     local z_rand_vel = rand(6, 11)
  4906.                     writefloat(m_vehicleObj + 0x90, z_rand_vel)
  4907.                     writefloat(m_vehicleObj + 0x94, 0)
  4908.                     writefloat(m_vehicleObj + 0x8C, 0)
  4909.                 end
  4910.                
  4911.                 writefloat(m_vehicleObj + 0x70, 0.1)
  4912.                 cmdreply[cmdreply()] = getname(playerId) .. " has been launched!"
  4913.                
  4914.                 -- update object physics
  4915.                 writefloat(m_vehicleObj + 0x70, 0.4)
  4916.                 writebit(m_vehicleObj + 0x10, 0, 0) -- Unset noCollisions bit32.
  4917.                 writebit(m_vehicleObj + 0x10, 5, 0) -- Unset ignorePhysics.
  4918.                
  4919.                 ::continue::
  4920.             end
  4921.            
  4922.             sendresponse(cmdreply, executorPlayerId)
  4923.            
  4924.         end
  4925.     }
  4926. )
  4927.  
  4928. function lo3Timer(id, count)
  4929.     if gameend then return false end
  4930.     if count >= 3 then
  4931.         if not defaults.scrim_mode then say "WARNING! Scrim mode is NOT on!" end
  4932.         say "Start your match"
  4933.         halo_svcmd "sv_map_reset"
  4934.         lo3_timer = nil
  4935.         return false
  4936.     else
  4937.         halo_svcmd "sv_map_reset"
  4938.         return true
  4939.     end
  4940. end
  4941.  
  4942. Commands.Create(
  4943.     "lo3",
  4944.     {
  4945.         aliases = {"scrim"},
  4946.         help = [[-- Live on Three
  4947.         -- Syntax: %s
  4948.         -- This command will reset the map 3 times]]
  4949.     },
  4950.     {
  4951.         arguments = {minArgs = 0, maxArgs = 0},
  4952.         func = function(executorPlayerId)
  4953.  
  4954.             if lo3_timer then
  4955.                 sendresponse("Live on three is already in progress! Please wait!", executorPlayerId)
  4956.             else
  4957.                 lo3_timer = registertimer(1000, "lo3Timer")
  4958.             end
  4959.            
  4960.             sendresponse("Live on three.", executorPlayerId)
  4961.         end
  4962.     }
  4963. )
  4964.  
  4965. Commands.Create(
  4966.     "login",
  4967.     {
  4968.         aliases = {"l", "log"},
  4969.         help = [[-- Login
  4970.         -- Syntax: %s [Username] [Password]
  4971.         -- If there are no admins in the admin_table then you will be able to login with this command
  4972.         -- so you are able to use Chat commands even without being a hash or IP admin, it is only temporary.]]
  4973.     },
  4974.     {
  4975.         arguments = {"String", "String", minArgs = 2, maxArgs = 2},
  4976.         func = function(executorPlayerId, username, password)
  4977.             if not executorPlayerId then
  4978.                 sendresponse("the Server is always logged in.", executorPlayerId)
  4979.                 return
  4980.             end
  4981.            
  4982.             local hash, ip = gethash(executorPlayerId), getip(executorPlayerId)
  4983.            
  4984.             if ip_table[ip].tempadmin then
  4985.                 sendresponse("You are already logged in", executorPlayerId)
  4986.                 return
  4987.             end
  4988.            
  4989.             if player_table[executorPlayerId].admin_entry then
  4990.                 sendresponse("You are already an admin!", executorPlayerId)
  4991.                 return
  4992.             end
  4993.            
  4994.             if admin_logins[username] == password then
  4995.                 ip_table[ip].tempadmin = true
  4996.                 sendresponse("You have successfully logged in, you are now able to use chat commands.", executorPlayerId)
  4997.             else
  4998.                 sendresponse("Bad username/password combo.", executorPlayerId)
  4999.             end
  5000.         end
  5001.     }
  5002. )
  5003.  
  5004. Commands.Create(
  5005.     "mnext",
  5006.     {
  5007.         aliases = {"mapnext"},
  5008.         is_alias = true,
  5009.         help = [[-- Map Next
  5010.         -- Syntax: %s
  5011.         -- Shortcut for sv_map_next]]
  5012.     },
  5013.     {
  5014.         arguments = {minArgs = 0, maxArgs = 0},
  5015.         func = function(executorPlayerId)
  5016.             halo_svcmd "sv_map_next"
  5017.             halo_svcmd "sv_mapcycle_timeout 1"
  5018.             sendresponse("The next map will start shortly", executorPlayerId)
  5019.         end
  5020.     }
  5021. )
  5022.  
  5023. Commands.Create(
  5024.     "reset",
  5025.     {
  5026.         aliases = {"mapreset", "resetmap"},
  5027.         is_alias = true,
  5028.         help = [[-- Map Reset
  5029.         -- Syntax: %s
  5030.         -- Shortcut for sv_map_reset]]
  5031.     },
  5032.     {
  5033.         arguments = {minArgs = 0, maxArgs = 0},
  5034.         func = function(executorPlayerId)
  5035.             halo_svcmd "sv_map_reset"
  5036.             sendresponse("The map has been reset", executorPlayerId)
  5037.         end
  5038.     }
  5039. )
  5040.  
  5041. Commands.Create(
  5042.     "move",
  5043.     {
  5044.         aliases = {"j", "mv"},
  5045.         scrimBlock = true,
  5046.         help = [[-- Move Player
  5047.         -- Syntax: %s [player] [x] [y] [z]
  5048.         -- Move the player by the set number of coords.]]
  5049.     },
  5050.     {
  5051.         arguments = {"Player", "Number", "Number", "Number", minArgs = 4, maxArgs = 4},
  5052.         func = function(executorPlayerId, players, X, Y, Z)
  5053.             local playerId, m_playerObj, playerObjId, x, y, z
  5054.             for i = 1,#players do playerId = players[i]
  5055.                 m_playerObj, playerObjId = getplayerobject(playerId)
  5056.                 if m_playerObj then
  5057.                     x,y,z = getobjectcoords(playerObjId)
  5058.                     movobjectcoords(playerObjId, x+X, y+Y, z+Z)
  5059.                     cmdreply[cmdreply()] = getname(playerId) .. " has been moved"
  5060.                 else
  5061.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  5062.                 end
  5063.             end
  5064.            
  5065.             sendresponse(cmdreply, executorPlayerId)
  5066.         end
  5067.     }
  5068. )
  5069.  
  5070. Commands.Create(
  5071.     "nameban",
  5072.     {
  5073.         aliases = {"banname"},
  5074.         help = [[-- Name Ban
  5075.         -- Syntax: %s [player]
  5076.         -- Ban a person via their name]]
  5077.     },
  5078.     {
  5079.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5080.         func = function(executorPlayerId, players)
  5081.    
  5082.             local exname = getname(executorPlayerId)
  5083.             local playerId, name, ban_entry, found, b
  5084.             for i = 1,#players do playerId = players[i]
  5085.            
  5086.                 name = getname(playerId)
  5087.                 if not checkAdminBlockerAccess(executorPlayerId, playerId) then
  5088.                     sendresponse("You cannot use this command on " .. name, executorPlayerId)
  5089.                     privatesay(playerId, exname .. " attemped to use NameBan on you!")
  5090.                     goto continue
  5091.                 end
  5092.                
  5093.                 if name ~= "NameBanned" then
  5094.                     for id = 1,#ban_table do ban_entry = ban_table[id]
  5095.                         if ban_entry.time ~= "Unbanned" then
  5096.                             if ban_entry == name then found = true break end
  5097.                         end
  5098.                     end
  5099.                     if not found then
  5100.                         b = TM.New()
  5101.                         b.name,b.type = name,"name"
  5102.                         ban_table[#ban_table+1] = b
  5103.                         cmdreply[cmdreply()] = halo_svcmd("sv_kick " .. resolveplayer(playerId), true)
  5104.                         say(name .. " has been name banned from the server")
  5105.                     end
  5106.                 else
  5107.                     cmdreply[cmdreply()] = "You cannot ban this name, this name has been assigned automatically."
  5108.                 end
  5109.                
  5110.                 ::continue::
  5111.             end
  5112.            
  5113.             sendresponse(cmdreply, executorPlayerId)
  5114.         end
  5115.     }
  5116. )
  5117.  
  5118. Commands.Create(
  5119.     "overshield",
  5120.     {
  5121.         aliases = {"os", "giveos", "osgive", "giveovershield", "overshieldgive"},
  5122.         scrimBlock = true,
  5123.         help = [[-- OverShield
  5124.         -- Syntax: %s [player]
  5125.         -- Give specified players an overshield (os)]]
  5126.     },
  5127.     {
  5128.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5129.         func = function(executorPlayerId, players)
  5130.    
  5131.             local playerId, m_playerObj, playerObjId, m_vehicleObj, vehicleObjId, x, y, z, overshield, obj_shields
  5132.             for i = 1,#players do playerId = players[i]
  5133.                 m_playerObj, playerObjId = getplayerobject(playerId)
  5134.                 if not m_playerObj then
  5135.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  5136.                     goto continue
  5137.                 end
  5138.                
  5139.                 obj_shields = readfloat(m_playerObj + 0xE4)
  5140.                 if obj_shields > 1 then
  5141.                     cmdreply[cmdreply()] = getname(playerId) .. " already has an overshield"
  5142.                     goto continue
  5143.                 end
  5144.                
  5145.                 m_vehicleObj, vehicleObjId = getplayervehicle(playerId)
  5146.                 if m_vehicleObj then
  5147.                     writefloat(m_playerObj + 0xE4, 3)
  5148.                 else
  5149.                     x,y,z = getobjectcoords(playerObjId)
  5150.                     overshield = getobject(createobject(gettag("eqip", "powerups\\overshield"), 0, 0, false, x, y, z+0.5))
  5151.                     if overshield then writefloat(overshield + 0x70, -2) end
  5152.                 end
  5153.                 cmdreply[cmdreply()] = getname(playerId) .. " has been given an overshield"
  5154.                
  5155.                 ::continue::
  5156.             end
  5157.            
  5158.             sendresponse(cmdreply, executorPlayerId)
  5159.         end
  5160.     }
  5161. )
  5162.  
  5163. Commands.Create(
  5164.     "players",
  5165.     {
  5166.         aliases = {"pl", "playerlist"},
  5167.         help = [[-- Player List
  5168.         -- Syntax: %s
  5169.         -- sv_players command modified
  5170.         -- Displays all Player Indicies and Names]]
  5171.     },
  5172.     {
  5173.         arguments = {minArgs = 0, maxArgs = 0},
  5174.         func = function(executorPlayerId)
  5175.  
  5176.             cmdreply.header = "[ID | Name]"
  5177.             cmdreply.delim = "|"
  5178.             cmdreply.align = true
  5179.             local playerId
  5180.             for i = 1,16 do playerId = rresolveplayer(i)
  5181.                 if not getplayer(playerId) then goto continue end
  5182.                
  5183.                 cmdreply[cmdreply()] = "[" .. i .. " | " .. getname(playerId) .. "]"
  5184.                
  5185.                 ::continue::
  5186.             end
  5187.             sendresponse(cmdreply, executorPlayerId)
  5188.         end
  5189.     }
  5190. )
  5191.  
  5192. Commands.Create(
  5193.     "playersmore",
  5194.     {
  5195.         aliases = {"plmore", "moreplayers"},
  5196.         help = [[-- Extended Player List
  5197.         -- Syntax: %s
  5198.         -- Shows Player ID, Player Name, Player Team, Status(Admin/Regular), IP, and Hash]]
  5199.     },
  5200.     {
  5201.         arguments = {minArgs = 0, maxArgs = 0},
  5202.         func = function(executorPlayerId)
  5203.            
  5204.             cmdreply.header = "[ID | Name | Team | Type | IP | Hash]"
  5205.             cmdreply.delim = "|"
  5206.             cmdreply.align = true
  5207.             local playerId, team
  5208.             for i = 1,16 do playerId = rresolveplayer(i)
  5209.                 if not getplayer(playerId) then goto continue end
  5210.                
  5211.                 team = getteam(playerId)
  5212.                 team = team_play and (team == 0 and "Red" or team == 1 and "Blue" or "Hidden") or "FFA " .. team
  5213.                 cmdreply[cmdreply()] = format("[%s | %s | %s | %s | %s | %s]", i, getname(playerId), team, player_table[playerId].admin_entry and "Admin" or "Regular", getip(playerId), gethash(playerId))
  5214.                
  5215.                 ::continue::
  5216.             end
  5217.            
  5218.             sendresponse(cmdreply, executorPlayerId)
  5219.         end
  5220.     }
  5221. )
  5222.  
  5223. Commands.Create(
  5224.     "privatesay",
  5225.     {
  5226.         aliases = {"pvtsay", "psay", "sayprivately"},
  5227.         help = [[-- Private Say
  5228.         --Syntax %s {player} {message}
  5229.         --Sends a private message to the specifed player]]
  5230.     },
  5231.     {
  5232.         arguments = {"Player", "Remaining Arguments", minArgs = 2, maxArgs = 2},
  5233.         func = function(executorPlayerId, players, message)
  5234.  
  5235.             for i = 1,#players do
  5236.                 sendconsoletext(players[i], message)
  5237.             end
  5238.             sendresponse("Private messages sent.", executorPlayerId)
  5239.         end
  5240.     }
  5241. )
  5242.  
  5243. Commands.Create(
  5244.     "rconlist",
  5245.     {
  5246.         aliases = {"listrcons", "rcons"},
  5247.         help = [[-- Rcon Password List
  5248.         -- Syntax: %s
  5249.         -- Lists all available rcon passwords except the main rcon password]]
  5250.     },
  5251.     {
  5252.         arguments = {minArgs = 0, maxArgs = 0},
  5253.         func = function(executorPlayerId)
  5254.    
  5255.             cmdreply.header = "[Rcon | Level]"
  5256.             cmdreply.align = true
  5257.             cmdreply.delim = "|"
  5258.             local rcon_entry
  5259.             for rcon,level in next,rcon_passwords do
  5260.                 cmdreply[cmdreply()] = "[" .. rcon .. " | " .. level .. "]"
  5261.             end
  5262.            
  5263.             sendresponse(cmdreply, executorPlayerId)
  5264.         end
  5265.     }
  5266. )
  5267.  
  5268. local function tobinary(number)
  5269.     number = tonumber(number) or error("bad argument #1 to 'tobinary' (number expected, got '" .. type(number) .. "')")
  5270.     local t = TM.New()
  5271.     local rest
  5272.     while number > 0 do
  5273.         rest = number % 2
  5274.         t[#t+1] = rest
  5275.         number = (number - rest) * 0.5
  5276.     end
  5277.     return concat(t)
  5278. end
  5279. tobinary = memoize(tobinary) -- memoized
  5280.  
  5281. Commands.Create(
  5282.     "read",
  5283.     {
  5284.         help = [[-- Read Address/Struct
  5285.         -- Syntax: %s [Type] [Struct or Address] [Offset] [Value] [Player or Bit], [Player]
  5286.         -- Read the Guide for info on this command]]
  5287.     },
  5288.     {
  5289.         arguments = {"Struct", "Number", "Bit", "Player", minArgs = 3, maxArgs = 3},
  5290.         func = function(executorPlayerId, struct, offset, bit, players)
  5291.             local playerId, m_playerObj, playerObjId, value, float
  5292.             for i = 1,#players do playerId = players[i]
  5293.                 m_playerObj = getplayerobject(playerId)
  5294.                 if struct == "player" then
  5295.                     struct = getplayer(playerId)
  5296.                 elseif m_playerObj then
  5297.                     if struct == "object" then
  5298.                         struct = m_playerObj
  5299.                     elseif struct == "weapon" then
  5300.                         struct = getplayerweapon(playerId)
  5301.                         if not struct then sendresponse(getname(playerId) .. " is not holding a Weapon", executorPlayerId) return end
  5302.                     elseif struct == "vehicle" then
  5303.                         struct = getplayervehicle(playerId)
  5304.                         if not struct then sendresponse(getname(playerId) .. " is not in a Vehicle", executorPlayerId) return end
  5305.                     end
  5306.                 else
  5307.                     sendresponse("Player Object must exist to use Struct: " .. struct)
  5308.                 end
  5309.                 value = readbit(struct + offset, struct)
  5310.                 sendresponse("Reading " .. format("0x%08X", struct) ..  " at Offset " .. format("0x%X", offset) .. " was a Success", executorPlayerId)
  5311.                 sendresponse("Binary Val: " .. value, executorPlayerId)
  5312.             end
  5313.         end
  5314.     },
  5315.     {
  5316.         arguments = {"Datatype", "Struct", "Number", "Player", minArgs = 3, maxArgs = 3},
  5317.         func = function(executorPlayerId, datatype, struct, offset, players)
  5318.             local playerId, m_playerObj, playerObjId, float, value
  5319.             for i = 1,#players do playerId = players[i]
  5320.                 m_playerObj, playerObjId = getplayerobject(playerId)
  5321.                 if struct == "player" then
  5322.                     struct = getplayer(playerId)
  5323.                 elseif m_playerObj then
  5324.                     if struct == "object" then
  5325.                         struct = m_playerObj
  5326.                     elseif struct == "weapon" then
  5327.                         struct = getplayerweapon(playerId)
  5328.                         if not struct then sendresponse(getname(playerId) .. " is not holding a Weapon", executorPlayerId) end
  5329.                     elseif struct == "vehicle" then
  5330.                         struct = getplayervehicle(playerId)
  5331.                         if not struct then sendresponse(getname(playerId) .. " is not in a Vehicle", executorPlayerId) end
  5332.                     end
  5333.                 else
  5334.                     sendresponse("Player Object must exist to use Struct: " .. struct)
  5335.                 end
  5336.                 if datatype == "bit8" then
  5337.                     value = tobinary(readbyte(struct + offset))
  5338.                 elseif datatype == "bit16" then
  5339.                     value = tobinary(readword(struct + offset))
  5340.                 elseif datatype == "bit32" then
  5341.                     value = tobinary(readdword(struct + offset))
  5342.                 elseif datatype == "char" then
  5343.                     value = readchar(struct + offset)
  5344.                 elseif datatype == "byte" then
  5345.                     value = readbyte(struct + offset)
  5346.                 elseif datatype == "short" then
  5347.                     value = readshort(struct + offset)
  5348.                 elseif datatype == "word" then
  5349.                     value = readword(struct + offset)
  5350.                 elseif datatype == "int" then
  5351.                     value = readint(struct + offset)
  5352.                 elseif datatype == "dword" then
  5353.                     value = readdword(struct + offset)
  5354.                 elseif datatype == "float" then
  5355.                     float = true
  5356.                     value = readfloat(struct + offset)
  5357.                 elseif datatype == "string" then
  5358.                     value = readstring(struct + offset)
  5359.                 elseif datatype == "widestring" then
  5360.                     value = readwidestring(struct + offset)
  5361.                 end
  5362.                 sendresponse("Reading Address " .. format("0x%08X", struct) .. " was a Success", executorPlayerId)
  5363.                 if not match(datatype, "^bit%d+$") then
  5364.                     if float then
  5365.                         sendresponse("Float: " .. value, executorPlayerId)
  5366.                     elseif type(value) == "number" then
  5367.                         sendresponse("Decimal: " .. value .. (value >= 0 and (" Hex: " .. format("0x%X", value)) or ""), executorPlayerId)
  5368.                     else
  5369.                         sendresponse("Value: " .. value, executorPlayerId)
  5370.                     end
  5371.                 else
  5372.                     sendresponse("Binary Val: " .. value, executorPlayerId)
  5373.                 end
  5374.             end
  5375.         end
  5376.     },
  5377.     {
  5378.         arguments = {"Datatype", "Number", "Number", minArgs = 3, maxArgs = 3},
  5379.         func = function(executorPlayerId, datatype, address, offset)
  5380.             local float, value
  5381.             if datatype == "bit8" then
  5382.                 value = tobinary(readbyte(address + offset))
  5383.             elseif datatype == "bit16" then
  5384.                 value = tobinary(readword(address + offset))
  5385.             elseif datatype == "bit32" then
  5386.                 value = tobinary(readdword(address + offset))
  5387.             elseif datatype == "char" then
  5388.                 value = readchar(address + offset)
  5389.             elseif datatype == "byte" then
  5390.                 value = readbyte(address + offset)
  5391.             elseif datatype == "short" then
  5392.                 value = readshort(address + offset)
  5393.             elseif datatype == "word" then
  5394.                 value = readword(address + offset)
  5395.             elseif datatype == "int" then
  5396.                 value = readint(address + offset)
  5397.             elseif datatype == "dword" then
  5398.                 value = readdword(address + offset)
  5399.             elseif datatype == "float" then
  5400.                 float = true
  5401.                 value = readfloat(address + offset)
  5402.             elseif datatype == "string" then
  5403.                 value = readstring(address + offset)
  5404.             elseif datatype == "widestring" then
  5405.                 value = readwidestring(address + offset)
  5406.             end
  5407.             sendresponse("Reading Address " .. format("0x%08X", offset) .. " was a Success", executorPlayerId)
  5408.             if float then
  5409.                 sendresponse("Float: " .. value, executorPlayerId)
  5410.             elseif value >= 0 then
  5411.                 sendresponse("Decimal: " .. value .. " Hex: " .. format("0x%X", value), executorPlayerId)
  5412.             else
  5413.                 sendresponse("Value: " .. value, executorPlayerId)
  5414.             end
  5415.         end
  5416.     },
  5417.     {
  5418.         arguments = {"Number", "Number", "Bit", minArgs = 3, maxArgs = 3},
  5419.         func = function(executorPlayerId, address, offset, bit)
  5420.             sendresponse("Reading Address " .. format("0x%08X", address) .. " was a Success", executorPlayerId)
  5421.             sendresponse("Binary Val: " .. readbit(address + offset, bit) and 1 or 0, executorPlayerId)
  5422.         end
  5423.     }
  5424. )
  5425.  
  5426. Commands.Create(
  5427.     "write",
  5428.     {
  5429.         help = [[-- Write
  5430.         -- Syntax: %s [Type] [Struct] [Offset] [Value] [Player]
  5431.         -- Read the Guide for info on this command]]
  5432.     },
  5433.     {
  5434.         arguments = {"Datatype", "Struct", "Whole Number", "Number", "Player", minArgs = 3, maxArgs = 5},
  5435.         func = function(executorPlayerId, datatype, struct, offset, value, playerId)
  5436.             --[[local address
  5437.             if count >= 5 and count <= 6 then
  5438.                 if lower(sub(offset, 1, 2)) == "0x" then
  5439.                     offset = tonumber(sub(offset, 3), 16)
  5440.                 else
  5441.                     offset = tonumber(offset) or tonumber(offset, 16)
  5442.                 end
  5443.                 local players = getvalidplayers(playerId, executorPlayerId)
  5444.                 if players then
  5445.                     local playerId
  5446.                     for i = 1,#players do playerId = players[i]
  5447.                         local m_playerObj, playerObjId = getplayerobject(playerId)
  5448.                         if struct == "player" then
  5449.                             address = getplayer(playerId)
  5450.                         elseif struct ~= "object" and struct ~= "weapon" and struct ~= "vehicle" then
  5451.                             sendresponse("Invalid Struct. Valid structs are: playerId, object, weapon, and vehicle.", executorPlayerId)
  5452.                         elseif m_playerObj then
  5453.                             if struct == "object" then
  5454.                                 address = m_playerObj
  5455.                             elseif struct == "weapon" then
  5456.                                 address = getplayerweapon(playerId)
  5457.                                 if not address then sendresponse(getname(playerId) .. " is not holding a weapon", executorPlayerId) end
  5458.                             elseif struct == "vehicle" then
  5459.                                 address = getplayervehicle(playerId)
  5460.                                 if not address then sendresponse(getname(playerId) .. " is not in a vehicle", executorPlayerId) end
  5461.                             elseif not struct then
  5462.                                 sendresponse("Invalid Struct. Valid structs are: playerId, object, weapon, and vehicle", executorPlayerId)
  5463.                             end
  5464.                         elseif struct ~= "object" and struct ~= "weapon" and struct ~= "vehicle" then
  5465.                             sendresponse("Invalid Struct. Valid structs are: playerId, object, weapon, and vehicle.", executorPlayerId)
  5466.                         else
  5467.                             sendresponse("playerId object must exist to use struct: " .. struct)
  5468.                         end
  5469.                         if offset and address then
  5470.                             if lower(sub(tostring(value), 2)) == "0x" then
  5471.                                 value = tonumber(sub(tostring(value), 3), 16)
  5472.                             else
  5473.                                 value = tonumber(value) or tonumber(value, 16)
  5474.                             end
  5475.                             if value then
  5476.                                 if datatype == "char" then
  5477.                                     writechar(address + offset, value)
  5478.                                 elseif datatype == "byte" then
  5479.                                     writebyte(address + offset, value)
  5480.                                 elseif datatype == "short" then
  5481.                                     writeshort(address + offset, value)
  5482.                                 elseif datatype == "word" then
  5483.                                     writeword(address + offset, value)
  5484.                                 elseif datatype == "int" then
  5485.                                     writeint(address + offset, value)
  5486.                                 elseif datatype == "dword" then
  5487.                                     writedword(address + offset, value)
  5488.                                 elseif datatype == "float" then
  5489.                                     writefloat(address + offset, value)
  5490.                                 elseif datatype == "string" then
  5491.                                     writestring(address + offset, value)
  5492.                                 elseif datatype == "widestring" then
  5493.                                     writewidestring(address + offset, value)
  5494.                                 else
  5495.                                     sendresponse("Invalid datatype. Valid datatypes are 'char', 'byte', 'short', 'word', 'int', 'dword', 'float', 'string', and 'widestring'", executorPlayerId)
  5496.                                 end
  5497.                                 sendresponse("Writing " .. value .. " to address " .. format("0x%08X", offset) .. " was a success", executorPlayerId)
  5498.                             else
  5499.                                 sendresponse("Value must be a number", executorPlayerId)
  5500.                             end
  5501.                         elseif not offset then
  5502.                             sendresponse("Offset must be a number", executorPlayerId)
  5503.                         end
  5504.                     end
  5505.                 elseif not playerId then
  5506.                     if lower(sub(struct, 1, 2)) == "0x" then
  5507.                         address = tonumber(sub(struct, 3), 16)
  5508.                     else
  5509.                         address = tonumber(struct) or tonumber(struct, 16)
  5510.                     end
  5511.                     if address then
  5512.                         if offset then
  5513.                             if lower(sub(value, 1, 2)) == "0x" then
  5514.                                 value = tonumber(sub(value, 3), 16)
  5515.                             else
  5516.                                 value = tonumber(value) or tonumber(value, 16)
  5517.                             end
  5518.                             if value then
  5519.                                 if datatype == "char" then
  5520.                                     writechar(address + offset, value)
  5521.                                 elseif datatype == "byte" then
  5522.                                     writebyte(address + offset, value)
  5523.                                 elseif datatype == "short" then
  5524.                                     writeshort(address + offset, value)
  5525.                                 elseif datatype == "word" then
  5526.                                     writeword(address + offset, value)
  5527.                                 elseif datatype == "int" then
  5528.                                     writeint(address + offset, value)
  5529.                                 elseif datatype == "dword" then
  5530.                                     writedword(address + offset, value)
  5531.                                 elseif datatype == "float" then
  5532.                                     writefloat(address + offset, value)
  5533.                                 elseif datatype == "string" then
  5534.                                     writestring(address + offset, value)
  5535.                                 elseif datatype == "widestring" then
  5536.                                     writewidestring(address + offset, value)
  5537.                                 else
  5538.                                     sendresponse("Invalid datatype. Valid datatypes are 'char', 'byte', 'short', 'word', 'int', 'dword', 'float', 'string', and 'widestring'", executorPlayerId)
  5539.                                     return
  5540.                                 end
  5541.                                 sendresponse("Writing " .. value .. " to address " .. format("0x%08X", offset) .. " was a success", executorPlayerId)
  5542.                             else
  5543.                                 sendresponse("Value must be a number.", executorPlayerId)
  5544.                             end
  5545.                         else
  5546.                             sendresponse("Offset must be a number", executorPlayerId)
  5547.                         end
  5548.                     else
  5549.                         sendresponse("Struct must be a number", executorPlayerId)
  5550.                     end
  5551.                 else
  5552.                     sendresponse("Invalid Player", executorPlayerId)
  5553.                 end
  5554.             end]]
  5555.         end
  5556.     }
  5557. )
  5558.  
  5559. Commands.Create(
  5560.     "resetplayer",
  5561.     {
  5562.         aliases = {"playerreset", "playereset"},
  5563.         help = [[-- Reset Player
  5564.         -- Syntax: %s [Player]
  5565.         -- Removes all troll settings from specified player]]
  5566.     },
  5567.     {
  5568.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5569.         func = function(executorPlayerId, players)
  5570.    
  5571.             local playerId
  5572.             for i = 1,#players do playerId = players[i]
  5573.                 ResetPlayer(playerId)
  5574.                 cmdreply[cmdreply()] = getname(playerId) .. " has been reset."
  5575.             end
  5576.            
  5577.             sendresponse(cmdreply, executorPlayerId)
  5578.         end
  5579.     }
  5580. )
  5581.  
  5582. Commands.Create(
  5583.     "resetweapons",
  5584.     {
  5585.         scrimBlock = true,
  5586.         help = [[-- Reset Weapons
  5587.         -- Syntax: %s [Player]
  5588.         -- Reset the weapons of the specified players]]
  5589.     },
  5590.     {
  5591.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  5592.         func = function(executorPlayerId, players)
  5593.    
  5594.             local playerId, iptable, m_playerObj
  5595.             for i = 1,#players do playerId = players[i]
  5596.                 iptable = ip_table[getip(playerId)]
  5597.                 if iptable.disarmed then
  5598.                     iptable.disarmed = false
  5599.                     resetweapons(playerId)
  5600.                     cmdreply[cmdreply()] = getname(playerId) .. " had their weapons reset"
  5601.                 else
  5602.                     cmdreply[cmdreply()] = getname(playerId) .. " never had their weapons taken away"
  5603.                 end
  5604.             end
  5605.            
  5606.             sendresponse(cmdreply, executorPlayerId)
  5607.         end
  5608.     }
  5609. )
  5610.  
  5611. Commands.Create(
  5612.     "resp",
  5613.     {
  5614.         aliases = {"respplayer", "playerresp"},
  5615.         scrimBlock = true,
  5616.         help = [[-- Respawn Time for Player
  5617.         -- Syntax: %s [Player] {Time}
  5618.         -- Change the player's respawn time]]
  5619.     },
  5620.     {
  5621.         arguments = {"Player", "Time", minArgs = 2, maxArgs = 2},
  5622.         func = function(executorPlayerId, players, time)
  5623.    
  5624.             local playerId, m_playerObj
  5625.             for i = 1,#players do playerId = players[i]
  5626.                 m_playerObj = getplayerobject(playerId)
  5627.                 if not m_playerObj then
  5628.                     writedword(getplayer(playerId) + 0x2C, time)
  5629.                     cmdreply[cmdreply()] = "Setting " .. getname(playerId) .. "'s respawn time to " .. timetoword(time)
  5630.                 else
  5631.                     cmdreply[cmdreply()] = getname(playerId) .. " is alive. Setting their respawn time will do nothing."
  5632.                 end
  5633.             end
  5634.            
  5635.             sendresponse(cmdreply, executorPlayerId)
  5636.         end
  5637.     }
  5638. )
  5639.  
  5640. Commands.Create(
  5641.     "rtvrequired",
  5642.     {
  5643.         aliases = {"rtvneeded"},
  5644.         help = [[-- RTV Needed
  5645.         -- Syntax: %s [Percent]
  5646.         -- Change the number of votes needed for RTV to change the map.]]
  5647.     },
  5648.     {
  5649.         arguments = {"Percent", minArgs = 0, maxArgs = 1},
  5650.         func = function(executorPlayerId, percent)
  5651.             if percent then
  5652.                 sendresponse("Votes required for RTV has been set to " .. percent .. "%", executorPlayerId)
  5653.                 defaults.rtv_required = percent
  5654.             else
  5655.                 sendresponse(defaults.rtv_required .. "% votes required for RTV", executorPlayerId)
  5656.             end
  5657.         end
  5658.     }
  5659. )
  5660.  
  5661. Commands.Create(
  5662.     "rtvtimeout",
  5663.     {
  5664.         help = [[-- RTV Timeout
  5665.         -- Syntax: %s {Time}
  5666.         -- The amount of time between each RTV attempt.]]
  5667.     },
  5668.     {
  5669.         arguments = {"Time", minArgs = 0, maxArgs = 1},
  5670.         func = function(executorPlayerId, time)
  5671.             if time == -1 then
  5672.                 sendresponse("RTV Timeout is currently " .. timetoword(defaults.rtv_timeout), executorPlayerId)
  5673.             else
  5674.                 sendresponse("RTV Timeout has been set to " .. timetoword(time), executorPlayerId)
  5675.                 defaults.rtv_timeout = time
  5676.             end
  5677.         end
  5678.     }
  5679. )
  5680.  
  5681. Commands.Create(
  5682.     "setammo",
  5683.     {
  5684.         aliases = {"ammo", "setammo", "ammoset"},
  5685.         scrimBlock = true,
  5686.         help = [[-- Set Ammo
  5687.         -- Syntax: %s [Player] [Type] [Ammo]
  5688.         -- Set the ammo of the players specified
  5689.         -- type means type of ammo, use 1 for unloaded ammo and 2 for loaded ammo]]
  5690.     },
  5691.     {
  5692.         arguments = {"Player", "String", "Whole Number", minArgs = 3, maxArgs = 3},
  5693.         func = function(executorPlayerId, players, ammotype, ammo)
  5694.            
  5695.             local playerId, m_playerObj, playerObjId, m_weaponObj, weaponObjId
  5696.             for i = 1,#players do playerId = players[i]
  5697.                 m_playerObj, playerObjId = getplayerobject(playerId)
  5698.                 if not m_playerObj then
  5699.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead and cannot have ammo"
  5700.                     goto continue
  5701.                 end
  5702.                
  5703.                 m_weaponObj, weaponObjId = getplayerweapon(playerId)
  5704.                 if not m_weaponObj then
  5705.                     cmdreply[cmdreply()] = getname(playerId) .. " is not holding any weapons"
  5706.                     goto continue
  5707.                 end
  5708.  
  5709.                 if ammotype == "unloaded" or ammotype == "1" then
  5710.                     writeword(m_weaponObj + 0x2B6, ammo)
  5711.                     cmdreply[cmdreply()] = getname(playerId) .. " had their unloaded ammo changed to " .. ammo
  5712.                 elseif ammotype == "loaded" or ammotype == "2" then
  5713.                     writeword(m_weaponObj + 0x2B8, ammo)
  5714.                     updateammo(weaponObjId)
  5715.                     cmdreply[cmdreply()] = getname(playerId) .. " had their loaded ammo changed to " .. ammo
  5716.                 else
  5717.                     cmdreply[cmdreply()] = "Invalid ammo type: 1 for unloaded, 2 for loaded ammo"
  5718.                 end
  5719.                 ::continue::
  5720.             end
  5721.            
  5722.             sendresponse(cmdreply, executorPlayerId)
  5723.         end
  5724.     }
  5725. )
  5726.  
  5727. Commands.Create(
  5728.     "setcolor",
  5729.     {
  5730.         aliases = {"color", "colorset"},
  5731.         scrimBlock = true,
  5732.         help = [[-- Set Color
  5733.         -- Syntax: %s [Player] [Color]
  5734.         -- Change the color of the selected player. Works on FFA Only]]
  5735.     },
  5736.     {
  5737.         arguments = {"Player", "String", minArgs = 1, maxArgs = 2},
  5738.         func = function(executorPlayerId, players, color)
  5739.            
  5740.             local colors = TM{[0] = "white", "black", "red", "blue", "grey", "yellow", "green", "pink", "purple", "cyan", "cobalt", "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, cobalt = 10, orange = 11, teal = 12, sage = 13, brown = 14, tan = 15, maroon = 16, salmon = 17}
  5741.  
  5742.             if color then
  5743.                 color = tonumber(color) and tonumber(color) or colors[color]
  5744.                
  5745.                 if type(color) ~= "number" then
  5746.                     sendresponse("Invalid Color", executorPlayerId)
  5747.                     return
  5748.                 end
  5749.             end
  5750.            
  5751.             local color_name = colors[color]
  5752.             local playerId, m_playerObj, playerObjId, ptable, x, y, z
  5753.             for i = 1,#players do playerId = players[i]
  5754.                 if not color then
  5755.                     cmdreply[cmdreply()] = getname(playerId) .. " is currently " .. (colors[readbyte(getplayer(playerId) + 0x60)] or "Invalid Color")
  5756.                     goto continue
  5757.                 end
  5758.                
  5759.                 writebyte(getplayer(playerId) + 0x60, color)
  5760.                 cmdreply[cmdreply()] = getname(playerId) .. " had their color changed to '" .. color_name .. "'"
  5761.                
  5762.                 m_playerObj, playerObjId = getplayerobject(playerId)
  5763.                
  5764.                 if not m_playerObj then
  5765.                     goto continue
  5766.                 end
  5767.                
  5768.                 ptable = player_table[i]
  5769.                 x,y,z = getobjectcoords(playerObjId)
  5770.                 ptable.colorspawn = true
  5771.                 ptable.x,ptable.y,ptable.z = x,y,z
  5772.                 destroyobject(playerObjId)
  5773.                
  5774.                 ::continue::
  5775.             end
  5776.            
  5777.             sendresponse(cmdreply, executorPlayerId)
  5778.         end
  5779.     }
  5780. )
  5781.  
  5782. Commands.Create(
  5783.     "setassists",
  5784.     {
  5785.         aliases = {"assists", "assistset", "setassists"},
  5786.         scrimBlock = true,
  5787.         help = [[-- Set Assists
  5788.         -- Syntax: %s [Player] [Assists]
  5789.         -- Set the assists for the specified players]]
  5790.     },
  5791.     {
  5792.         arguments = {"Player", "Whole Number", minArgs = 2, maxArgs = 2},
  5793.         func = function(executorPlayerId, players, assists)
  5794.    
  5795.             local playerId
  5796.             for i = 1,#players do playerId = players[i]
  5797.                 writeshort(getplayer(playerId) + 0xA4, assists)
  5798.                 cmdreply[cmdreply()] = getname(playerId) .. " had their assists set to " .. assists
  5799.             end
  5800.            
  5801.             sendresponse(cmdreply, executorPlayerId)
  5802.         end
  5803.     }
  5804. )
  5805.  
  5806. Commands.Create(
  5807.     "setdeaths",
  5808.     {
  5809.         aliases = {"deaths", "deathset", "setdeaths", "setdeath"},
  5810.         scrimBlock = true,
  5811.         help = [[-- Set Deaths
  5812.         -- Syntax: %s [Player] [Deaths]
  5813.         -- Set the deaths for the specified players]]
  5814.     },
  5815.     {
  5816.         arguments = {"Player", "Whole Number", minArgs = 2, maxArgs = 2},
  5817.         func = function(executorPlayerId, players, deaths)
  5818.    
  5819.             local playerId
  5820.             for i = 1,#players do playerId = players[i]
  5821.                 writeshort(getplayer(playerId) + 0xAE, deaths)
  5822.                 cmdreply[cmdreply()] = getname(playerId) .. " had their deaths set to " .. deaths
  5823.             end
  5824.            
  5825.             sendresponse(cmdreply, executorPlayerId)
  5826.         end
  5827.     }
  5828. )
  5829.  
  5830. Commands.Create(
  5831.     "setkills",
  5832.     {
  5833.         aliases = {"kills", "killset"},
  5834.         scrimBlock = true,
  5835.         help = [[-- Set Kills
  5836.         -- Syntax: %s [Player] [Kills]
  5837.         -- Set the kills for the specified players]]
  5838.     },
  5839.     {
  5840.         arguments = {"Player", "Whole Number", minArgs = 2, maxArgs = 2},
  5841.         func = function(executorPlayerId, players, kills)
  5842.    
  5843.             local playerId
  5844.             for i = 1,#players do playerId = players[i]
  5845.                 writeshort(getplayer(playerId) + 0x9C, kills)
  5846.                 cmdreply[cmdreply()] = getname(playerId) .. " had their kills set to " .. kills
  5847.             end
  5848.            
  5849.             sendresponse(cmdreply, executorPlayerId)
  5850.         end
  5851.     }
  5852. )
  5853.  
  5854. Commands.Create(
  5855.     "setscore",
  5856.     {
  5857.         aliases = {"scores", "score", "scoreset"},
  5858.         scrimBlock = true,
  5859.         help = [[-- Set Score
  5860.         -- Syntax: %s [Player] [Score]
  5861.         -- Set the score for the specified players]]
  5862.     },
  5863.     {
  5864.         arguments = {"Player", "Whole Number", minArgs = 2, maxArgs = 2},
  5865.         func = function(executorPlayerId, players, score)
  5866.    
  5867.             local playerId
  5868.             for i = 1,#players do playerId = players[i]
  5869.                 setscore(playerId, score)
  5870.                 cmdreply[cmdreply()] = getname(playerId) .. " had their score set to " .. score
  5871.             end
  5872.            
  5873.             sendresponse(cmdreply, executorPlayerId)
  5874.         end
  5875.     }
  5876. )
  5877.  
  5878. Commands.Create(
  5879.     "setupright",
  5880.     {
  5881.         help = [[-- Set Vehicle Upright
  5882.         -- Syntax: %s {Player}
  5883.         -- Sets the player's vehicle upright if they are flipped]],
  5884.     },
  5885.     {
  5886.         arguments = {"Player", minArgs = 0, maxArgs = 1},
  5887.         func = function(executorPlayerId, playerId)
  5888.            
  5889.             local playerId, m_vehicleObj
  5890.             for i = 1,#players do playerId = players[i]
  5891.                 m_vehicleObj = getplayervehicle(playerId)
  5892.                 if not m_vehicleObj then
  5893.                     sendresponse(getname(playerId) .. " is not in a vehicle!", executorPlayerId)
  5894.                     goto continue
  5895.                 end
  5896.  
  5897.                 writefloat(m_vehicleObj + 0x8A, 2.3 * (10 ^ -41))
  5898.                 writefloat(m_vehicleObj + 0x8C, 2.3 * (10 ^ -41))
  5899.                 writefloat(m_vehicleObj + 0x90, 2.3 * (10 ^ -41))
  5900.                 writefloat(m_vehicleObj + 0x94, 2.3 * (10 ^ -41))
  5901.                 writebit(m_vehicleObj + 0x10, 0, 0) -- Unset noCollisions bit.
  5902.                 writebit(m_vehicleObj + 0x10, 5, 0) -- Unset ignorePhysics.
  5903.                 sendresponse(getname(playerId) .. " had their vehicle set upright!", executorPlayerId)
  5904.                 ::continue::
  5905.             end
  5906.         end
  5907.     }
  5908. )
  5909.  
  5910. Commands.Create(
  5911.     "setfrags",
  5912.     {
  5913.         aliases = {"setfrags", "frags", "fragset", "setfragnades"},
  5914.         scrimBlock = true,
  5915.         help = [[-- Set Frags
  5916.         -- Syntax: %s [Player] [Frags]
  5917.         -- Set the frags for the specified players]]
  5918.     },
  5919.     {
  5920.         arguments = {"Player", "Whole Number", minArgs = 2, maxArgs = 2},
  5921.         func = function(executorPlayerId, players, frags)
  5922.            
  5923.             frags = frags > 7 and 7 or frags
  5924.            
  5925.             local playerId, m_playerObj, playerObjId
  5926.             for i = 1,#players do playerId = players[i]
  5927.                 m_playerObj, playerObjId = getplayerobject(playerId)
  5928.                 if not m_playerObj then
  5929.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  5930.                     goto continue
  5931.                 end
  5932.                
  5933.                 writebyte(m_playerObj + 0x31E, frags)
  5934.                 cmdreply[cmdreply()] = "Setting " .. getname(playerId) .. "'s frag grenades to " .. frags
  5935.                 privatesay(playerId, "Your frag grenades were set to " .. frags)
  5936.                
  5937.                 ::continue::
  5938.             end
  5939.  
  5940.             sendresponse(cmdreply, executorPlayerId)
  5941.         end
  5942.     }
  5943. )
  5944.  
  5945. Commands.Create(
  5946.     "setplasmas",
  5947.     {
  5948.         aliases = {"setplasmas", "stickies", "plasmas", "plasmaset", "setplasmanades"},
  5949.         scrimBlock = true,
  5950.         help = [[-- Set Plasmas
  5951.         -- Syntax: %s [Player] [Plasmas]
  5952.         -- Set the plasmas for the specified players]]
  5953.     },
  5954.     {
  5955.         arguments = {"Player", "Whole Number", minArgs = 2, maxArgs = 2},
  5956.         func = function(executorPlayerId, players, plasmas)
  5957.  
  5958.             plasmas = plasmas > 7 and 7 or plasmas
  5959.            
  5960.             local playerId, m_playerObj, playerObjId
  5961.             for i = 1,#players do playerId = players[i]
  5962.                 m_playerObj, playerObjId = getplayerobject(playerId)
  5963.                 if not m_playerObj then
  5964.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead"
  5965.                     goto continue
  5966.                 end
  5967.                
  5968.                 writebyte(m_playerObj + 0x31F, plasmas)
  5969.                 cmdreply[cmdreply()] = "Setting " .. getname(playerId) .. "'s plasma grenades to " .. plasmas
  5970.                 privatesay(playerId, "Your plasma grenades were set to " .. plasmas)
  5971.                
  5972.                 ::continue::
  5973.             end
  5974.  
  5975.             sendresponse(cmdreply, executorPlayerId)
  5976.         end
  5977.     }
  5978. )
  5979.  
  5980. Commands.Create(
  5981.     "setprefix",
  5982.     {
  5983.         aliases = {"serverprefix"},
  5984.         help = [[-- Set Server Prefix
  5985.         -- Syntax: %s [Prefix]
  5986.         -- Will set the server prefix on sv_say messages to whatever you want (e.g. **SERVER** **MYCLAN** **PHASOR**)]]
  5987.     },
  5988.     {
  5989.         arguments = {"Remaining Arguments", minArgs = 0, maxArgs = 1},
  5990.         func = function(executorPlayerId, prefix)
  5991.  
  5992.             if prefix == "default" then
  5993.                 server_prefix = nil
  5994.                 sendresponse("Prefix is now set to default.", executorPlayerId)
  5995.             elseif prefix then
  5996.                 server_prefix = prefix
  5997.                 sendresponse(server_prefix .. " is the new prefix.", executorPlayerId)
  5998.             else
  5999.                 sendresponse(server_prefix .. " is the current prefix.", executorPlayerId)
  6000.             end
  6001.         end
  6002.     }
  6003. )
  6004.  
  6005. Commands.Create(
  6006.     "setmode",
  6007.     {
  6008.         aliases = {"modeset"},
  6009.         scrimBlock = true,
  6010.         help = [[-- mode
  6011.         -- Syntax: %s [Player] [Mode] {Object}
  6012.         -- destroy
  6013.         -- portalgun
  6014.         -- entergun
  6015.         -- spawngun
  6016.         -- normal]]
  6017.     },
  6018.     {
  6019.         arguments = {"Player", "String", "String", minArgs = 2, maxArgs = 2},
  6020.         func = function(executorPlayerId, players, bulletmode)
  6021.             local playerId
  6022.             for i = 1,#players do playerId = players[i]
  6023.                 if bulletmode == "destroy" then
  6024.                     player_table[playerId].bulletmode = "destroy"
  6025.                     cmdreply[cmdreply()] = getname(playerId) .. " is now in destroy mode"
  6026.                 elseif bulletmode == "portalgun" then
  6027.                     player_table[playerId].bulletmode = "portalgun"
  6028.                     cmdreply[cmdreply()] = getname(playerId) .. " is now in portalgun mode"
  6029.                 elseif bulletmode == "entergun" then
  6030.                     player_table[playerId].bulletmode = "entergun"
  6031.                     cmdreply[cmdreply()] = getname(playerId) .. " is now in entergun mode"
  6032.                 elseif bulletmode == "normal" or bulletmode == "none" or bulletmode == "regular" then
  6033.                     local ptable = player_table[playerId]
  6034.                     ptable.objspawnid = false
  6035.                     ptable.bulletmode = false
  6036.                     cmdreply[cmdreply()] = getname(playerId) .. " is now in normal mode"
  6037.                 else
  6038.                     cmdreply[cmdreply()] = "Invalid mode"
  6039.                 end
  6040.             end
  6041.        
  6042.             sendresponse(cmdreply, executorPlayerId)
  6043.        
  6044.         end
  6045.     },
  6046.     {
  6047.         arguments = {"Player", "String", "String", "String", minArgs = 3, maxArgs = 3},
  6048.         func = function(executorPlayerId, players, bulletmode, object)
  6049.             if bulletmode == "spawngun" then
  6050.                 local thisObject = objects[object]
  6051.                 if thisObject then
  6052.                     local playerId, ptable
  6053.                     for i = 1,#players do playerId = players[i]
  6054.                         ptable = player_table[playerId]
  6055.                         ptable.bulletmode = "spawngun"
  6056.                         ptable.objspawnid = thisObject
  6057.                         cmdreply[cmdreply()] = getname(playerId) .. " is now spawning " .. thisObject.name .. ""
  6058.                     end
  6059.                 else
  6060.                     cmdreply[cmdreply()] = "Object does not exist. Make sure you are spelling it correctly."
  6061.                 end
  6062.             end
  6063.            
  6064.             sendresponse(cmdreply, executorPlayerId)
  6065.            
  6066.         end
  6067.     }
  6068. )
  6069.  
  6070. Commands.Create(
  6071.     "pass",
  6072.     {
  6073.         aliases = {"password", "setpassword"},
  6074.         help = [[-- Set Server Password
  6075.         -- Syntax: %s {Password}]]
  6076.     },
  6077.     {
  6078.         arguments = {"Password", minArgs = 0, maxArgs = 1},
  6079.         func = function(executorPlayerId, password)
  6080.  
  6081.             if not password then
  6082.                 sendresponse(readstring(addresses.network_server_globals + 0x8, 8), executorPlayerId)
  6083.             elseif password == "" then
  6084.                 writestring(addresses.network_server_globals + 0x8, 8, "")
  6085.                 sendresponse("Password has been taken off", executorPlayerId)
  6086.             elseif password then
  6087.                 writestring(addresses.network_server_globals + 0x8, 8, password)
  6088.                 sendresponse("The password is now " .. password, executorPlayerId)
  6089.             end
  6090.         end
  6091.     }
  6092. )
  6093.  
  6094. Commands.Create(
  6095.     "reloadadmins",
  6096.     {
  6097.         aliases = {"reloadadminlist", "adminlistreload", "adminsreload"},
  6098.         help = [[-- Reload Admin List
  6099.         -- Syntax: %s
  6100.         -- Loads all admins from the admin file.]]
  6101.     },
  6102.     {
  6103.         arguments = {minArgs = 0, maxArgs = 0},
  6104.         func = function(executorPlayerId)
  6105.             loadAllAdminFiles()
  6106.    
  6107.             -- We can now archive the other admin files without worrying about losing the data.
  6108.             os.rename(profilepath .. "ipadmins.txt", profilepath .. "archived_ipadmins.txt")
  6109.             os.rename(profilepath .. "admin.txt", profilepath .. "archived_admin.txt")
  6110.            
  6111.             sendresponse("All admins have been reloaded from the file.", executorPlayerId)
  6112.         end
  6113.     }
  6114. )
  6115.  
  6116. Commands.Create(
  6117.     "reloadbanlist",
  6118.     {
  6119.         aliases = {"reloadbans", "banlistreload", "reloadbanlist", "refreshipbans"},
  6120.         help = [[-- Reload Banlist
  6121.         -- Syntax: %s
  6122.         -- Loads all bans from the ban file.]]
  6123.     },
  6124.     {
  6125.         arguments = {minArgs = 0, maxArgs = 0},
  6126.         func = function(executorPlayerId)
  6127.             loadBanFile(profilepath .. "ipbans.txt", "ip") -- load sapp ip bans
  6128.             loadBanFile(profilepath .. "ipbanlist.txt", "ip") -- load ipbanlist file for backwards compatibility
  6129.             loadBanFile(profilepath .. "iprangebanlist.txt", "ip") -- load iprangebanlist file for backwards compatibility
  6130.             loadBanFile(profilepath .. "textbanlist.txt", "chat") -- load textbanlist file for backwards compatibility
  6131.             loadBanFile(profilepath .. "namebans.txt", "name") -- load textbanlist file for backwards compatibility
  6132.            
  6133.             loadBanFile(profilepath .. defaults.banlist_file .. ".txt")
  6134.            
  6135.             -- Check if a banned player is in the server.
  6136.             local hash, ip, ban_entry
  6137.             for playerId = 0,15 do
  6138.                 if getplayer(playerId) then
  6139.                     hash, ip = gethash(playerId), getip(playerId)
  6140.                     for id = 1,#ban_table do ban_entry = ban_table[id]
  6141.                         if ban_entry.time ~= "Unbanned" and (ban_table.type == "hash" and hash == ban_table.hash or ban_table.type == "ip" and ban_table.ip == ip) then
  6142.                             registertimer(0, "tempBanPlayer", resolveplayer(playerId))
  6143.                         end
  6144.                     end
  6145.                 end
  6146.             end
  6147.            
  6148.             updateBanFiles()
  6149.             sendresponse("The Banlist has been reloaded.", executorPlayerId)
  6150.         end
  6151.     }
  6152. )
  6153.  
  6154. Commands.Create(
  6155.     "respawntime",
  6156.     {
  6157.         aliases = {"setresp"},
  6158.         help = [[-- Server Respawn Time
  6159.         -- Syntax: %s {Time}
  6160.         -- Sets the default respawn time for all players.]]
  6161.     },
  6162.     {
  6163.         arguments = {"Time", minArgs = 0, maxArgs = 1},
  6164.         func = function(executorPlayerId, time)
  6165.             if time == -1 then
  6166.                 sendresponse("Respawn time is currently: " .. (defaults.respawn_time ~= -1 and timetoword(defaults.respawn_time) or "Default"))
  6167.             else
  6168.                 defaults.respawn_time = time
  6169.                 sendresponse("Respawn time set to " .. (time ~= -1 and timetoword(time) or "Default"), executorPlayerId)
  6170.             end
  6171.         end
  6172.     }
  6173. )
  6174.  
  6175. Commands.Create(
  6176.     "setspeed",
  6177.     {
  6178.         aliases = {"spd", "s", "speed", "speedset"},
  6179.         scrimBlock = true,
  6180.         help = [[-- Set Speed
  6181.         -- Syntax: %s [Player] {Speed}
  6182.         -- Allow you to view/change the selected players' speed]]
  6183.     },
  6184.     {
  6185.         arguments = {"Player", "Number", minArgs = 1, maxArgs = 2},
  6186.         func = function(executorPlayerId, players, speed)
  6187.             local playerId, m_player
  6188.             if not speed then
  6189.                 for i = 1,#players do playerId = players[i]
  6190.                     speed = readfloat(getplayer(playerId) + 0x6C)
  6191.                     sendresponse(getname(playerId) .. "'s speed is currently " .. speed, executorPlayerId)
  6192.                 end
  6193.             else
  6194.                 for i = 1,#players do playerId = players[i]
  6195.                     setspeed(playerId, speed)
  6196.                     sendresponse(getname(playerId) .. " had their speed changed to " .. speed, executorPlayerId)
  6197.                 end
  6198.             end
  6199.         end
  6200.     }
  6201. )
  6202.  
  6203. Commands.Create(
  6204.     "setteleport",
  6205.     {
  6206.         aliases = {"teleportadd", "addteleport", "tadd", "st", "tpadd", "addtp", "addlocation", "locationadd"},
  6207.         help = [[--Set Teleport Location
  6208.         -- Syntax: %s [Location] [Player or X] {Y} {Z}
  6209.         -- Adds a teleport location wherever the specified player is standing.
  6210.         -- Or you can manually specify XYZ Coordinates for a location]]
  6211.     },
  6212.     {
  6213.         arguments = {"String", "Number", "Number", "Number", "String", minArgs = 4, maxArgs = 5},
  6214.         func = function(executorPlayerId, locname, x, y, z, map)
  6215.             locations[map or Map][locname] = TM{x, y, z}
  6216.             sendresponse("'" .. locname .. "' has been added as a teleport location!", executorPlayerId)
  6217.         end
  6218.     },
  6219.     {
  6220.         arguments = {"String", "Single Player", minArgs = 1, maxArgs = 1},
  6221.         func = function(executorPlayerId, locname, playerId)
  6222.             local m_playerObj, playerObjId = getplayerobject(playerId)
  6223.             if not m_playerObj then
  6224.                 sendresponse("Cannot add teleport because the player is dead.", executorPlayerId)
  6225.                 return
  6226.             end
  6227.            
  6228.             if locations[Map][locname] then
  6229.                 sendresponse("Location '" .. locname .. "' already exists on this map!\nUse sv_teleport_del to remove it from the list first.", executorPlayerId)
  6230.                 return
  6231.             end
  6232.            
  6233.             local x,y,z = getobjectcoords(playerObjId)
  6234.             locations[Map][locname] = TM{x, y, z}
  6235.             sendresponse("'" .. locname .. "' has been added as a teleport location!", executorPlayerId)
  6236.         end
  6237.     }
  6238. )
  6239.  
  6240. Commands.Create(
  6241.     "teleportlist",
  6242.     {
  6243.         aliases = {"tlist", "listteleports", "locations", "teleports", "locs"},
  6244.         help = [[--List Teleport Locations
  6245.         -- Syntax: %s {Map}
  6246.         -- Lists all the teleport locations available for teleporting.]]
  6247.     },
  6248.     {
  6249.         arguments = {"String", minArgs = 0, maxArgs = 0},
  6250.         func = function(executorPlayerId, map)
  6251.             sendresponse("Teleport Locations " .. (map and (" for map " .. map) or ""), executorPlayerId)
  6252.             cmdreply.header = "Map Location"
  6253.             cmdreply.align = true
  6254.             cmdreply.delim = " "
  6255.             for thisMap,mapLocations in next,locations do
  6256.                 for locname,_ in next,mapLocations do
  6257.                     if not map and Map == thisMap or map == thisMap then
  6258.                         cmdreply[cmdreply()] = thisMap .. " " .. locname
  6259.                     end
  6260.                 end
  6261.             end
  6262.            
  6263.             sendresponse(cmdreply, executorPlayerId)
  6264.         end
  6265.     }
  6266. )
  6267.  
  6268. local function Spawn(players, amount, resp_time, bRecycle, obj_display_name, objtype, mapId, spawnmethod, executorPlayerId)
  6269.     amount = amount or 1
  6270.     bRecycle = bRecycle or false
  6271.     local playerId, m_playerObj, playerObjId, objectId, x, y, z, camera_x, camera_y
  6272.     for i = 1,#players do playerId = players[i]
  6273.         m_playerObj, playerObjId = getplayerobject(playerId)
  6274.         if m_playerObj then
  6275.        
  6276.             -- Spawn the object right where they are looking (should work for vehicles too)
  6277.             x,y,z = getobjectcoords(playerObjId)
  6278.             camera_x = readfloat(m_playerObj + 0x230)
  6279.             camera_y = readfloat(m_playerObj + 0x234)
  6280.             x = x + camera_x * 2
  6281.             y = y + camera_y * 2
  6282.            
  6283.             -- Check if they actually wanted to spawn something.
  6284.             if amount == 0 then sendresponse("You didn't spawn anything!", executorPlayerId) return end
  6285.            
  6286.             -- Create the object
  6287.             for i = 1,amount do
  6288.                 objectId = createobject(mapId, 0, resp_time, bRecycle, x, y + i, z + i*2)
  6289.             end
  6290.            
  6291.             -- check if object was spawned correctly
  6292.             if objectId then
  6293.                 if not spawnmethod then
  6294.                     sendresponse(obj_display_name .. " spawned at " .. getname(playerId) .. "'s location.", executorPlayerId)
  6295.                 elseif spawnmethod == "give" then
  6296.                     assignweapon(playerId, objectId)
  6297.                     sendresponse(obj_display_name .. " given to " .. getname(playerId), executorPlayerId)
  6298.                 elseif spawnmethod == "enter" then
  6299.                     local drones = player_table[playerId].drones
  6300.                     drones[#drones+1] = objectId
  6301.                     entervehicle(playerId, objectId, 0)
  6302.                     sendresponse(getname(playerId) .. " was forced to enter a " .. obj_display_name, executorPlayerId)
  6303.                 end
  6304.             else
  6305.                 sendresponse("Error spawning object: " .. mapId, executorPlayerId)
  6306.             end
  6307.         else
  6308.             sendresponse("Player is dead", executorPlayerId)
  6309.         end
  6310.     end
  6311.     return objectId
  6312. end
  6313.  
  6314. Commands.Create(
  6315.     "spawn",
  6316.     {
  6317.         aliases = {"spawnobj", "create", "createobject", "spawnobject", "objspawn"},
  6318.         help = [[-- Spawn
  6319.         -- Syntax: %s [Object] [Player] {Amount} {Respawn Time} {Recycle Boolean}
  6320.         -- Spawns specified object near the specified player]]
  6321.     },
  6322.     {
  6323.         arguments = {"String", "Player", "Whole Number", "Number", "Boolean", minArgs = 1, maxArgs = 5},
  6324.         func = function(executorPlayerId, object, players, amount, resp_time, recycle, spawn_type)
  6325.             if not spawn_type then
  6326.                 if object == "cyborg" or object == "bot" or object == "mastercheif" or object == "masterchief" then
  6327.                     Spawn(players, amount, resp_time, recycle, "Cyborg", "bipd", gettag("bipd", "characters\\cyborg_mp\\cyborg_mp"), spawn_type, executorPlayerId)
  6328.                 elseif object == "captain" or object == "keyes" then
  6329.                     Spawn(players, amount, resp_time, recycle, "Captain Keyes", "bipd", gettag("bipd", "characters\\captain\\captain"), spawn_type, executorPlayerId)
  6330.                 elseif object == "cortana" then
  6331.                     Spawn(players, amount, resp_time, recycle, "Cortana", "bipd", gettag("bipd", "characters\\cortana\\cortana"), spawn_type, executorPlayerId)
  6332.                 elseif object == "cortana2" then
  6333.                     Spawn(players, amount, resp_time, recycle, "Cortana2", "bipd", gettag("bipd", "characters\\cortana\\halo_enhanced\\halo_enhanced"), spawn_type, executorPlayerId)
  6334.                 elseif object == "crewman" then
  6335.                     Spawn(players, amount, resp_time, recycle, "Crewman", "bipd", gettag("bipd", "characters\\crewman\\crewman"), spawn_type, executorPlayerId)
  6336.                 elseif object == "elite" then
  6337.                     Spawn(players, amount, resp_time, recycle, "elite", "bipd", gettag("bipd", "characters\\elite\\elite"), spawn_type, executorPlayerId)
  6338.                 elseif object == "elite2" then
  6339.                     Spawn(players, amount, resp_time, recycle, "Elite Special", "bipd", gettag("bipd", "characters\\elite\\elite special"), spawn_type, executorPlayerId)
  6340.                 elseif object == "engineer" then
  6341.                     Spawn(players, amount, resp_time, recycle, "Engineer", "bipd", gettag("bipd", "characters\\engineer\\engineer"), spawn_type, executorPlayerId)
  6342.                 elseif object == "flood" then
  6343.                     Spawn(players, amount, resp_time, recycle, "Flood Captain", "bipd", gettag("bipd", "characters\\flood_captain\\flood_captain"), spawn_type, executorPlayerId)
  6344.                 elseif object == "flood2" then
  6345.                     Spawn(players, amount, resp_time, recycle, "Flood Infection", "bipd", gettag("bipd", "characters\\flood_infection\\flood_infection"), spawn_type, executorPlayerId)
  6346.                 elseif object == "flood3" then
  6347.                     Spawn(players, amount, resp_time, recycle, "Flood Carrier", "bipd", gettag("bipd", "characters\\floodcarrier\\floodcarrier"), spawn_type, executorPlayerId)
  6348.                 elseif object == "floodelite" then
  6349.                     Spawn(players, amount, resp_time, recycle, "FloodCombat Elite", "bipd", gettag("bipd", "characters\\floodcombat elite\\floodcombat elite"), spawn_type, executorPlayerId)
  6350.                 elseif object == "floodhuman" then
  6351.                     Spawn(players, amount, resp_time, recycle, "FloodCombat Human", "bipd", gettag("bipd", "characters\\floodcombat_human\\floodcombat_human"), spawn_type, executorPlayerId)
  6352.                 elseif object == "pedobear" or object == "grunt" then
  6353.                     Spawn(players, amount, resp_time, recycle, "Pedobear", "bipd", gettag("bipd", "characters\\grunt\\grunt"), spawn_type, executorPlayerId)
  6354.                 elseif object == "hunter" then
  6355.                     Spawn(players, amount, resp_time, recycle, "Hunter", "bipd", gettag("bipd", "characters\\hunter\\hunter"), spawn_type, executorPlayerId)
  6356.                 elseif object == "marine" then
  6357.                     Spawn(players, amount, resp_time, recycle, "Marine", "bipd", gettag("bipd", "characters\\marine\\marine"), spawn_type, executorPlayerId)
  6358.                 elseif object == "marinesuicide" or object == "marine2" then
  6359.                     Spawn(players, amount, resp_time, recycle, "Marine Suicidal", "bipd", gettag("bipd", "characters\\marine_suicidal\\marine_suicidal"), spawn_type, executorPlayerId)
  6360.                 elseif object == "monitor" then
  6361.                     Spawn(players, amount, resp_time, recycle, "Monitor", "bipd", gettag("bipd", "characters\\monitor\\monitor"), spawn_type, executorPlayerId)
  6362.                 elseif object == "sentinel" then
  6363.                     Spawn(players, amount, resp_time, recycle, "Sentinel", "bipd", gettag("bipd", "characters\\sentinel\\sentinel"), spawn_type, executorPlayerId)
  6364.                 elseif object == "johnson" then
  6365.                     Spawn(players, amount, resp_time, recycle, "Sgt. Johnson", "bipd", gettag("bipd", "characters\\johnson\\johnson"), spawn_type, executorPlayerId)
  6366.                 elseif object == "camo" or object == "camouflage" then
  6367.                     Spawn(players, amount, resp_time, recycle, "Camouflage", "eqip", gettag("eqip", "powerups\\active camouflage"), spawn_type, executorPlayerId)
  6368.                 elseif object == "dblspd" then
  6369.                     Spawn(players, amount, resp_time, recycle, "Double Speed", "eqip", gettag("eqip", "powerups\\double speed"), spawn_type, executorPlayerId)
  6370.                 elseif object == "fullspec" then
  6371.                     Spawn(players, amount, resp_time, recycle, "Full-Spectrum Vision", "eqip", gettag("eqip", "powerups\\full-spectrum vision"), spawn_type, executorPlayerId)
  6372.                 elseif object == "fnade" or object == "nades" then
  6373.                     Spawn(players, amount, resp_time, recycle, "Frag Grenade", "eqip", gettag("eqip", "weapons\\frag grenade\\frag grenade"), spawn_type, executorPlayerId)
  6374.                 elseif object == "pnade" then
  6375.                     Spawn(players, amount, resp_time, recycle, "Plasma Grenade", "eqip", gettag("eqip", "weapons\\plasma grenade\\plasma grenade"), spawn_type, executorPlayerId)
  6376.                 elseif object == "overshield" or object == "os" then
  6377.                     Spawn(players, amount, resp_time, recycle, "Overshield", "eqip", gettag("eqip", "powerups\\over shield"), spawn_type, executorPlayerId)
  6378.                 elseif object == "rifleammo" then
  6379.                     Spawn(players, amount, resp_time, recycle, "Assault Rifle Ammo", "eqip", gettag("eqip", "powerups\\assault rifle ammo\\assault rifle ammo"), spawn_type, executorPlayerId)
  6380.                 elseif object == "healthpack" then
  6381.                     Spawn(players, amount, resp_time, recycle, "Health Pack", "eqip", gettag("eqip", "powerups\\health pack"), spawn_type, executorPlayerId)
  6382.                 elseif object == "needlerammo" then
  6383.                     Spawn(players, amount, resp_time, recycle, "Needler Ammo", "eqip", gettag("eqip", "powerups\\needler ammo\\needler ammo"), spawn_type, executorPlayerId)
  6384.                 elseif object == "pistolammo" then
  6385.                     Spawn(players, amount, resp_time, recycle, "Pistol Ammo", "eqip", gettag("eqip", "powerups\\pistol ammo\\pistol ammo"), spawn_type, executorPlayerId)
  6386.                 elseif object == "rocketammo" then
  6387.                     Spawn(players, amount, resp_time, recycle, "Rocket Ammo", "eqip", gettag("eqip", "powerups\\rocket launcher ammo\\rocket launcher ammo"), spawn_type, executorPlayerId)
  6388.                 elseif object == "shottyammo" then
  6389.                     Spawn(players, amount, resp_time, recycle, "Shotgun Ammo", "eqip", gettag("eqip", "powerups\\shotgun ammo\\shotgun ammo"), spawn_type, executorPlayerId)
  6390.                 elseif object == "sniperammo" then
  6391.                     Spawn(players, amount, resp_time, recycle, "Sniper Ammo", "eqip", gettag("eqip", "powerups\\sniper rifle ammo\\sniper rifle ammo"), spawn_type, executorPlayerId)
  6392.                 elseif object == "flameammo" then
  6393.                     Spawn(players, amount, resp_time, recycle, "Flamethrower Ammo", "eqip", gettag("eqip", "powerups\\flamethrower ammo\\flamethrower ammo"), spawn_type, executorPlayerId)
  6394.                 end
  6395.             end
  6396.             if spawn_type ~= "enter" then
  6397.                 if object == "energysword" or object == "esword" then
  6398.                     Spawn(players, amount, resp_time, recycle, "Energy Sword", "weap", gettag("weap", "weapons\\energy sword\\energy sword"), spawn_type, executorPlayerId)
  6399.                 elseif object == "ball" or object == "oddball" then
  6400.                     Spawn(players, amount, resp_time, recycle, "Oddball", "weap", gettag("weap", "weapons\\ball\\ball"), spawn_type, executorPlayerId)
  6401.                 elseif object == "flag" then
  6402.                     Spawn(players, amount, resp_time, recycle, "Flag", "weap", gettag("weap", "weapons\\flag\\flag"), spawn_type, executorPlayerId)
  6403.                 elseif object == "frg" or object == "fuelrod" or object == "rod" or object == "plasmacannon" then
  6404.                     Spawn(players, amount, resp_time, recycle, "Fuel Rod", "weap", gettag("weap", "weapons\\plasma_cannon\\plasma_cannon"), spawn_type, executorPlayerId)
  6405.                 elseif object == "ggun" or object == "gravitygun" then
  6406.                     Spawn(players, amount, resp_time, recycle, "Gravity Gun", "weap", gettag("weap", "weapons\\gravity rifle\\gravity rifle"), spawn_type, executorPlayerId)
  6407.                 elseif object == "needler" then
  6408.                     Spawn(players, amount, resp_time, recycle, "Needler", "weap", gettag("weap", "weapons\\needler\\mp_needler"), spawn_type, executorPlayerId)
  6409.                 elseif object == "pistol" then
  6410.                     Spawn(players, amount, resp_time, recycle, "Pistol", "weap", gettag("weap", "weapons\\pistol\\pistol"), spawn_type, executorPlayerId)
  6411.                 elseif object == "ppistol" or object == "plasmapistol" then
  6412.                     Spawn(players, amount, resp_time, recycle, "Plasma Pistol", "weap", gettag("weap", "weapons\\plasma pistol\\plasma pistol"), spawn_type, executorPlayerId)
  6413.                 elseif object == "prifle" or object == "plasmarifle" then
  6414.                     Spawn(players, amount, resp_time, recycle, "Plasma Rifle", "weap", gettag("weap", "weapons\\plasma rifle\\plasma rifle"), spawn_type, executorPlayerId)
  6415.                 elseif object == "rifle" or object == "arifle" or object == "assaultrifle" then
  6416.                     Spawn(players, amount, resp_time, recycle, "Assault Rifle", "weap", gettag("weap", "weapons\\assault rifle\\assault rifle"), spawn_type, executorPlayerId)
  6417.                 elseif object == "rocket" or object == "rocketlauncher" or object == "rox" then
  6418.                     Spawn(players, amount, resp_time, recycle, "Rocket Launcher", "weap", gettag("weap", "weapons\\rocket launcher\\rocket launcher"), spawn_type, executorPlayerId)
  6419.                 elseif object == "shotty" or object == "shotgun" then
  6420.                     Spawn(players, amount, resp_time, recycle, "Shotgun", "weap", gettag("weap", "weapons\\shotgun\\shotgun"), spawn_type, executorPlayerId)
  6421.                 elseif object == "sniper" or object == "sniperrifle" then
  6422.                     Spawn(players, amount, resp_time, recycle, "Sniper Rifle", "weap", gettag("weap", "weapons\\sniper rifle\\sniper rifle"), spawn_type, executorPlayerId)
  6423.                 elseif object == "flamer" or object == "flamethrower" then
  6424.                     Spawn(players, amount, resp_time, recycle, "Flamethrower", "weap", gettag("weap", "weapons\\flamethrower\\flamethrower"), spawn_type, executorPlayerId)
  6425.                 elseif spawn_type == "give" then
  6426.                     goto objNotFound
  6427.                 end
  6428.                 if spawn_type == "give" then return end
  6429.             end
  6430.             if spawn_type ~= "give" then
  6431.                 if object == "wraith" then
  6432.                     Spawn(players, amount, resp_time, recycle, "Wraith", "vehi", gettag("vehi", "vehicles\\wraith\\wraith"), spawn_type, executorPlayerId)
  6433.                 elseif object == "peli" or object == "pelican" then
  6434.                     Spawn(players, amount, resp_time, recycle, "Pelican", "vehi", gettag("vehi", "vehicles\\pelican\\pelican"), spawn_type, executorPlayerId)
  6435.                 elseif object == "ghost" then
  6436.                     Spawn(players, amount, resp_time, recycle, "Ghost", "vehi", gettag("vehi", "vehicles\\ghost\\ghost_mp"), spawn_type, executorPlayerId)
  6437.                 elseif object == "hog" or object == "warthog" then
  6438.                     Spawn(players, amount, resp_time, recycle, "Warthog", "vehi", gettag("vehi", "vehicles\\warthog\\mp_warthog"), spawn_type, executorPlayerId)
  6439.                 elseif object == "rhog" or object == "rocketwarthog" then
  6440.                     Spawn(players, amount, resp_time, recycle, "Rocket Warthog", "vehi", gettag("vehi", "vehicles\\rwarthog\\rwarthog"), spawn_type, executorPlayerId)
  6441.                 elseif object == "shee" or object == "banshee" then
  6442.                     Spawn(players, amount, resp_time, recycle, "Banshee", "vehi", gettag("vehi", "vehicles\\banshee\\banshee_mp"), spawn_type, executorPlayerId)
  6443.                 elseif object == "tank" or object == "scorpion" then
  6444.                     Spawn(players, amount, resp_time, recycle, "Tank", "vehi", gettag("vehi", "vehicles\\scorpion\\scorpion_mp"), spawn_type, executorPlayerId)
  6445.                 elseif object == "turret" or object == "shade" then
  6446.                     Spawn(players, amount, resp_time, recycle, "Gun Turret", "vehi", gettag("vehi", "vehicles\\c gun turret\\c gun turret_mp"), spawn_type, executorPlayerId)
  6447.                 else
  6448.                     goto objNotFound
  6449.                 end
  6450.                 return
  6451.             end
  6452.            
  6453.             ::objNotFound::
  6454.            
  6455.             if spawn_type == "give" then
  6456.                 sendresponse("Invalid Weapon", executorPlayerId)
  6457.             elseif spawn_type == "enter" then
  6458.                 sendresponse("Invalid Vehicle", executorPlayerId)
  6459.             elseif not spawn_type then
  6460.                 sendresponse("Invalid Object", executorPlayerId)
  6461.             end
  6462.         end
  6463.     }
  6464. )
  6465.  
  6466. Commands.Create(
  6467.     "enter",
  6468.     {
  6469.         aliases = {"entervehicle", "vehicleeneter", "vehienter", "entervehi"},
  6470.         scrimBlock = true,
  6471.         help = [[-- Enter Vehicle
  6472.         -- Syntax: %s [Player1 or Vehicle] [Player2]
  6473.         -- Force specified player into specified vehicle
  6474.         -- Or will put player1 into player2's vehicle, provided halo will let them.
  6475.         -- You cannot enter a vehicle of an enemy (unless sv_multiteam_vehicles is enabled in Free-For-All GameTypes)]]
  6476.     },
  6477.     {
  6478.         arguments = {"String", "Player", minArgs = 1, maxArgs = 2},
  6479.         func = function(executorPlayerId, object, players) Commands.spawn[2].func(executorPlayerId, object, players, nil, nil, nil, "enter") end
  6480.     },
  6481.     {
  6482.         arguments = {"Player", "Single Player", "Whole Number", minArgs = 3, maxArgs = 3},
  6483.         func = function(executorPlayerId, players, playerId2, seat)
  6484.        
  6485.             local m_vehicleObj, vehicleObjId = getplayervehicle(playerId2)
  6486.             if not m_vehicleObj then
  6487.                 sendresponse(getname(playerId2) .. " is not in a vehicle!", executorPlayerId)
  6488.                 return
  6489.             end
  6490.        
  6491.             local playerId
  6492.             for i = 1,#players do playerId = players[i]
  6493.                 entervehicle(playerId, vehicleObjId, seat)
  6494.                 sendresponse("Entering " .. getname(playerId) .. " into " .. getname(playerId2) .. "'s vehicle!", executorPlayerId)
  6495.             end
  6496.         end
  6497.     }
  6498. )
  6499.  
  6500. Commands.Create(
  6501.     "give",
  6502.     {
  6503.         aliases = {"giveweapon", "weapongive"},
  6504.         scrimBlock = true,
  6505.         help = [[-- Give
  6506.         -- Syntax: %s [Object] [Player]
  6507.         -- Gives specified player the specified weapon]]
  6508.     },
  6509.     {
  6510.         arguments = {"String", "Player", minArgs = 1, maxArgs = 2},
  6511.         func = function(executorPlayerId, object, players) Commands.spawn[2].func(executorPlayerId, object, players, nil, nil, nil, "give") end
  6512.     }
  6513. )
  6514.  
  6515. Commands.Create(
  6516.     "spammax",
  6517.     {
  6518.         aliases = {"smax", "maxspam"},
  6519.         help = [[-- SpamMax
  6520.         -- Syntax: %s {Value or Boolean}
  6521.         -- Determines how many messages a player can send before a player is muted.
  6522.         -- Wizard recommends leaving this at the default, but you're welcome to change it
  6523.         -- Setting this to false or 0 will disable Spam Protection.]]
  6524.     },
  6525.     {
  6526.         arguments = {"Boolean", minArgs = 0, maxArgs = 1},
  6527.         func = function(executorPlayerId, boolean)
  6528.             if boolean == false and defaults.spam_max ~= false then
  6529.                 defaults.spam_max = 0
  6530.                 sendresponse("Spam protection is now disabled", executorPlayerId)
  6531.             elseif not boolean and defaults.spam_max == false then
  6532.                 sendresponse("Spam protection is already disabled", executorPlayerId)
  6533.             elseif boolean then
  6534.                 defaults.spam_max = 7
  6535.                 sendresponse("Spam protection is now on!", executorPlayerId)
  6536.             end
  6537.         end
  6538.     },
  6539.     {
  6540.         arguments = {"Number", minArgs = 0, maxArgs = 1},
  6541.         func = function(executorPlayerId, time)
  6542.             if time == -1 then
  6543.                 sendresponse("The Spam max is currently '" .. defaults.spam_max .. "'", executorPlayerId)
  6544.             else
  6545.                 defaults.spam_max = time
  6546.                 sendresponse("The Spam max is now " .. time, executorPlayerId)
  6547.             end
  6548.         end
  6549.     }
  6550. )
  6551.  
  6552. Commands.Create(
  6553.     "spamtimeout",
  6554.     {
  6555.         aliases = {"timeoutspam"},
  6556.         help = [[-- SpamTimeout
  6557.         -- Syntax: %s {Time}
  6558.         -- Changes the time you are muted for spamming]],
  6559.     },
  6560.     {
  6561.         arguments = {"Time", minArgs = 0, maxArgs = 1},
  6562.         func = function(executorPlayerId, time)
  6563.             if time == -1 then
  6564.                 sendresponse("Spam timeout is currently " .. timetoword(defaults.spam_timeout), executorPlayerId)
  6565.             else
  6566.                 defaults.spam_timeout = time
  6567.                 sendresponse("The Spam timeout is now " .. timetoword(time), executorPlayerId)
  6568.             end
  6569.         end
  6570.     }
  6571. )
  6572.  
  6573. Commands.Create(
  6574.     "specs",
  6575.     {
  6576.         aliases = {"serverspecs", "machineinfo"},
  6577.         help = [[-- Specs
  6578.         -- Syntax: %s
  6579.         -- Display the server specifications (like processor, RAM, model, etc)]]
  6580.     },
  6581.     {
  6582.         arguments = {minArgs = 0, maxArgs = 0},
  6583.         func = function(executorPlayerId)
  6584.             sendresponse("The server specs are: " .. readstring(addresses.computer_specs_address), executorPlayerId)
  6585.         end
  6586.     }
  6587. )
  6588.  
  6589. Commands.Create(
  6590.     "mc",
  6591.     {
  6592.         aliases = {"mcbegin", "startcycle", "cyclestart", "mapcyclebegin"},
  6593.         is_alias = true,
  6594.         help = [[-- Start MapCycle
  6595.         -- Syntax: %s
  6596.         -- Shortcut for sv_mapcycle_begin]]
  6597.     },
  6598.     {
  6599.         arguments = {minArgs = 0, maxArgs = 0},
  6600.         func = function(executorPlayerId)
  6601.             sendresponse(halo_svcmd("sv_mapcycle_begin", true), executorPlayerId)
  6602.         end
  6603.     }
  6604. )
  6605.  
  6606. Commands.Create(
  6607.     "statusmore",
  6608.     {
  6609.         aliases = {"serverinfo", "sinfo", "sinfo"},
  6610.         help = [[-- Status
  6611.         -- Syntax: %s
  6612.         -- Shows a list of all the init.txt commands and their status.]]
  6613.     },
  6614.     {
  6615.         arguments = {minArgs = 0, maxArgs = 0},
  6616.         func = function(executorPlayerId)
  6617.             for key,value in next,defaults do
  6618.                 cmdreply(capitalizeWords(key .. ": " .. value))
  6619.             end
  6620.             sendresponse(cmdreply, executorPlayerId)
  6621.         end
  6622.     }
  6623. )
  6624.  
  6625. Commands.Create(
  6626.     "superban",
  6627.     {
  6628.         aliases = {"ultraban"},
  6629.         help = [[-- Superban
  6630.         -- Syntax: %s [Player] {Time}
  6631.         -- Bans a person via their Name, IP, and Hash
  6632.         -- Most likely overkill in most situations
  6633.         -- This command does the same as doing the following,
  6634.         -- where player is the player being banned, and time is a time if specified
  6635.         -- sv_ipban player time        sv_nameban player        sv_ban player time]],
  6636.         usesBanCounts = true,
  6637.     },
  6638.     {
  6639.         arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3},
  6640.         func = function(executorPlayerId, players, time, reason)
  6641.  
  6642.             local exname = getname(executorPlayerId)
  6643.             local playerId, name, b
  6644.             for i = 1,#players do playerId = players[i]
  6645.                 name = getname(playerId)
  6646.                 if not checkAdminBlockerAccess(executorPlayerId, playerId) then
  6647.                     sendresponse("You cannot use this command on " .. name, executorPlayerId)
  6648.                     privatesay(playerId, exname .. " attemped to use SuperBan on you!")
  6649.                     goto continue
  6650.                 end
  6651.                
  6652.                 reason = reason == "None Given" and "SuperBan" or reason
  6653.                 WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was Super-Banned by " .. exname .. " Reason: " .. reason .. " Type: All Bans")
  6654.                 say(name .. " was Super Banned from the server! Reason: " .. reason)
  6655.                 local b = TM.New()
  6656.                 b.name,b.type,b.reason = name,"name","SuperBan"
  6657.                 ban_table[#ban_table+1] = b
  6658.                 addBan(name, nil, getip(playerId) .. "/24", time, "ip", reason)
  6659.                 svcmd("sv_ban " .. resolveplayer(playerId) .. " " .. timetoword(time))
  6660.                
  6661.                 ::continue::
  6662.             end
  6663.         end
  6664.     }
  6665. )
  6666.  
  6667. Commands.Create(
  6668.     "suspend",
  6669.     {
  6670.         aliases = {"suspendplayer", "playersuspend", "suspendpl", "sleep"},
  6671.         scrimBlock = true,
  6672.         help = [[-- Suspend Player
  6673.         -- Syntax: %s [Player] {Time}
  6674.         -- Kills a player and prevents them from respawning.]]
  6675.     },
  6676.     {
  6677.         arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3},
  6678.         func = function(executorPlayerId, players, time, reason)
  6679.             reason = reason or "None Given"
  6680.             local playerId, iptable
  6681.             for i = 1,#players do playerId = players[i]
  6682.                 iptable = ip_table[getip(playerId)]
  6683.                 if iptable.suspended then
  6684.                     cmdreply[cmdreply()] = getname(playerId) .. " has already been suspended."
  6685.                     goto continue
  6686.                 end
  6687.  
  6688.                 local m_player = getplayer(playerId)
  6689.                 kill(playerId)
  6690.                 writedword(m_player + 0x2C, (time ~= -1 and time or 2880) * 30)
  6691.                 iptable.suspended = time ~= -1 and time or true
  6692.                 cmdreply[cmdreply()] = getname(playerId) .. " was suspended by an admin " .. (time ~= -1 and ("for " .. timetoword(time)) or "") .. " Reason: " .. reason
  6693.  
  6694.                 ::continue::
  6695.             end
  6696.            
  6697.             sendresponse(cmdreply, executorPlayerId)
  6698.         end
  6699.     }
  6700. )
  6701.  
  6702. Commands.Create(
  6703.     "unsuspend",
  6704.     {
  6705.         aliases = {"unsuspendplayer", "unsuspendpl", "playerunsuspend"},
  6706.         help = [[-- Unsuspend player
  6707.         -- Syntax: %s [Player]
  6708.         -- Unsuspend the specified player.]]
  6709.     },
  6710.     {
  6711.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  6712.         func = function(executorPlayerId, players)
  6713.    
  6714.             local playerId
  6715.             for i = 1,#players do playerId = players[i]
  6716.                 if not ip_table[getip(playerId)].suspended then
  6717.                     sendresponse(getname(playerId) .. " has never been suspended.", executorPlayerId)
  6718.                     goto continue
  6719.                 end
  6720.                
  6721.                 writedword(getplayer(playerId) + 0x2C, 0)
  6722.                 sendresponse(getname(playerId) .. " has been unsuspended", executorPlayerId)
  6723.                
  6724.                 ::continue::
  6725.             end
  6726.         end
  6727.     }
  6728. )
  6729.  
  6730. Commands.Create(
  6731.     "takeweapons",
  6732.     {
  6733.         aliases = {"removeweapons", "takeweaponspl", "takeweps"},
  6734.         scrimBlock = true,
  6735.         help = [[-- Take Weapons
  6736.         -- Syntax: %s [Player]
  6737.         -- Take all the weapons away from the specified player.]]
  6738.     },
  6739.     {
  6740.         arguments = {"Player", "Time", minArgs = 1, maxArgs = 1},
  6741.         func = function(executorPlayerId, players)
  6742.  
  6743.             local playerId, iptable, m_playerObj, playerObjId
  6744.             for i = 1,#players do playerId = players[i]
  6745.                 ip_table[getip(playerId)].disarmed = true
  6746.                 m_playerObj, playerObjId = getplayerobject(playerId)
  6747.                 if m_playerObj then
  6748.                     for j = 1,4 do
  6749.                         local m_weapon, weaponObjId = getplayerweapon(playerId, j)
  6750.                         if m_weapon then
  6751.                             destroyobject(weaponObjId)
  6752.                         end
  6753.                     end
  6754.                 end
  6755.                 cmdreply[cmdreply()] = getname(playerId) .. " now cannot pickup weapons"
  6756.             end
  6757.             sendresponse(cmdreply, executorPlayerId)
  6758.         end
  6759.     }
  6760. )
  6761.  
  6762. Commands.Create(
  6763.     "teleportdel",
  6764.     {
  6765.         aliases = {"tdel", "delteleport", "dellocation", "locationdel", "tpdel", "rmtel", "teldel", "deltel"},
  6766.         help = [[--Delete Teleport Location
  6767.         -- Syntax: %s [Location]
  6768.         -- Deletes the specified teleport location
  6769.         -- Use 'sv_teleport_list' to get a list of teleport locations.]]
  6770.     },
  6771.     {
  6772.         arguments = {"String", "String", minArgs = 1, maxArgs = 2},
  6773.         func = function(executorPlayerId, locname, map)
  6774.             if map and not locations[map] then
  6775.                 sendresponse("Invalid Map!", command, executorPlayerId)
  6776.                 return
  6777.             end
  6778.            
  6779.             if map and locations[map][locname] then
  6780.                 locations[map][locname] = nil
  6781.                 sendresponse("Location '" .. locname .. "' on map '" .. map .. "' has been removed from the teleport locations list!", executorPlayerId)
  6782.             elseif Map and locations[Map][locname] then
  6783.                 locations[Map][locname] = nil
  6784.                 sendresponse("Location '" .. locname .. "' on map '" .. map .. "' has been removed from the teleport locations list!", executorPlayerId)
  6785.             else
  6786.                 sendresponse("'" .. locname .. "' is not a teleport location\nUse sv_teleport_list for current teleport locations.", executorPlayerId)
  6787.             end
  6788.         end
  6789.     }
  6790. )
  6791.  
  6792. Commands.Create(
  6793.     "teleport",
  6794.     {
  6795.         aliases = {"tp", "t", "teletolocation", "tele"},
  6796.         help = [[--Teleport Player
  6797.         -- Syntax: %s [Player] [Player2 or Location or X] {Y} {Z}
  6798.         -- Teleports the specified players' to a location.
  6799.         -- Use 'sv_teleport_list' to get a list of teleport locations.
  6800.         -- You can also use this command to teleport to a set of XYZ coordinates]]
  6801.     },
  6802.     {
  6803.         arguments = {"Player", "Single Player", minArgs = 2, maxArgs = 2},
  6804.         func = function(executorPlayerId, players, playerId2)
  6805.             local m_player2Obj, player2ObjId = getplayerobject(playerId2)
  6806.             if not m_player2Obj then
  6807.                 sendresponse("The player you are trying to teleport to is dead!", executorPlayerId)
  6808.                 return
  6809.             end
  6810.            
  6811.             local teletoname = getname(playerId2)
  6812.             local x,y,z = getobjectcoords(player2ObjId)
  6813.             local playerId, m_playerObj, playerObjId, m_vehicleObj, vehicleObjId
  6814.             for i = 1,#players do playerId = players[i]
  6815.                
  6816.                 m_playerObj, playerObjId = getplayerobject(playerId)
  6817.                 if not m_playerObj then
  6818.                     cmdreply[cmdreply()] = "The players you are trying to teleport are dead"
  6819.                     goto continue
  6820.                 end
  6821.                
  6822.                 m_vehicleObj, vehicleObjId = getplayervehicle(playerId)
  6823.                 movobjectcoords(m_vehicleObj and vehicleObjId or playerObjId, x, y, z+1)
  6824.                 cmdreply[cmdreply()] = getname(playerId) .. " was teleported to " .. teletoname
  6825.                
  6826.                 ::continue::
  6827.             end
  6828.            
  6829.             sendresponse(cmdreply, executorPlayerId)
  6830.         end
  6831.     },
  6832.     {
  6833.         arguments = {"Player", "String", minArgs = 2, maxArgs = 2},
  6834.         func = function(executorPlayerId, players, location)
  6835.             local thisLocation = locations[Map][location]
  6836.             if not thisLocation then
  6837.                 sendresponse("Location '" .. location .. "' doesn't exist on this map!", executorPlayerId)
  6838.                 return
  6839.             end
  6840.            
  6841.             -- A player can never exist unless the game is started on a map.
  6842.             local x,y,z = thisLocation[1], thisLocation[2], thisLocation[3]
  6843.             local playerId, m_playerObj, playerObjId, m_vehicleObj, vehicleObjId
  6844.             for i = 1,#players do playerId = players[i]
  6845.                
  6846.                 m_playerObj, playerObjId = getplayerobject(playerId)
  6847.                 if not m_playerObj then
  6848.                     cmdreply[cmdreply()] = getname(playerId) .. " is dead and cannot be teleported."
  6849.                     goto continue
  6850.                 end
  6851.                
  6852.                 m_vehicleObj, vehicleObjId = getplayervehicle(playerId)
  6853.                 movobjectcoords(m_vehicleObj and vehicleObjId or playerObjId, x, y, z+1)
  6854.                 cmdreply[cmdreply()] = getname(playerId) .. " was teleported to " .. location
  6855.                
  6856.                 ::continue::
  6857.             end
  6858.            
  6859.             sendresponse(cmdreply, executorPlayerId)
  6860.         end
  6861.     },
  6862.     {
  6863.         arguments = {"Player", "Number", "Number", "Number", minArgs = 4, maxArgs = 4},
  6864.         func = function(executorPlayerId, players, x, y, z)
  6865.             local playerId, m_playerObj, playerObjId, m_vehicleObj, vehicleObjId
  6866.             for i = 1,#players do playerId = players[i]
  6867.                
  6868.                 m_playerObj, playerObjId = getplayerobject(playerId)
  6869.                 if not m_playerObj then
  6870.                     cmdreply[cmdreply()] = "The players you are trying to teleport are dead"
  6871.                     goto continue
  6872.                 end
  6873.                
  6874.                 m_vehicleObj, vehicleObjId = getplayervehicle(playerId)
  6875.                 movobjectcoords(m_vehicleObj and vehicleObjId or playerObjId, x, y, z+1)
  6876.                 cmdreply[cmdreply()] = getname(playerId) .. " was teleported to " .. teletoname
  6877.                
  6878.                 ::continue::
  6879.             end
  6880.            
  6881.             sendresponse(cmdreply, executorPlayerId)
  6882.         end
  6883.     }
  6884. )
  6885.  
  6886. Commands.Create(
  6887.     "textban",
  6888.     {
  6889.         aliases = {"mute", "muteplayer", "textbanplayer", "textban", "tban", "chatban", "playermute"},
  6890.         help = [[-- Text Ban
  6891.         -- Syntax: %s [Player] {Time}]],
  6892.     },
  6893.     {
  6894.         arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3},
  6895.         func = function(executorPlayerId, players, time, reason)
  6896.  
  6897.             local exname = getname(executorPlayerId)
  6898.             local playerId, name, ip, hash, ban_entry, iptable
  6899.             for i = 1,#players do playerId = players[i]
  6900.                 name = getname(playerId)
  6901.                 ip = getip(playerId)
  6902.                 hash = gethash(playerId)
  6903.                 iptable = ip_table[ip]
  6904.                 if player_table[playerId].admin_entry then
  6905.                     sendresponse("Admins cannot be banned from the chat!", executorPlayerId)
  6906.                 else
  6907.                     if iptable.muted then
  6908.                         sendresponse(name .. " is already textbanned!", executorPlayerId)
  6909.                         goto continue
  6910.                     end
  6911.                     iptable.muted = true
  6912.                     addBan(name, hash, ip .. "/24", time, "chat", reason)
  6913.                     WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was text banned by " .. exname .. " Reason: " .. reason)
  6914.                     say(name .. " was text banned from the server by an admin! Reason: " .. reason)
  6915.                     sendresponse(time == -1 and (name .. " has been banned from the chat indefinitely") or (name .. " has been banned from the chat for " .. timetoword(time)), executorPlayerId)
  6916.                 end
  6917.                 ::continue::
  6918.             end
  6919.         end
  6920.     }
  6921. )
  6922.  
  6923. Commands.Create(
  6924.     "timecur",
  6925.     {
  6926.         aliases = {"curtime"},
  6927.         scrimBlock = true,
  6928.         help = [[-- Current Time
  6929.         -- Syntax: %s {Time}]]
  6930.     },
  6931.     {
  6932.         arguments = {"Time", minArgs = 0, maxArgs = 1},
  6933.         func = function(executorPlayerId, time)
  6934.             if time == -1 then
  6935.                 local time_passed = readdword(readdword(addresses.gameinfo_header) + 0xC) / 30
  6936.                 local timelimit = timelimit_set_value or (readdword(addresses.gametype_base + 0x78) / 30)
  6937.                 local time_left = timelimit - time_passed
  6938.                 sendresponse("Current Timelimit is " .. timetoword(timelimit) .. ". Time remaining: " .. timetoword(time_left), executorPlayerId)
  6939.             else
  6940.                 timelimit_set_value = time
  6941.                 writedword(readdword(addresses.gameinfo_header) + 0xC, 0) -- set time passed to 0
  6942.                 writedword(addresses.gametype_base + 0x78, readdword(readdword(addresses.gameinfo_header) + 0xC) + 30*time)
  6943.                 sendresponse("Timelimit set to " .. timetoword(time), executorPlayerId)
  6944.             end
  6945.         end
  6946.     }
  6947. )
  6948.  
  6949. Commands.Create(
  6950.     "unbos",
  6951.     {
  6952.         aliases = {"removebos", "bosremove", "unbanbos", "bosunban"},
  6953.         help = [[-- Remove from Ban on Sight List
  6954.         -- Syntax: %s [ID]
  6955.         -- Remove selected index off of the ban on sight list]]
  6956.     },
  6957.     {
  6958.         arguments = {"Positive Number", minArgs = 1, maxArgs = 1},
  6959.         func = function(executorPlayerId, ID)
  6960.             local entry = bos_table[ID]
  6961.             if not entry then
  6962.                 sendresponse("Invalid Entry", executorPlayerId)
  6963.             else
  6964.                 sendresponse("Removing " .. entry.name .. " - " .. entry.hash .. " from BoS.", executorPlayerId)
  6965.                 remove(bos_table, ID)
  6966.             end
  6967.         end
  6968.     }
  6969. )
  6970.  
  6971. Commands.Create(
  6972.     "ungod",
  6973.     {
  6974.         aliases = {"unsetgod", "removegod", "godunset", "godremove"},
  6975.         help = [[-- Ungod
  6976.         -- Syntax: %s [Player]
  6977.         -- Ungods the specified player.]]
  6978.     },
  6979.     {
  6980.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  6981.         func = function(executorPlayerId, players)
  6982.             local playerId, ptable
  6983.             for i = 1,#players do playerId = players[i]
  6984.                 local m_playerObj, playerObjId = getplayerobject(playerId)
  6985.                 if m_playerObj then
  6986.                     ptable = player_table[playerId]
  6987.                     if ptable.godmode then
  6988.                         ptable.godmode = nil
  6989.                         sendresponse(getname(playerId) .. " is no longer in godmode", executorPlayerId)
  6990.                     else
  6991.                         sendresponse(getname(playerId) .. " is not in godmode", executorPlayerId)
  6992.                     end
  6993.                 else
  6994.                     sendresponse("The selected playerId is dead", executorPlayerId)
  6995.                 end
  6996.             end
  6997.         end
  6998.     }
  6999. )
  7000.  
  7001. Commands.Create(
  7002.     "cheat_unhax",
  7003.     {
  7004.         aliases = {"unhax"},
  7005.         help = [[-- Cheat Unhax
  7006.         -- Syntax: %s [Player]
  7007.         -- Unhaxs the specified player.]]
  7008.     },
  7009.     {
  7010.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  7011.         func = function(executorPlayerId, players)
  7012.             local playerId
  7013.             for i = 1,#players do playerId = players[i]
  7014.                 local m_player = getplayer(playerId)
  7015.                 setscore(playerId, 0)
  7016.                 writeshort(m_player + 0x9C, 0)
  7017.                 writeshort(m_player + 0xA4, 0)
  7018.                 writeshort(m_player + 0xAC, 0)
  7019.                 writeshort(m_player + 0xAE, 0)
  7020.                 writeshort(m_player + 0xB0, 0)
  7021.                 sendresponse(getname(playerId) .. " has been unhaxed", executorPlayerId)
  7022.             end
  7023.         end
  7024.     }
  7025. )
  7026.  
  7027. Commands.Create(
  7028.     "unhide",
  7029.     {
  7030.         aliases = {"removehide"},
  7031.         help = [[-- Unhide
  7032.         -- Syntax: %s [Player]
  7033.         -- Unhides the specified player.]]
  7034.     },
  7035.     {
  7036.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  7037.         func = function(executorPlayerId, players)
  7038.    
  7039.             local playerId, ptable
  7040.             for i = 1,#players do playerId = players[i]
  7041.                 ptable = player_table[playerId]
  7042.                 if ptable.hidden then
  7043.                     sendresponse(getname(playerId) .. " is no longer hidden", executorPlayerId)
  7044.                     ptable.hidden = false
  7045.                 else
  7046.                     sendresponse(getname(playerId) .. " was never hidden", executorPlayerId)
  7047.                 end
  7048.             end
  7049.         end
  7050.     }
  7051. )
  7052.  
  7053. Commands.Create(
  7054.     "uninvis",
  7055.     {
  7056.         aliases = {"uncamo", "removeinvis", "removecamo"},
  7057.         help = [[-- Uninvis
  7058.         -- Syntax: %s [Player]
  7059.         -- Removes camouflage from the specified player.]]
  7060.     },
  7061.     {
  7062.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  7063.         func = function(executorPlayerId, players)
  7064.  
  7065.             local playerId, ptable
  7066.             for i = 1,#players do playerId = players[i]
  7067.                 ptable = player_table[playerId]
  7068.                 if not ptable.invisible then
  7069.                     sendresponse(getname(playerId) .. " is not invisible", executorPlayerId)
  7070.                 else
  7071.                     ptable.invisible = false
  7072.                     sendresponse(getname(playerId) .. " is no longer invisible", executorPlayerId)
  7073.                 end
  7074.             end
  7075.         end
  7076.     }
  7077. )
  7078.  
  7079. Commands.Create(
  7080.     "unmute",
  7081.     {
  7082.         aliases = {"removemute"},
  7083.         help = [[-- Unmute
  7084.         -- Syntax: %s [Player]
  7085.         -- Unmutes the specified player.
  7086.         -- Will also remove their chat ban from the banlist]]
  7087.     },
  7088.     {
  7089.         arguments = {"Player", minArgs = 1, maxArgs = 1},
  7090.         func = function(executorPlayerId, players)
  7091.             local playerId, ip, iptable, ban_entry, found
  7092.             for i = 1,#players do playerId = players[i]
  7093.                 ip = getip(playerId)
  7094.                 iptable = ip_table[ip]
  7095.                 if iptable.muted then
  7096.                     iptable.muted = nil
  7097.                     -- remove them from the textbanlist
  7098.                     for id = 1,#ban_table do ban_entry = ban_table[i]
  7099.                         if ban_entry.time ~= "Unbanned" and ban_entry.type == "chat" and netMatch(ban_entry.ip, ip) then
  7100.                             sendresponse(getname(playerId) .. " has been unmuted", executorPlayerId)
  7101.                             ban_table[id].time = "Unbanned"
  7102.                             updateBanFiles()
  7103.                             return
  7104.                         end
  7105.                     end
  7106.                    
  7107.                     if iptable.spamcounter < 0 then
  7108.                         sendresponse(getname(playerId) .. " has been forgiven for spamming.", executorPlayerId)
  7109.                         iptable.spamcounter = 0
  7110.                     else
  7111.                         sendresponse(getname(playerId) .. " is not found in any entries???", executorPlayerId)
  7112.                         iptable.muted = false
  7113.                     end
  7114.                 else
  7115.                     sendresponse(getname(playerId) .. " has not been muted.", executorPlayerId)
  7116.                 end
  7117.             end
  7118.         end
  7119.     }
  7120. )
  7121.  
  7122. Commands.Create(
  7123.     "viewadmins",
  7124.     {
  7125.         aliases = {"curadmins", "adminscur"},
  7126.         help = [[-- Viewadmins
  7127.         -- Syntax: %s
  7128.         -- Shows Current Admins in the Server]]
  7129.     },
  7130.     {
  7131.         arguments = {minArgs = 0, maxArgs = 0},
  7132.         func = function(executorPlayerId)
  7133.             sendresponse("The current admins in the server are listed below:", executorPlayerId)
  7134.             cmdreply.header = "[Level | Nickname | Name | Admin Type]"
  7135.             cmdreply.align = true
  7136.             cmdreply.delim = "|"
  7137.             local admin_entry
  7138.             for playerId = 0,15 do
  7139.                 admin_entry = player_table[playerId].admin_entry
  7140.                 if admin_entry then
  7141.                     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"))
  7142.                 end
  7143.             end
  7144.             sendresponse(cmdreply, executorPlayerId)
  7145.         end
  7146.     }
  7147. )
  7148.  
  7149. Commands.Create(
  7150.     "votekick_action",
  7151.     {
  7152.         aliases = {"votekickaction"},
  7153.         help = [[-- Vote Kick Action
  7154.         -- Syntax: %s [Kick/Ban]
  7155.         -- Allows you to either ban or kick the player that has been voted out.]]
  7156.     },
  7157.     {
  7158.         arguments = {"String", minArgs = 0, maxArgs = 1},
  7159.         func = function(executorPlayerId, action)
  7160.             if not action then
  7161.                 sendresponse("The current action for people who are votekicked is '" .. defaults.votekick_action .. "'", executorPlayerId)
  7162.                 sendresponse("Valid actions are 'kick' and 'ban'", executorPlayerId)
  7163.             else
  7164.                 sendresponse("The current VoteKick action has been changed to '" .. action .. "'", executorPlayerId)
  7165.                 defaults.votekick_action = action
  7166.             end
  7167.         end
  7168.     }
  7169. )
  7170.  
  7171. Commands.Create(
  7172.     "votekick_timeout",
  7173.     {
  7174.         help = [[-- VoteKick Timeout
  7175.         -- Syntax: %s [Time]
  7176.         -- The amount of time between each votekick.]]
  7177.     },
  7178.     {
  7179.         arguments = {"Time", minArgs = 0, maxArgs = 1},
  7180.         func = function(executorPlayerId, time)
  7181.             if time == -1 then
  7182.                 sendresponse("VoteKick Timeout is currently " .. timetoword(defaults.votekick_timeout), executorPlayerId)
  7183.             else
  7184.                 sendresponse("VoteKick Timeout has been set to " .. timetoword(time), executorPlayerId)
  7185.                 defaults.votekick_timeout = time
  7186.             end
  7187.         end
  7188.     }
  7189. )
  7190.  
  7191. Commands.Create(
  7192.     "votekick_required",
  7193.     {
  7194.         aliases = {"votekickneeded"},
  7195.         help = [[-- Vote Kick Needed
  7196.         -- Syntax: %s [Percent]
  7197.         -- Allow you to change the number of votes needed for VoteKick to kick the player.]]
  7198.     },
  7199.     {
  7200.         arguments = {"Percent", minArgs = 0, maxArgs = 1},
  7201.         func = function(executorPlayerId, percent)
  7202.             if not percent then
  7203.                 sendresponse(defaults.votekick_required .. "% votes required for VoteKick", executorPlayerId)
  7204.             else
  7205.                 sendresponse("Votes required for VoteKick has been set to " .. percent .. "%", executorPlayerId)
  7206.                 defaults.votekick_required = percent
  7207.             end
  7208.         end
  7209.     }
  7210. )
  7211.  
  7212. function GetRequiredVersion()
  7213.     return 200
  7214. end
  7215.  
  7216. function OnScriptLoad(process, game, persistent)
  7217.     processid = process
  7218.     Persistent = persistent
  7219.     profilepath = getprofilepath()
  7220.     Game = game
  7221.     GetGameAddresses(game)
  7222.     writeword(addresses.special_chars_patch, 0x9090)
  7223.     writeword(addresses.gametype_patch, 0xEB)
  7224.     writeword(addresses.devmode_patch1, 0x9090)
  7225.     writeword(addresses.devmode_patch2, 0x9090)
  7226.     writebyte(addresses.color_patch, 0xEB)
  7227.     gametype = readbyte(addresses.gametype_base + 0x30)
  7228.     team_play = readbyte(addresses.gametype_base + 0x34) == 1
  7229.    
  7230.     -- This bit of code fixes the stupidness that is sv_public.
  7231.     -- Usually if sv_public is disabled, no one can join the server (or weird things start happening)
  7232.     -- This bit of code will fix that.
  7233.     --[[local public_status = readdword(addresses.public_value_address) == 0x10101
  7234.     if not public_status then
  7235.         writedword(addresses.public_value_address, 0x101)
  7236.         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)
  7237.     end--]]
  7238.  
  7239.     local file = io.open("changelog_" .. script_version .. ".txt")
  7240.     if file then
  7241.         changelog = true
  7242.         file:close()
  7243.     else
  7244.         WriteChangeLog()
  7245.     end
  7246.  
  7247.     file = io.open("temp_" .. process .. ".tmp")
  7248.     if not file then
  7249.         file = io.open "defaults.txt"
  7250.     end
  7251.  
  7252.     local temp_commands_executed = TM.New()
  7253.     local words
  7254.    
  7255.     registertimer(0, "turnAdminCheckOff")
  7256.    
  7257.     -- 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)
  7258.     -- No bans will be deleted, anything in banned.txt will be formatted exactly the same as it was before.
  7259.     writedword(addresses.banlist_header, 0) -- writing the number of bans to 0 seems to remove all bans, sweet
  7260.    
  7261.     local gameinfo_base = readdword(addresses.gameinfo_header)
  7262.     -- if game_info_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)
  7263.     if gameinfo_base and file then
  7264.         for line in file:lines() do
  7265.             if match(line, "[%w_]+%s+[%w%p]+") then
  7266.                 -- used to call svcmd but I hate it using halo's servercommand call
  7267.                 -- no need when I only want it to execute scripted commands anyway.
  7268.                 OnServerCommand(nil, line)
  7269.             end
  7270.             words = tokenizecmdstring(line)
  7271.             temp_commands_executed[#temp_commands_executed+1] = words[1]
  7272.         end
  7273.         file:close()
  7274.         if filename == "temp_" .. processid .. ".tmp" then
  7275.             os.remove(filename)
  7276.         end
  7277.     elseif file then
  7278.         file:close()
  7279.     else
  7280.         file = io.open("defaults.txt", "a")
  7281.         hprintf "       >> Defaults.txt not found. File will be created..."
  7282.         local command
  7283.         for command,value in next,defaults do
  7284.             file:write("sv_" .. command .. " " .. tostring(value) .. "\n")
  7285.         end
  7286.         file:close()
  7287.     end
  7288.    
  7289.     hprintf "-------------------------------------------------------------------------------"
  7290.     hprintf("   >> Command Script Version: " .. script_version .. " <<")
  7291.     if not changelog then
  7292.     hprintf("   >> [!] Change log Version " .. script_version .. " is being written [!] <<")
  7293.     end
  7294.     hprintf "   >> Credit: Creator Wizard, Updater Aelite_Prime <<"
  7295.     hprintf "   >> Xfire: th3w1zard3 <<"
  7296.     hprintf "   >> Support: http://phasor.proboards.com/ <<"
  7297.     hprintf "-------------------------------------------------------------------------------"
  7298.     maintimer = registertimer(33, "MainTimer")
  7299.    
  7300.     file = io.open(defaults.sharedhash_file .. ".txt")
  7301.     if file then
  7302.         sharedhashes = TM.deleteEntries(sharedhashes)
  7303.         local iter = 0
  7304.         for line in file:lines() do
  7305.             iter = iter + 1
  7306.             sharedhashes[iter] = line
  7307.         end
  7308.     else
  7309.         file = io.open(defaults.sharedhash_file .. ".txt", "w")
  7310.         if file then
  7311.             file:write(concat(sharedhashes, "\n"))
  7312.         end
  7313.     end
  7314.  
  7315.     loadBanFile(profilepath .. "ipbans.txt", "ip") -- load sapp ip bans
  7316.     loadBanFile(profilepath .. "ipbanlist.txt", "ip") -- load ipbanlist file for backwards compatibility
  7317.     loadBanFile(profilepath .. "iprangebanlist.txt", "ip") -- load iprangebanlist file for backwards compatibility
  7318.     loadBanFile(profilepath .. "textbanlist.txt", "chat") -- load textbanlist file for backwards compatibility
  7319.     loadBanFile(profilepath .. "namebans.txt", "name") -- load textbanlist file for backwards compatibility
  7320.    
  7321.     loadBanFile(profilepath .. defaults.banlist_file .. ".txt")
  7322.  
  7323.     updateBanFiles()
  7324.    
  7325.     -- we're not going to remove the files, let's just rename them so we don't upset anyone.
  7326.     local timestamp = os.date "%Y_%m_%d_%H_%M_%S"
  7327.     os.rename(profilepath .. "ipbans.txt", profilepath .. "old_ipbans_" .. timestamp .. ".txt")
  7328.     os.rename(profilepath .. "ipbanlist.txt", profilepath .. "old_ipbanlist_" .. timestamp .. ".txt")
  7329.     os.rename(profilepath .. "iprangebanlist.txt", profilepath .. "old_iprangebanlist_" .. timestamp .. ".txt")
  7330.     os.rename(profilepath .. "textbanlist.txt", profilepath .. "old_textbanlist_" .. timestamp .. ".txt")
  7331.     os.rename(profilepath .. "namebans.txt", profilepath .. "old_namebans_" .. timestamp .. ".txt")
  7332.    
  7333.     -- Check if a banned player is in the server.
  7334.     local hash, ip
  7335.     for playerId = 0,15 do
  7336.         if getplayer(playerId) then
  7337.             hash, ip = gethash(playerId), getip(playerId)
  7338.             for i = 1,#ban_table do
  7339.                 if ban_entry.time ~= "Unbanned" and ban_table.type == "hash" and hash == ban_table.hash or ban_table.type == "ip" and ban_table.ip == ip then
  7340.                     registertimer(0, "tempBanPlayer", resolveplayer(playerId))
  7341.                 end
  7342.             end
  7343.         end
  7344.     end
  7345.  
  7346.     loadAllAdminFiles()
  7347.    
  7348.     -- We can now archive the other admin files without worrying about losing the data.
  7349.     os.rename(profilepath .. "ipadmins.txt", profilepath .. "archived_ipadmins.txt")
  7350.     os.rename(profilepath .. "admin.txt", profilepath .. "archived_admin.txt")
  7351.     file = io.open(profilepath .. "access.ini")
  7352.     if file then
  7353.         local commands, lvlMatch, level, thisCommand
  7354.         local iter = 0
  7355.         for line in file:lines() do
  7356.             -- ignore blank lines
  7357.             if match(line, "%g%g%g+") then
  7358.                 lvlMatch = tonumber(match(line, "%[([0-9]+)%]"))
  7359.                 commands = match(line, "data=(.+)")
  7360.                 if iter % 2 == 0 and lvlMatch then
  7361.                     level = lvlMatch
  7362.                 elseif iter % 2 ~= 0 and commands then
  7363.                     if commands == "-1" then
  7364.                         access_table[level] = -1
  7365.                     else
  7366.                         -- String full of commands this access level can execute.
  7367.                         access_table[level] = TM{commands = commands}
  7368.                        
  7369.                         -- We want to set each access_table[level][command] to equal the actual true name of the command (e.g. Display Admins List).
  7370.                         -- Doing this will allow command aliases like sv_rcon_add, /rcon_add, add_rcon etc to work without using AccessMerging anymore (yuck)
  7371.                         commands = tokenizestring(commands, ",")
  7372.                         for i = 1,#commands do
  7373.                             thisCommand = Commands[getvalidformat(commands[i])]
  7374.                             if thisCommand then
  7375.                                 access_table[level][thisCommand] = true
  7376.                             end
  7377.                         end
  7378.                     end
  7379.                 else
  7380.                     error(profilepath .. "access.ini is formatted incorrectly! Line: " .. line)
  7381.                 end
  7382.                 iter = iter + 1
  7383.             end
  7384.         end
  7385.         file:close()
  7386.     end
  7387.    
  7388.     file = io.open(profilepath .. "data\\bos.data")
  7389.     if file then
  7390.         local name, hash, ip
  7391.         for line in file:lines() do
  7392.             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+)$")
  7393.             ip = validate_ipv4(ip)
  7394.             bos_table[#bos_table+1] = TM{name = name, hash = hash, ip = ip}
  7395.         end
  7396.         file:close()
  7397.     end
  7398.    
  7399.     file = io.open(profilepath .. "data\\locations.txt")
  7400.     if file then
  7401.         local map, locname, x, y, z
  7402.         for line in file:lines() do
  7403.             map,locname,x,y,z = match(line, "^(%g+),(%g+),([%d%.%-]+),([%d%.%-]+),([%d%.%-]+)")
  7404.             x,y,z = tonumber(x), tonumber(y), tonumber(z)
  7405.             if locname and x and y and z then
  7406.                 locations[map] = locations[map] or TM{}
  7407.                 locations[map][locname] = TM{x, y, z}
  7408.             end
  7409.         end
  7410.         file:close()
  7411.     end
  7412.    
  7413.     -- Code for script reload.
  7414.     local gameinfo_base = readdword(addresses.gameinfo_header)
  7415.    
  7416.     -- If this script loads as a persistent script (in the persistent folder) this will sometimes be nil/0.
  7417.     if gameinfo_base and gameinfo_base ~= 0 then
  7418.         local gameinfo_time_passed = readdword(gameinfo_base + 0xC)
  7419.        
  7420.         -- Seems to not work when starting at 0.
  7421.         if gameinfo_time_passed >= 30 then
  7422.             gameend = false
  7423.             Map = readstring(addresses.map_name_address2)
  7424.             locations[Map] = locations[Map] or TM{}
  7425.             team_play = readbyte(addresses.gametype_base + 0x34) == 1
  7426.             LoadTags()
  7427.             local m_player, iptable
  7428.             for playerId = 0,15 do
  7429.                 m_player = _G.getplayer(playerId)
  7430.                 if m_player then
  7431.                     cur_players = cur_players + 1
  7432.                     -- Add player in the script's tables.
  7433.                     player_table(playerId)
  7434.                     iptable = ip_table(_G.getip(playerId), true)
  7435.                 end
  7436.             end
  7437.         end
  7438.     end
  7439.     collectgarbage()
  7440. end
  7441.  
  7442. function turnAdminCheckOff(id, count)
  7443.     halo_svcmd "sv_admin_check false" -- stupid phasor :(
  7444.    
  7445.     -- Load Maplist and Gamelist.
  7446.     --[[local gmatch = string.gmatch
  7447.     for gametype in gmatch(concat(halo_svcmd("sv_maplist", true)), "%w+") do
  7448.         valid_maps[gametype] = true
  7449.     end
  7450.     for gametype in gmatch(concat(halo_svcmd("sv_gamelist", true)), "%w+") do
  7451.         valid_gametypes[gametype] = true
  7452.     end--]]
  7453.    
  7454.     return false
  7455. end
  7456.  
  7457. function OnScriptUnload()
  7458.     local writetbl = TM.New()
  7459.    
  7460.     local file = io.open(profilepath .. "data\\bos.data", "w")
  7461.     local bos_entry
  7462.     for id = 1,#bos_table do bos_entry = bos_table[id]
  7463.         writetbl[#writetbl+1] = bos_entry.name .. "," .. bos_entry.hash .. "," .. bos_entry.ip
  7464.     end
  7465.     file:write(concat(writetbl, "\n"))
  7466.     file:close()
  7467.    
  7468.     file = io.open(profilepath .. "data\\locations.txt", "w")
  7469.     local start = #writetbl+1
  7470.     for map,mapLocations in next,locations do
  7471.         for locname,thisLocation in next,mapLocations do
  7472.             writetbl[#writetbl+1] = map .. "," .. locname .. "," .. thisLocation[1] .. "," .. thisLocation[2] .. "," .. thisLocation[3]
  7473.         end
  7474.     end
  7475.     file:write(concat(writetbl, "\n", start))
  7476.     file:close()
  7477.    
  7478.     -- Continue to write these onscriptunload because they aren't as important as admins/bans and they're written to a lot more.
  7479.     file = io.open(profilepath .. "uniques.txt", "w")
  7480.     start = #writetbl+1
  7481.     for k,unique_entry in next,unique_table do
  7482.         if k ~= "total" then
  7483.             writetbl[#writetbl+1] = k .. "," .. unique_entry.joincount .. "," .. concat(unique_entry.names, ",")
  7484.         end
  7485.     end
  7486.     writetbl[#writetbl+1] = unique_table.total
  7487.     file:write(concat(writetbl, "\n", start))
  7488.     file:close()
  7489.  
  7490.     -- Write all script game variables to temp file
  7491.     file = io.open("temp_" .. processid .. ".tmp", "w")
  7492.     start = #writetbl+1
  7493.     for command,value in next,defaults do
  7494.         writetbl[#writetbl+1] = command .. " " .. tostring(value)
  7495.     end
  7496.    
  7497.     for rcon,level in next,rcon_passwords do
  7498.         writetbl[#writetbl+1] = "sv_rcon_add " .. rcon .. " " .. level
  7499.     end
  7500.     file:write(concat(writetbl, "\n", start))
  7501.     file:close()
  7502.    
  7503.     -- Clean up drones.
  7504.     for i = 0,15 do
  7505.         if getplayer(i) then
  7506.             cleanupdrones(i)
  7507.         end
  7508.     end
  7509. end
  7510.  
  7511. local isMuted
  7512. function OnBanCheck(hash, ip)
  7513.      -- 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.
  7514.     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
  7515.  
  7516.     local bos_entry
  7517.     for i = 1,#bos_table do bos_entry = bos_table[i]
  7518.         if bos_entry.ip == ip then
  7519.             for i = 0,15 do
  7520.                 if player_table[i].admin_entry then
  7521.                     sendconsoletext(i, bos_entry.name .. " banned from BoS.\nEntry: " .. bos_entry.name .. "- " .. bos_entry.ip)
  7522.                 end
  7523.             end
  7524.             hprintf(bos_entry.name .. " banned from BoS.\nEntry: " .. bos_entry.name .. "- " .. bos_entry.ip)
  7525.             WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", bos_entry.name .. " was Banned on Sight")
  7526.             addBan(bos_entry.name, nil, ip, nil, "ip", "Ban on Sight")
  7527.             return false
  7528.         end
  7529.     end
  7530.    
  7531.     local bReturn
  7532.  
  7533.     local ban_entry
  7534.     for id = 1,#ban_table do ban_entry = ban_table[id]
  7535.         if ban_entry.time ~= "Unbanned" then
  7536.             if ban_entry.type == "ip" then
  7537.                 if netMatch(ban_entry.ip, ip) then
  7538.                     if ban_entry.time == -1 or ban_entry.time > os.time() then
  7539.                         bReturn = false
  7540.                         break
  7541.                     end
  7542.                 end
  7543.             elseif ban_entry.type == "hash" and hash == ban_entry.hash then
  7544.                 bReturn = false
  7545.                 break
  7546.             elseif ban_entry.type == "chat" and (ban_entry.hash == hash or ban_entry.ip == ip) then
  7547.                 isMuted = true
  7548.             end
  7549.         end
  7550.     end
  7551.     return bReturn
  7552. end
  7553.  
  7554. function OnNameRequest(hash, name)
  7555.     hprintf(name .. " (" .. hash .. ") is attempting to join the server")
  7556.    
  7557.     local ban_entry
  7558.     for id = 1,#ban_table do ban_entry = ban_table[id]
  7559.         if ban_entry.time ~= "Unbanned" and ban_entry.type == "name" then
  7560.             if ban_entry.name == name then
  7561.                 return false, "NameBanned"
  7562.             end
  7563.         end
  7564.     end
  7565.    
  7566.     return nil
  7567. end
  7568.  
  7569. function OnPlayerJoin(playerId)
  7570.  
  7571.     local ptable = player_table(playerId)
  7572.     local ip = getip(playerId)
  7573.     local iptable = ip_table[ip] or ip_table(ip)
  7574.    
  7575.     -- write the team colors to the player (required since we are using the color patch)
  7576.     if team_play then
  7577.         writeword(getplayer(playerId) + 0x60, getteam(playerId)+2)
  7578.     end
  7579.    
  7580.     cur_players = cur_players + 1
  7581.     local name = getname(playerId)
  7582.     local hash = gethash(playerId)
  7583.    
  7584.     local iprange = match(ip, "^%d+%.%d+%.%d+")
  7585.    
  7586.     iptable.muted = iptable.muted or isMuted or false
  7587.     isMuted = nil
  7588.    
  7589.     if iptable.suspended then
  7590.         kill(playerId)
  7591.         writeword(getplayer(playerId) + 0x2C, tonumber(iptable.suspended) or 3000)
  7592.     end
  7593.  
  7594.     if defaults.uniques_enabled then
  7595.         if unique_table[hash] or unique_table[ip] or unique_table[iprange] then
  7596.             if defaults.wb_message then
  7597.                 privatesay(playerId, "Welcome back " .. name .. "")
  7598.             end
  7599.             unique_table[hash] = unique_table[hash] or TM.New()
  7600.             unique_table[hash].joincount = (unique_table[hash].joincount or 0) + 1
  7601.             unique_table[ip] = unique_table[ip] or TM.New()
  7602.             unique_table[ip].joincount = (unique_table[ip].joincount or 0) + 1
  7603.             unique_table[iprange] = unique_table[iprange] or TM.New()
  7604.             unique_table[iprange].joincount = (unique_table[iprange].joincount or 0) + 1
  7605.         else
  7606.             unique_table[hash] = TM{joincount = 1, names = TM{name}}
  7607.             unique_table[ip] = TM{joincount = 1, names = TM{name}}
  7608.             unique_table[iprange] = TM{joincount = 1, names = TM{name}}
  7609.             unique_table.total = unique_table.total + 1
  7610.             if defaults.firstjoin_message then
  7611.                 say("This is " .. name .. "'s first time in the server unique player #: " .. unique_table.total)
  7612.             end
  7613.         end
  7614.     end
  7615.     if defaults.sa_message then
  7616.         if player_table[playerId].admin_entry then
  7617.             hprintf("Server Admin: " .. name)
  7618.             Say("Server Admin: " .. name)
  7619.         end
  7620.     end
  7621.     if defaults.multiteam_vehicles then
  7622.         writebyte(getplayer(playerId) + 0x20, 0)
  7623.     end
  7624.     hprintf(name .. " has joined the game")
  7625. end
  7626.  
  7627. function OnPlayerLeave(playerId)
  7628.     cleanupdrones(playerId)
  7629.     cur_players = cur_players - 1
  7630.     local name = getname(playerId)
  7631.     local ip = getip(playerId)
  7632.     local iptable = ip_table[ip]
  7633.     if not gameend and iptable.tempadmin then
  7634.         iptable.tempadmin = false
  7635.     end
  7636.     if votekickPlayerId == playerId then
  7637.         votekicktimer = nil
  7638.         votekickPlayerId = nil
  7639.         votekick_counter = -defaults.votekick_timeout
  7640.         for i = 0,15 do
  7641.             if getplayer(i) then
  7642.                 ip_table[getip(i)].used_votekick = false
  7643.             end
  7644.         end
  7645.         say "Votekick ending because votekicked player left the server!"
  7646.     end
  7647.     ResetPlayer(playerId)
  7648.     local left_entry = TM.New()
  7649.     left_entry.name = name
  7650.     left_entry.hash = gethash(playerId)
  7651.     left_entry.ip = ip
  7652.     leave_table[resolveplayer(playerId)] = left_entry
  7653.     hprintf(name .. " is leaving the game")
  7654.     player_table[playerId].player_struct = nil
  7655.     player_table[playerId].objectId = 0xFFFFFFFF
  7656.     player_table[playerId].object_struct = nil
  7657.     player_table[playerId].m_vehicleObj = nil
  7658.     player_table[playerId].vehicleObjId = 0xFFFFFFFF
  7659. end
  7660.  
  7661. function OnTeamChange(playerId, old_team, new_team, relevant)
  7662.     if team_play then
  7663.         writeword(getplayer(playerId) + 0x60, new_team+2)
  7664.     end
  7665. end
  7666.  
  7667. function OnPlayerSpawn(playerId)
  7668.     local ip = getip(playerId)
  7669.  
  7670.     local ptable = player_table[playerId]
  7671.     ptable.objectId = readdword(ptable.player_struct + 0x34)
  7672.     ptable.object_struct = getobject(ptable.objectId)
  7673.     local iptable = ip_table[ip]
  7674.     if defaults.noweapons or iptable.disarmed then
  7675.         local m_weapon, weaponObjId
  7676.         for slot = 1,4 do
  7677.             m_weapon, weaponObjId = getplayerweapon(playerId, slot)
  7678.             if m_weapon then
  7679.                 destroyobject(weaponObjId)
  7680.             end
  7681.         end
  7682.     end
  7683.    
  7684.     if defaults.multiteam_vehicles then
  7685.         writebyte(ptable.player_struct + 0x20, 0)
  7686.     end
  7687.  
  7688.     if ptable.colorspawn then
  7689.         movobjectcoords(ptable.objectId, ptable.x, ptable.y, ptable.z)
  7690.         ptable.colorspawn = false
  7691.     end
  7692.     if iptable.suspended then iptable.suspended = false end
  7693.     if ptable.ghostmode then ptable.ghostmode = false end
  7694.     --writebit(m_playerObj + 0x10, 0, 1) -- both for ghostmode
  7695.     --writebit(m_playerObj + 0x10, 24, 0)
  7696. end
  7697.  
  7698. -- screw you phasor
  7699. local mode = 1
  7700. function OnNewGame(map)
  7701.     if Persistent then
  7702.         rtv_counter = 0
  7703.         for _,entry in next,ip_table do
  7704.             entry.rtv_rocked = false
  7705.         end
  7706.     end
  7707.     Map = map
  7708.     locations[map] = locations[map] or TM{}
  7709.     gameend = false
  7710.     team_play = readbyte(addresses.gametype_base + 0x34) == 1
  7711.     LoadTags()
  7712.     mode = 1
  7713.    
  7714.     -- reset cache on memoized functions.
  7715.     getObjType = memoize(getObjType) -- memoized
  7716.     tobinary = memoize(tobinary) -- memoized
  7717.     --tokenizestring = memoize(tokenizestring) -- memoized
  7718.     --tokenizecmdstring = memoize(tokenizecmdstring) -- memoized
  7719.     trim = memoize(trim) -- memoized
  7720.     capitalizeWords = memoize(capitalizeWords) -- memoized
  7721.     --formatOutput = memoize(formatOutput) -- memoized
  7722.     wildstring = memoize(wildstring) -- memoized
  7723.     getvalidformat = memoize(getvalidformat) -- memoized
  7724.     netMatch = memoize(netMatch) -- memoized
  7725.     long2ip = memoize(long2ip) -- memoized
  7726.     convertSign = memoize(convertSign) -- memoized
  7727.     ip2long = memoize(ip2long) -- memoized
  7728.     check_ip = memoize(check_ip) -- memoized
  7729.     validate_ipv4 = memoize(validate_ipv4) -- memoized
  7730.     getTimeAndReason = memoize(getTimeAndReason) -- memoized
  7731.     timetoword = memoize(timetoword) -- memoized
  7732.     wordtotime = memoize(wordtotime) -- memoized
  7733.     formatTime = memoize(formatTime) -- memoized
  7734.     objectidtoplayer = memoize(objectidtoplayer) -- memoized
  7735.    
  7736.     collectgarbage()
  7737. end
  7738.  
  7739.  
  7740. function OnGameEnd(mode_that_sometimes_lies)
  7741.     if mode == 1 then
  7742.         gameend = true
  7743.         for i = 0,15 do
  7744.             cleanupdrones(i)
  7745.         end
  7746.         collectgarbage()
  7747.     end
  7748.     mode = mode + 1
  7749. end
  7750.  
  7751. local function votekick()
  7752.     say("Removing " .. getname(votekickPlayerId) .. " from the server")
  7753.     if defaults.votekick_action == "ban" then
  7754.         svcmd("sv_ban " .. resolveplayer(votekickPlayerId) .. " 5m Votekicked with " .. votekick_counter .. " number of votes")
  7755.     else
  7756.         svcmd("sv_kick " .. resolveplayer(votekickPlayerId) .. " Votekicked with " .. votekick_counter .. " number of votes")
  7757.     end
  7758.     votekickPlayerId = nil
  7759.     if votekicktimer then
  7760.         removetimer(votekicktimer)
  7761.         votekicktimer = nil
  7762.     end
  7763.     votekick_counter = -defaults.votekick_timeout
  7764. end
  7765.  
  7766. function OnServerChat(playerId, chattype, message)
  7767.     local AllowChat, found, receiverPlayer
  7768.     if chattype == 4 then
  7769.         -- don't do anything if the server is private messaging someone.
  7770.         hprintf(gsub(message, "**SERVER**", "\n**SERVER TO " .. (playerId and getname(playerId)) .. "**"))
  7771.         if server_prefix then
  7772.             return true, gsub(message, "**SERVER**", server_prefix)
  7773.         end
  7774.         return nil
  7775.     elseif not playerId then
  7776.         -- do nothing here if the server is globally talking to everyone.
  7777.         hprintf("\n" .. message)
  7778.         if server_prefix then
  7779.             return true, gsub(message, "**SERVER**", server_prefix)
  7780.         end
  7781.         return nil
  7782.     end
  7783.    
  7784.     local name, hash, ip = getname(playerId), gethash(playerId), getip(playerId)
  7785.    
  7786.     local ptable = player_table[playerId]
  7787.     local iptable = ip_table[ip]
  7788.    
  7789.     if iptable.muted or iptable.spamcounter < 0 then
  7790.         return false
  7791.     end
  7792.     local t = tokenizestring(message, " ")
  7793.     local count = #t
  7794.     local cmd = t[1]
  7795.    
  7796.     if cmd == "rtv" or cmd == "skip" then
  7797.         if count ~= 1 then
  7798.             goto endchat
  7799.         end
  7800.        
  7801.         AllowChat = false
  7802.        
  7803.         if not defaults.rtv_enabled then
  7804.             privatesay(playerId, "Rockthevote is disabled.")
  7805.             goto endchat
  7806.         end
  7807.        
  7808.         if rtv_counter < 0 then
  7809.             privatesay(playerId, "You cannot initiate rtv at this time")
  7810.             goto endchat
  7811.         end
  7812.  
  7813.         local total_votes_required = round(cur_players * defaults.rtv_required * 0.01)
  7814.        
  7815.         if iptable.rtv_rocked then
  7816.             privatesay(playerId, "You have already voted for rtv")
  7817.             goto endchat
  7818.         end
  7819.        
  7820.         rtv_counter = rtv_counter + 1
  7821.         if rtv_counter == 1 then
  7822.             say(name .. " has initiated rtv")
  7823.             say('Type "rtv" to join the vote')
  7824.             rtvtimer = registertimer(defaults.rtv_timeout * 1000, "rtvTimer")
  7825.         else
  7826.             say(name .. " has voted for rtv")
  7827.             say(rtv_counter .. " of " .. total_votes_required .. " votes required for rtv")
  7828.         end
  7829.        
  7830.         iptable.rtv_rocked = true
  7831.         if rtv_counter >= total_votes_required then
  7832.             if rtvtimer then
  7833.                 removetimer(rtvtimer)
  7834.                 rtvtimer = nil
  7835.             end
  7836.             rtv_counter = -defaults.rtv_timeout
  7837.             say("Enough votes for rtv, game is now ending...")
  7838.             halo_svcmd "sv_map_next"
  7839.         end
  7840.     elseif cmd == "votekick" then
  7841.         if count ~= 2 then
  7842.             goto endchat
  7843.         end
  7844.        
  7845.         AllowChat = false
  7846.        
  7847.         if not defaults.votekick_enabled then
  7848.             privatesay(playerId, "Votekick is disabled")
  7849.             goto endchat
  7850.         end
  7851.        
  7852.         if iptable.used_votekick then
  7853.             privatesay(playerId, "You have already voted for a votekick!")
  7854.             goto endchat
  7855.         end
  7856.        
  7857.         if votekick_counter < 0 then
  7858.             privatesay(playerId, "Votekick will be available in " .. -votekick_counter .. " seconds")
  7859.             goto endchat
  7860.         elseif votekick_counter > 0 then
  7861.             privatesay(playerId, "There is already a votekick in progress.")
  7862.             goto endchat
  7863.         end
  7864.        
  7865.         local players = getvalidplayers(t[2])
  7866.         if not players then
  7867.             privatesay(playerId, "Invalid Player!")
  7868.             goto endchat
  7869.         end
  7870.  
  7871.         if players[2] then
  7872.             privatesay(playerId, "You can only votekick one player at a time!")
  7873.             goto endchat
  7874.         end
  7875.  
  7876.         receiverPlayer = players[1]
  7877.         if playerId == receiverPlayer then
  7878.             privatesay(playerId, "You cannot votekick yourself noob.")
  7879.             goto endchat
  7880.         end
  7881.        
  7882.         if player_table[receiverPlayer].admin_entry then
  7883.             privatesay(playerId, "Admins cannot be votekicked")
  7884.             goto endchat
  7885.         end
  7886.        
  7887.         local total_votes_required = round(cur_players*(defaults.votekick_required*0.01))
  7888.         votekickPlayerId = receiverPlayer
  7889.         iptable.used_votekick = true
  7890.         votekick_counter = votekick_counter + 1
  7891.         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')
  7892.  
  7893.         if votekick_counter >= total_votes_required then
  7894.             votekick()
  7895.         end
  7896.     elseif cmd == "kick" then
  7897.         if count ~= 1 then
  7898.             goto endchat
  7899.         end
  7900.        
  7901.         AllowChat = false
  7902.        
  7903.         if not defaults.votekick_enabled then
  7904.             privatesay(playerId, "Votekick is disabled")
  7905.             goto endchat
  7906.         end
  7907.        
  7908.         if iptable.used_votekick then
  7909.             privatesay(playerId, "You have already voted for a votekick!")
  7910.             goto endchat
  7911.         end
  7912.        
  7913.         if votekick_counter <= 0 then
  7914.             privatesay(playerId, "There is no votekick in progress. Use 'votekick (playerIndex)' to start one!")
  7915.             goto endchat
  7916.         end
  7917.        
  7918.         if playerId == votekickPlayerId then
  7919.             privatesay(playerId, "You cannot vote for yourself to be kicked noob")
  7920.             goto endchat
  7921.         end
  7922.  
  7923.         local total_votes_required = round(cur_players*(defaults.votekick_required*0.01))
  7924.  
  7925.         iptable.used_votekick = true
  7926.         votekick_counter = votekick_counter + 1
  7927.         say(name .. " has voted to kick " .. getname(votekickPlayerId))
  7928.         say(votekick_counter .. " of " .. total_votes_required .. " votes required to kick")
  7929.  
  7930.         if votekick_counter >= total_votes_required then
  7931.             votekick()
  7932.         end
  7933.     end
  7934.     receiverPlayer = match(cmd, "^@(%g+)$")
  7935.     if defaults.pm_enabled and receiverPlayer then
  7936.        
  7937.         AllowChat = false
  7938.        
  7939.         local players = getvalidplayers(receiverPlayer, playerId)
  7940.         if not players then
  7941.             privatesay(playerId, "There is no player identified as '" .. receiverPlayer .. "'")
  7942.             goto endchat
  7943.         end
  7944.        
  7945.         if #players > 4 then
  7946.             privatesay(playerId, "You cannot privatemessage more than 4 people at once!")
  7947.             goto endchat
  7948.         end
  7949.        
  7950.         local privatemessage = concat(t, " ", 2, #t)
  7951.         local names = TM.New()
  7952.        
  7953.         for i = 1,#players do receiverPlayer = players[i]
  7954.             if playerId == receiverPlayer then
  7955.                 goto nextPlayer
  7956.             end
  7957.             names[i] = getname(receiverPlayer) .. " (" .. resolveplayer(receiverPlayer) .. ")"
  7958.             sendconsoletext(receiverPlayer, getname(playerId) .. ": (" .. resolveplayer(playerId) .. ") " .. privatemessage)
  7959.             ::nextPlayer::
  7960.         end
  7961.         sendconsoletext(playerId, "PM to " .. concat(names, ", ") .. " " .. privatemessage)
  7962.     end
  7963.    
  7964.     if sub(cmd, 1, 1) == "/" then
  7965.         output_environment = 2
  7966.         found = true
  7967.         AllowChat = true
  7968.     elseif sub(cmd, 1, 1) == "\\" then
  7969.         output_environment = 3
  7970.         found = true
  7971.         AllowChat = false
  7972.     end
  7973.    
  7974.     if found then
  7975.         if defaults.chatcommands then
  7976.             if cmd == "/e" then
  7977.                 cmd = concat(t, " ", 2)
  7978.                 sendresponse("Executed " .. cmd, playerId)
  7979.                 sendresponse(svcmdplayer(cmd, playerId, true), playerId)
  7980.             --[[elseif cmd == "/l" or cmd == "/login" then
  7981.                 remove(t, 1) -- command is not an argument
  7982.                 Commands[cmd](t, cmd, playerId)--]]
  7983.             else
  7984.                 sendresponse(svcmdplayer(message, playerId, true), playerId)
  7985.             end
  7986.         else
  7987.             privatesay(playerId, "Chat commands are currently disabled")
  7988.         end
  7989.     end
  7990.    
  7991.     ::endchat::
  7992.    
  7993.     if AllowChat ~= false and defaults.spam_max > 0 and (defaults.antispam == "all" or (defaults.antispam == "players" and not getaccess(playerId))) then
  7994.         iptable.spamcounter = iptable.spamcounter + 1
  7995.     end
  7996.    
  7997.     if AllowChat and defaults.anticaps then
  7998.         return true, lower(message)
  7999.     end
  8000.    
  8001.     -- Print a message to the console of the chat.
  8002.     hprintf("\nOnServerChat(" .. playerId .. ", " .. tostring(chattype) .. ") " .. getname(playerId) .. ": (" .. resolveplayer(playerId) .. ") " .. message)
  8003.    
  8004.     if AllowChat ~= false and defaults.chatids then
  8005.         return true, " (" .. resolveplayer(playerId) .. ") " .. message
  8006.     end
  8007.    
  8008.     return AllowChat
  8009. end
  8010.  
  8011. function rtvTimer(id, count)
  8012.     if rtv_counter > 0 then
  8013.         rtv_counter = -defaults.rtv_timeout
  8014.         for i = 0,15 do
  8015.             ip_table[getip(i)].rtv_rocked = false
  8016.         end
  8017.         say "The current rtv has expired"
  8018.     end
  8019.     return false
  8020. end
  8021.  
  8022. function rconBruteForceTimeout(id, count, iptable)
  8023.     if iptable.rcon_fails == 0 then
  8024.         iptable.rconfail_timer = nil
  8025.         return false
  8026.     end
  8027.    
  8028.     iptable.rcon_fails = iptable.rcon_fails - 1
  8029.     return true
  8030. end
  8031.  
  8032. local command_attempt
  8033. -- this function is horrendously named, would you believe it's only SUPPOSED to be called when BAD rcon passwords are given?
  8034. function OnServerCommandAttempt(playerId, command, password)
  8035.     command_attempt = true
  8036.     local t = tokenizecmdstring(command)
  8037.     local cmd = getvalidformat(t[1])
  8038.    
  8039.     -- EVEN IF the server is executing a command, we don't want it executing commands during scrimmode.
  8040.     if defaults.scrim_mode then
  8041.  
  8042.         -- Format our command.
  8043.         if Commands[cmd].scrim == false then
  8044.             sendresponse("This command is currently disabled.\nTurn Scrim mode off to reenable this command.", playerId)
  8045.             cmdlog(getname(playerId) .. " attempted to use " .. cmd .. " during scrim mode.")
  8046.             return false
  8047.         end
  8048.     end
  8049.  
  8050.     -- Do nothing if the server is executing a command
  8051.     if not playerId then return nil end
  8052.    
  8053.     -- If the player has gotten the password wrong too many times, stop them from executing any more commands for 5 minutes
  8054.     local iptable = ip_table[getip(playerId)]
  8055.     if iptable.rcon_fails == 10 then
  8056.         if iptable.rconfail_timer then
  8057.             iptable.rcon_fails = iptable.rcon_fails + 1
  8058.         else
  8059.             iptable.rconfail_timer = registertimer(1000, "rconBruteForceTimeout", iptable)
  8060.         end
  8061.         return false
  8062.     end
  8063.    
  8064.     if password then
  8065.         output_environment = 1
  8066.     end
  8067.    
  8068.     -- We now have several cases here.
  8069.     -- If there are no admins, anyone can use the generic rcon
  8070.     -- If there are admins, then only admins can use the generic rcon
  8071.     -- If there is no generic rcon (sv_rcon_password set to "any"), admins can use any rcon password they want.
  8072.     -- If there is no password given, it is a chatcommand and we need to check their access.
  8073.     -- Everyone can use global rcons (in the rcon_passwords table).
  8074.  
  8075.     local permission = false
  8076.     local access
  8077.    
  8078.     -- Check out global passwords (sv_rcon_add)
  8079.     local level = password and rcon_passwords[password]
  8080.     if level then
  8081.         permission = checkaccess(Commands[cmd], level)
  8082.     else
  8083.         access = next(admin_table) and getaccess(playerId)
  8084.         local generic_rcon = readstring(addresses.network_server_globals + 0x128)
  8085.         -- Check if a password wasn't given (chat command), there is no generic rcon (sv_rcon_password is DISABLED), or if the generic rcon = the password given
  8086.         -- Only does this check if they are admin
  8087.         if access and (not password or generic_rcon == "any" or generic_rcon == password) then
  8088.             permission = checkaccess(Commands[cmd], access)
  8089.         end
  8090.     end
  8091.  
  8092.     if not permission then
  8093.         local admin_entry = player_table[playerId].admin_entry
  8094.         if level then
  8095.             cmdlog("    >>Security Alert: " .. getname(playerId) .. " (Nickname: " .. (admin_entry and admin_entry.name or "N/A") .. " Hash:" .. gethash(playerId) .. " IP: " .. getip(playerId) .. ") tried to execute: '" .. command .. "'")
  8096.             sendresponse("This Rcon does not have access to that command. This will be reported.", playerId)
  8097.         elseif password then
  8098.             if not access then
  8099.                 cmdlog(getname(playerId) .. " (Nickname: " .. (admin_entry and admin_entry.name or "N/A") .. " Hash:" .. gethash(playerId) .. " IP: " .. getip(playerId) .. ") tried to use '" .. password .. "' as an rcon password")
  8100.                 sendresponse("You are not an admin. This will be reported", playerId)
  8101.             elseif not level then
  8102.                 cmdlog(getname(playerId) .. " (Nickname: " .. (admin_entry and admin_entry.name or "N/A") .. " Hash:" .. gethash(playerId) .. " IP: " .. getip(playerId) .. ") tried to use '" .. password .. "' as an rcon password")
  8103.                 sendresponse("That is not an rcon password", playerId)
  8104.             end
  8105.         else
  8106.             cmdlog(getname(playerId) .. " (Nickname: " .. (admin_entry and admin_entry.name or "N/A") .. " Hash:" .. gethash(playerId) .. " IP: " .. getip(playerId) .. ") tried to execute: '" .. command .. "'")
  8107.             sendresponse("You cannot execute this command.", playerId)
  8108.             goto ReturnPermission
  8109.         end
  8110.        
  8111.         iptable.rcon_fails = iptable.rcon_fails + 1
  8112.        
  8113.         ::ReturnPermission::
  8114.         command_attempt = false
  8115.     end
  8116.     return permission
  8117. end
  8118.  
  8119. function OnServerCommand(playerId, command)
  8120.    
  8121.     -- this is to prevent infinite loops from when I want to execute a halo command
  8122.     -- without creating infinite loops (continually calling my sv_unban which will then continually call this etc)
  8123.     if dont_call_onservercommand then return nil end
  8124.    
  8125.     -- this means that a valid password was given so oncommandattempt was never actually called.
  8126.     -- It also means the command came using the console, and not the chat
  8127.     if not command_attempt then
  8128.         if OnServerCommandAttempt(playerId, command, readstring(addresses.network_server_globals + 0x128)) == false then
  8129.             return false
  8130.         elseif playerId then
  8131.             output_environment = 1
  8132.         end
  8133.     else
  8134.         command_attempt = nil
  8135.     end
  8136.  
  8137.     local response, thisCommand
  8138.     local t = tokenizecmdstring(command)
  8139.     local count = #t
  8140.  
  8141.     -- Format our command.
  8142.     local cmd = getvalidformat(t[1])
  8143.    
  8144.     if cmd == "help" or cmd == "gethelp" then
  8145.         response = false
  8146.         thisCommand = Commands[getvalidformat(t[2])] or count == 3 and Commands[getvalidformat(t[2] .. " " .. t[3])]
  8147.         if thisCommand and thisCommand.help then
  8148.             sendresponse(thisCommand.help, playerId)
  8149.         else
  8150.             sendresponse("No help topics for command '" .. tostring(t[2]) .. "'", playerId)
  8151.         end
  8152.     else
  8153.         -- this is a bit hacky, but I've made hackier stuff before, plus this will always work :D
  8154.         -- Code for commands with spaces in it.
  8155.         local testCmd
  8156.         while count >= 2 do
  8157.             testCmd = getvalidformat(concat(t, " ", 1, 2))
  8158.             thisCommand = Commands[testCmd]
  8159.             if thisCommand then
  8160.                 t[1] = testCmd
  8161.                 cmd = getvalidformat(testCmd)
  8162.                 remove(t, 2)
  8163.                 count = count - 1
  8164.             -- we done
  8165.             else
  8166.                 break
  8167.             end
  8168.         end
  8169.         thisCommand = Commands[cmd]
  8170.  
  8171.         -- First possibility: a command gets truncated in a valid format, and this function recognizes it as a script command
  8172.         if thisCommand then
  8173.             response = false
  8174.             local origCommand = t[1]
  8175.             remove(t, 1) -- the command isn't an argument.
  8176.             thisCommand:Execute(t, origCommand, playerId)
  8177.        
  8178.         -- this means it is NOT one of my scripted commands.
  8179.         else
  8180.             local message
  8181.             local newcmd = command
  8182.             local cmdWeirdFormat
  8183.             if sub(newcmd, 1, 1) == "/" or sub(newcmd, 1, 1) == "\\" then
  8184.                 newcmd = sub(newcmd, 2)
  8185.                 cmdWeirdFormat = command
  8186.             end
  8187.            
  8188.             -- Second Possibility: the command needs an appended sv_ at the beginning
  8189.             if sub(newcmd, 1, 3) ~= "sv_" then
  8190.            
  8191.                 cmdWeirdFormat = cmdWeirdFormat or "sv_" .. newcmd
  8192.                 message = halo_svcmd(newcmd, true)
  8193.                 if type(message) ~= "table" or type(message[1]) ~= "string" or find(concat(message), "Requested function \"") then
  8194.                     message = halo_svcmd("sv_" .. newcmd, true)
  8195.                 end
  8196.                 response = false
  8197.             end
  8198.            
  8199.             -- Send back the message from the non-scripted command.
  8200.             if type(message) == "table" and type(message[1]) == "string" and not find(concat(message), "Requested function \"") then
  8201.                 message[1] = "RESPONSE: " .. message[1]
  8202.                 sendresponse(message, playerId)
  8203.             elseif response == false then
  8204.                 sendresponse("Command \"" .. t[1] .. "\" not found.", playerId)
  8205.             end
  8206.         end
  8207.     end
  8208.     if playerId and response == false then
  8209.         cmdlog(format("%s (Nickname: %s Hash: %s IP: %s) has executed: %s", (player_table[playerId].admin_entry and player_table[playerId].admin_entry.name or "N/A"), getname(playerId), gethash(playerId), getip(playerId), command))
  8210.     end
  8211.    
  8212.     -- Third Possibility: if this was a chat command that was trying to execute a non-scripted command, then execute that command (returning false will do nothing)
  8213.     if output_environment >= 2 and response ~= false then
  8214.         halo_svcmd(cmd)
  8215.     end
  8216.    
  8217.     return response
  8218. end
  8219.  
  8220. function OnPlayerKill(killerPlayerId, victimPlayerId, mode)
  8221.     cleanupdrones(victimPlayerId)
  8222.    
  8223.     local vtable = player_table[victimPlayerId]
  8224.     local ktable = player_table[killerPlayerId]
  8225.     vtable.godmode = false
  8226.     if defaults.respawn_time then
  8227.  
  8228.         writedword(getplayer(victimPlayerId) + 0x2C, defaults.respawn_time * 30)
  8229.     end
  8230.     if mode == 4 then
  8231.         if defaults.tbag_detection then
  8232.             ktable.tbagname = getname(victimPlayerId)
  8233.             ktable.tbagcount = 0
  8234.             vtable.tbagcount = 0
  8235.             vtable.x,
  8236.             vtable.y,
  8237.             vtable.z = getobjectcoords(vtable.objectId)
  8238.         end
  8239.         if defaults.killing_spree then
  8240.             local m_kplayer = getplayer(killerPlayerId)
  8241.             local kname = getname(killerPlayerId)
  8242.  
  8243.  
  8244.             local multikill = readword(m_kplayer + 0x98)
  8245.             if multikill == 2 then
  8246.                 sendconsoletext(killerPlayerId, "Double Kill")
  8247.             elseif multikill == 3 then
  8248.                 sendconsoletext(killerPlayerId, "Triple Kill")
  8249.             elseif multikill == 4 then
  8250.                 sendconsoletext(killerPlayerId, "OverKill")
  8251.             elseif multikill == 5 then
  8252.                 sendconsoletext(killerPlayerId, "Killtacular")
  8253.             elseif multikill == 6 then
  8254.                 sendconsoletext(killerPlayerId, "Killtrocity")
  8255.             elseif multikill == 7 then
  8256.                 sendconsoletext(killerPlayerId, "Killimanjaro")
  8257.             elseif multikill == 8 then
  8258.                 sendconsoletext(killerPlayerId, "Killtastrophe")
  8259.             elseif multikill == 9 then
  8260.                 sendconsoletext(killerPlayerId, "Killpocalypse")
  8261.             elseif multikill >= 10 then
  8262.                 sendconsoletext(killerPlayerId, "Killionaire")
  8263.             end
  8264.            
  8265.             local spree = readword(m_kplayer + 0x96)
  8266.             if spree == 5 then
  8267.                 Say(kname .. " is on a Killing Spree", 1, killerPlayerId)
  8268.                 sendconsoletext(killerPlayerId, "Killing Spree")
  8269.             elseif spree == 10 then
  8270.                 Say(kname .. " is on a Killing Frenzy", 1, killerPlayerId)
  8271.                 sendconsoletext(killerPlayerId, "Killing Frenzy")
  8272.             elseif spree == 15 then
  8273.                 Say(kname .. " is on a Running Riot", 1, killerPlayerId)
  8274.                 sendconsoletext(killerPlayerId, "Running Riot")
  8275.             elseif spree == 20 then
  8276.                 Say(kname .. " is on a Rampage", 1, killerPlayerId)
  8277.                 sendconsoletext(killerPlayerId, "Rampage")
  8278.             elseif spree == 25 then
  8279.                 Say(kname .. " is Untouchable", 1, killerPlayerId)
  8280.                 sendconsoletext(killerPlayerId, "Untouchable")
  8281.             elseif spree == 30 then
  8282.                 Say(kname .. " is Invincible", 1, killerPlayerId)
  8283.                 sendconsoletext(killerPlayerId, "Invincible")
  8284.             elseif spree == 35 then
  8285.                 Say(kname .. " is Inconceivable", 1, killerPlayerId)
  8286.                 sendconsoletext(killerPlayerId, "Inconceivable")
  8287.             elseif spree >= 40 and spree%2 == 0 then
  8288.                 Say("OMFGWTFBBQWAFFLES " .. kname .. " is Unfrigginbelievable", 1, killerPlayerId)
  8289.                 sendconsoletext(killerPlayerId, "OMFGWTFBBQWAFFLES Unfrigginbelievable")
  8290.             end
  8291.         end
  8292.     end
  8293.     vtable.objectId = 0xFFFFFFFF
  8294.     vtable.object_struct = nil
  8295. end
  8296.  
  8297. function playerWeaponCheckTimer(id, count)
  8298.     for playerId = 0,15 do
  8299.    
  8300.         if not getplayer(playerId) then
  8301.             goto continue
  8302.         end
  8303.        
  8304.         local m_playerObj, playerObjId = getplayerobject(playerId)
  8305.         if not m_playerObj then
  8306.             goto continue
  8307.         end
  8308.  
  8309.         local pweaptable = player_table[playerId].weapons
  8310.  
  8311.         local m_weaponObj, weaponObjId
  8312.         for slot = 1,4 do
  8313.             weaponObjId = readdword(m_playerObj + 0x2F8+(slot-1)*4)
  8314.             m_weaponObj = getobject(weaponObjId)
  8315.             if m_weaponObj and weaponObjId ~= pweaptable[slot] then
  8316.                 writeshort(m_weaponObj + 0x2B6, 0x7CFF)
  8317.                 writeshort(m_weaponObj + 0x2B8, 0x7CFF)
  8318.                 updateammo(weaponObjId)
  8319.                 pweaptable[slot] = weaponObjId
  8320.             end
  8321.         end
  8322.         ::continue::
  8323.     end
  8324.  
  8325.     return true
  8326. end
  8327.  
  8328. function OnClientUpdate(playerId)
  8329.     if not defaults.tbag_detection then
  8330.         return
  8331.     end
  8332.    
  8333.     local ptable = player_table[playerId]
  8334.     if ptable.m_vehicleObj then
  8335.         return
  8336.     end
  8337.    
  8338.     local playerObjId = getplayerobjectid(playerId)
  8339.     local m_playerObj = getobject(playerObjId)
  8340.     if not m_playerObj then
  8341.         return
  8342.     end
  8343.  
  8344.  
  8345.     if ptable.tbagname == "" then
  8346.         return
  8347.     end
  8348.    
  8349.     local crouching = readbyte(m_playerObj + 0x2A0) == 3
  8350.    
  8351.     if not ptable.crouch and crouching then
  8352.         ptable.tbagcount = (ptable.tbagcount or 0) + 1
  8353.         if ptable.tbagcount == 4 then
  8354.             ptable.tbagcount = 0
  8355.             ptable.tbagname = ""
  8356.             say(getname(playerId) .. " is T-Bagging " .. ptable.tbagname)
  8357.         end
  8358.         ptable.crouch = true
  8359.     elseif ptable.crouch and not crouching then
  8360.         ptable.crouch = false
  8361.     end
  8362. end
  8363.  
  8364. function OnObjectInteraction(playerId, objectId, mapId)
  8365.     if defaults.noweapons or ip_table[getip(playerId)].disarmed then
  8366.         if getObjType(objectId) == 2 then
  8367.             return false
  8368.         end
  8369.     end
  8370.     return nil
  8371. end
  8372.  
  8373. function OnVehicleEntry(playerId, vehicleObjId, seat, mapId, relevant)
  8374.     local ptable = player_table[playerId]
  8375.     ptable.m_vehicleObj = getobject(vehicleObjId)
  8376.     ptable.vehicleObjId = vehicleObjId
  8377. end
  8378.  
  8379. function OnVehicleEject(playerId, voluntary)
  8380.     local ptable = player_table[playerId]
  8381.     ptable.m_vehicleObj = nil
  8382.     ptable.vehicleObjId = 0xFFFFFFFF
  8383. end
  8384.  
  8385. function OnDamageApplication(receiverObjId, causerObjId, tagId, hit, backtap)
  8386.     if getobject(causerObjId) then
  8387.         local playerId = objectidtoplayer(causerObjId)
  8388.         if playerId then
  8389.             local ptable = player_table[playerId]
  8390.             if ptable.bulletmode == "destroy" then
  8391.                 destroyobject(receiverObjId)
  8392.             elseif ptable.bulletmode == "entergun" then
  8393.                 local m_receiverObj = getobject(receiverObjId)
  8394.                 if m_receiverObj then
  8395.                     local objtype = readword(m_receiverObj + 0xB4)
  8396.                     if objtype == 1 then -- check if object is a vehicle
  8397.                         entervehicle(playerId, receiverObjId, 0)
  8398.                     end
  8399.                 end
  8400.             end
  8401.         end
  8402.     end
  8403. end
  8404.  
  8405. function OnDamageLookup(receiverObjId, causerObjId, mapId, tagdata)
  8406.     local receivingPlayerId = objectidtoplayer(receiverObjId)
  8407.     if not defaults.falldamage and (mapId == gettag("jpt!", "globals\\falling") or mapId == gettag("jpt!", "globals\\distance")) then
  8408.         odl_multiplier(0.001)
  8409.     elseif defaults.deathless or (receivingPlayerId and player_table[receivingPlayerId].godmode) then
  8410.         odl_multiplier(0.001)
  8411.         local dmg_side_effect = readword(tagdata + 0x1C4)
  8412.         if dmg_side_effect == 2 or dmg_side_effect == 3 then
  8413.             writeword(tagdata + 0x1C4, 0)
  8414.             registertimer(0, "DamageAddressReset", TM{tagdata, 0x1C4, dmg_side_effect})
  8415.         end
  8416.     elseif causerObjId and receivingPlayerId then
  8417.         local causingPlayerId = objectidtoplayer(causerObjId)
  8418.         local m_causingPlayer, m_receivingPlayer = getplayer(causingPlayerId), getplayer(receivingPlayerId)
  8419.         if m_receivingPlayer and m_causingPlayer and causingPlayerId ~= receivingPlayerId then
  8420.             local ptable = player_table[causingPlayerId]
  8421.             if ptable.dmgmultiplier ~= 1 then
  8422.                 odl_multiplier(ptable.dmgmultiplier)
  8423.             end
  8424.             if defaults.multiteam_vehicles then
  8425.                 local count = getteam(receivingPlayerId)
  8426.                 while getteam(causingPlayerId) == count do
  8427.                     count = count + 1
  8428.                 end
  8429.                 writebyte(m_receivingPlayer + 0x20, count)
  8430.                 registertimer(0, "multiteamtimer", receivingPlayerId)
  8431.             end
  8432.         end
  8433.     end
  8434.     return nil
  8435. end
  8436.  
  8437. function multiteamtimer(id, count, playerId)
  8438.     local m_player = getplayer(playerId)
  8439.     if m_player and defaults.multiteam_vehicles then
  8440.         writebyte(m_player + 0x20, 0)
  8441.     end
  8442.     return false
  8443. end
  8444.  
  8445. function DamageAddressReset(id, count, userdata)
  8446.     local address = userdata[1]
  8447.     local offset = userdata[2]
  8448.     local orig_value = userdata[3]
  8449.     writeword(address + offset, orig_value)
  8450.     return false
  8451. end
  8452.  
  8453. local TempObjectTable = {}
  8454. function OnObjectCreationAttempt(mapId, parentObjId, playerId)
  8455.     TempObjectTable[1] = mapId
  8456.     TempObjectTable[2] = playerId
  8457.     return nil
  8458. end
  8459.  
  8460. function OnObjectCreation(objectId)
  8461.     if defaults.infinite_ammo then
  8462.         local m_object = getobject(objectId)
  8463.         if m_object then
  8464.             local obj_type = readword(m_object, 0xB4)
  8465.             if obj_type == 2 then -- check if it is a weapon
  8466.                 writeshort(m_object + 0x2B6, 0x7CFF)
  8467.                 writeshort(m_object + 0x2B8, 0x7CFF)
  8468.             end
  8469.             return -- we can safely return here
  8470.         end
  8471.     end
  8472.     local mapId, playerId = TempObjectTable[1], TempObjectTable[2]
  8473.     if getplayer(playerId) then
  8474.         if mapId ~= gettag("proj", "weapons\\flamethrower\\flame")
  8475.         and mapId ~= gettag("proj", "weapons\\needler\\mp_needle")
  8476.         and mapId ~= gettag("proj", "weapons\\frag grenade\\frag grenade")
  8477.         and mapId ~= gettag("proj", "weapons\\plasma grenade\\plasma grenade") then
  8478.             local ptable = player_table[playerId]
  8479.             if ptable.bulletmode == "portalgun" then
  8480.                 registertimer(100, "portalgunTimer", TM{getplayerobjectid(playerId), objectId})
  8481.             elseif ptable.bulletmode == "spawngun" then
  8482.                 registertimer(100, "spawngunTimer", TM{playerId, objectId})
  8483.             end
  8484.         end
  8485.     end
  8486. end
  8487.  
  8488. function portalgunTimer(id, count, arg)
  8489.     local playerObjId = arg[1]
  8490.     local bulletObjId = arg[2]
  8491.     local m_bulletObj = getobject(bulletObjId)
  8492.     if count < 100 and getobject(bulletObjId) then
  8493.         if readfloat(m_bulletObj + 0x68) == 0 then
  8494.             local x,y,z = getobjectcoords(bulletObjId)
  8495.             if getobject(playerObjId) then
  8496.                 movobjectcoords(playerObjId, x, y, z)
  8497.             end
  8498.         else
  8499.             return true
  8500.         end
  8501.     end
  8502.     return false
  8503. end
  8504.  
  8505. function spawngunTimer(id, count, arg)
  8506.     local playerId = arg[1]
  8507.     local playerObjId = arg[2]
  8508.     if getobject(playerObjId) then
  8509.         local x,y,z = getobjectcoords(playerObjId)
  8510.         createobject(player_table[playerId].objspawnid, 0, 60, false, x, y, z+0.6)
  8511.     end
  8512.     return false
  8513. end
  8514.  
  8515. function MainTimer(id, count)
  8516.    
  8517.     -- For hiding.
  8518.     local m_player
  8519.     for i = 0,15 do
  8520.         if player_table[i].hidden then
  8521.             m_player = getplayer(i)
  8522.             if m_player then
  8523.                 writefloat(m_player + 0x100, -100)
  8524.             end
  8525.         end
  8526.     end
  8527.    
  8528.     -- will run every second
  8529.     if count % 30 == 0 then
  8530.    
  8531.         -- local variables used
  8532.         local ip, name, ptable, iptable
  8533.    
  8534.         -- For invisible timer, suspended timer, and message spamming.
  8535.         for i = 0,15 do
  8536.             if getplayer(i) then
  8537.                 ptable = player_table[i]
  8538.                 if ptable.invisible == -1 then
  8539.                     applycamo(i, 1)
  8540.                 elseif ptable.invisible then
  8541.                     applycamo(i, 1)
  8542.                     ptable.invisible = ptable.invisible - 1
  8543.                     if ptable.invisible <= 0 then
  8544.                         ptable.invisible = false
  8545.                     end
  8546.                 end
  8547.                
  8548.                 iptable = ip_table[getip(i)]
  8549.                
  8550.                 if type(iptable.suspended) == "number" and iptable.suspended ~= 0 then
  8551.                     iptable.suspended = iptable.suspended - 1
  8552.                 end
  8553.  
  8554.                 -- Player is currently muted for spamming, add 1 second from their timeout_table until they are at 0 (or above).
  8555.                 if iptable.spamcounter < 0 then
  8556.                     iptable.spamcounter = iptable.spamcounter + 1
  8557.                     if iptable.spamcounter > 0 then
  8558.                         say(getname(i) .. " has been unmuted")
  8559.                         iptable.spamcounter = 0
  8560.                     end
  8561.                 -- Player has spammed too many messages, mute them for spamming
  8562.                 elseif iptable.spamcounter > defaults.spam_max then
  8563.                     say(getname(i) .. " has been muted for " .. defaults.spam_timeout .. " seconds for spamming")
  8564.                     iptable.spamcounter = -defaults.spam_timeout
  8565.                 -- Player has sent a message within 1 second, will take 4 seconds to remove from spam counter.
  8566.                 elseif iptable.spamcounter > 0 then
  8567.                     iptable.spamcounter = iptable.spamcounter - 0.25
  8568.                 end
  8569.             end
  8570.         end
  8571.        
  8572.         -- RTV Counter
  8573.         if rtv_counter < 0 then
  8574.             rtv_counter = rtv_counter + 1
  8575.             if rtv_counter == 0 then
  8576.                 say "RTV can be started again."
  8577.             end
  8578.         end
  8579.        
  8580.         -- VoteKick Counter
  8581.         if votekick_counter < 0 then
  8582.             votekick_counter = votekick_counter + 1
  8583.             if votekick_counter == 0 then
  8584.                 say "VoteKick can be started again!"
  8585.             end
  8586.         end
  8587.     end
  8588.    
  8589.     return true
  8590. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement