- --Creator: Wizard
- --Script Name: Command Script
- --Website: http://phasorscripts.wordpress.com/
- --Xfire: th3w1zard3
- --Check Change Log for information on the updates
- --Thank you AElite for the awesome work you did in updating this script to the latest phasor, and the other awesome features you put in.
- --Without you I never would have updated to the newer phasor, and this script never would have been made.
- -- 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)
- --
- --Do Not Modify unless you really know what you are doing
- --
- -- Counts
- local cur_players = 0
- local rtv_counter = 0
- local votekick_counter = 0
- local scorelimit = 50
- -- Strings
- local script_version = "5.2 The 'Nimbus' Release"
- -- Timers
- local infammo_timer
- local lo3_timer
- local maintimer
- local rtvtimer
- local votekicktimer
- -- Script Variables
- local changelog
- local dont_call_onservercommand
- local executingPlayerId
- local Game
- local gameend
- local gametype
- local http
- local flameId
- local Map
- local output_environment = -1
- local Persistent
- local processid
- local profilepath
- local server
- local server_prefix
- local someoneHidden = false
- local socket
- local team_play
- local team_play_temp
- local time_passed_value
- local timelimit_set_value
- local votekickPlayerId
- -- Local variables defined for decreased execution time (but mostly to organize what is using the global environment)
- local io, tostring, tonumber, next, type, os, select = io, tostring, tonumber, next, type, os, select
- local sub, gsub, find, lower, format, match = string.sub, string.gsub, string.find, string.lower, string.format, string.match
- local insert, remove, concat = table.insert, table.remove, table.concat
- local ceil, floor = math.ceil, math.floor
- -- Table Management
- local TM = setmetatable({
- unused_tables = {},
- __gc = function(self) self.unused_tables[#self.unused_tables+1] = self end,
- __tostring = function(t)
- local tableStr = "{ "
- if next(t) then
- for k,v in next,t do
- if v == t then goto nextVal end
- k = type(k) ~= "number" and '["' .. k .. '"]' or k
- v = type(v) == "string" and '"' .. v .. '"' or tostring(v)
- tableStr = tableStr .. (k .. " = ") .. v .. ", "
- ::nextVal::
- end
- tableStr = sub(tableStr, 1, #tableStr-2)
- else
- tableStr = tableStr
- end
- return tableStr .. "}"
- end,
- deleteEntries = function(t)
- for key,_ in next,t do
- t[key] = nil
- end
- return t
- end
- },
- {
- __call = function(TM, t)
- local mt = getmetatable(t)
- if mt then
- mt.__index = TM
- return t
- else
- return setmetatable(t, TM)
- end
- end
- }
- )
- TM.__index = TM
- -- Tables
- local access_table = {}
- --local addresses
- local admin_table = {}
- local ban_table = {}
- local ban_penalty = {}
- local bos_table = {}
- local Commands = {commandAliases = {}}
- Commands.__index = Commands -- class setup
- local commandAliases = Commands.commandAliases
- local connections = {}
- local cmdreply = setmetatable({index = 0}, {
- __mode = "v", -- weak table
- __len = function(self) return (rawget(self, "index") or 0) end,
- --old method
- --[[
- __newindex = function(self, key, value)
- if not tonumber(key) then
- return
- end
- local index = rawget(self, "index")
- rawset(self, "index", value and (index+1) or (index-1)) -- update the index.
- rawset(self, key, value or rawget(self, index))
- end,]]
- __call = function(self, bResetAll)
- if not bResetAll then
- local index = rawget(self, "index") + 1
- rawset(self, "index", index)
- return index
- end
- rawset(self, "header", nil)
- rawset(self, "align", nil)
- rawset(self, "delim", nil)
- rawset(self, "separator", nil)
- rawset(self, "index", 0)
- end
- })
- local clients = {}
- local debug_players = {}
- -- REM: change back cobalthidden before release.
- local player_colors = {[0] = "white", "black", "red", "blue", "grey", "yellow", "green", "pink", "purple", "cyan", "cobalthidden", "orange", "teal", "sage", "brown", "tan", "maroon", "salmon", white = 0, black = 1, red = 2, blue = 3, grey = 4, yellow = 5, green = 6, pink = 7, purple = 8, cyan = 9, cobalthidden = 10, orange = 11, teal = 12, sage = 13, brown = 14, tan = 15, maroon = 16, salmon = 17}
- local team_colors = {[0] = "red", "blue", "white", "black", "pink", "yellow", "cobalthidden", "orange", "purple", "cyan", "maroon", "teal", "green", "sage", "brown", "salmon"}
- local player_scores = {[0] = 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
- local team_scores = {[0] = 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
- -- Default Scripted Game Variables
- local defaults = {
- kickbans_file = "KicksAndBans",
- commands_file = "commands",
- admin_file = "admins",
- banlist_file = "banned",
- sharedhash_file = "sharedhashes",
- ban_penalty = "5m 1d 10d",
- remote_bansystem = false,
- remotecontrol = false,
- --tkban_type = "ip",
- adminblocker = 0,
- anticaps = false,
- antispam = "players",
- chatcommands = true,
- chatids = true,
- crouch_camo = false,
- deathless = false,
- debug_mode = false,
- falldamage = true,
- firstjoin_message = true,
- hash_duplicates = true,
- infinite_ammo = false,
- killing_spree = true,
- multiteam_vehicles = false,
- noweapons = false,
- pm_enabled = true,
- respawn_time = -1,
- rtv_enabled = true,
- rtv_required = 50,
- rtv_timeout = 120,
- sa_message = true,
- scrim_mode = false,
- spam_max = 7,
- spam_timeout = 60,
- tbag_detection = true,
- uniques_enabled = true,
- votekick_enabled = true,
- votekick_action = "kick",
- votekick_required = 70,
- votekick_timeout = 120,
- wb_message = true
- }
- local identities = {}
- identities.__index = identities
- local leave_table = {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}
- local locations = {} -- map = {locname = {x, y, z}}
- local spawnWeapons = {}
- local tag_table = {}
- local objects
- local playerMT = {}
- local PlayerClass = {
- [0]={drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}},
- {drones = TM{}, weapons = {}}
- }
- PlayerClass.__index = PlayerClass
- for i = 0,15 do
- setmetatable(PlayerClass[i], PlayerClass)
- end
- local randomNames = {
- Butcher = 1,
- Caboose = 2,
- Crazy = 3,
- Cupid = 4,
- Darling = 5,
- Dasher = 6,
- Disco = 7,
- Donut = 8,
- Dopey = 9,
- Ghost = 10,
- Goat = 11,
- Grumpy = 12,
- Hambone = 13,
- Hollywood = 14,
- Howard = 15,
- Jack = 16,
- Killer = 17,
- King = 18,
- Mopey = 19,
- Noodle = 20,
- Penguin = 21,
- Pirate = 22,
- Prancer = 23,
- Saucy = 24,
- Shadow = 25,
- Sleepy = 26,
- Snake = 27,
- Sneak = 28,
- Stompy = 29,
- Stumpy = 30,
- ["The Bear"] = 31,
- ["The Big L"] = 32,
- Tooth = 33,
- ["Walla Walla"] = 34,
- Weasel = 35,
- Wheezy = 36,
- Whicker = 37,
- Whisp = 38,
- Wilshire = 39
- }
- local rcon_passwords = {}
- local sharedhashes = {
- ["f443106bd82fd6f3c22ba2df7c5e4094"] = 1,
- ["c702226e783ea7e091c0bb44c2d0ec64"] = 2,
- ["d72b3f33bfb7266a8d0f13b37c62fddb"] = 3,
- ["55d368354b5021e7dd5d3d1525a4ab82"] = 4,
- ["3d5cd27b3fa487b040043273fa00f51b"] = 5,
- ["b661a51d4ccf44f5da2869b0055563cb"] = 6,
- ["740da6bafb23c2fbdc5140b5d320edb1"] = 7,
- ["10440b462f6cbc3160c6280c2734f184"] = 8,
- ["7503dad2a08026fc4b6cfb32a940cfe0"] = 9,
- ["4486253cba68da6786359e7ff2c7b467"] = 10,
- ["f1d7c0018e1648d7d48f257dc35e9660"] = 11,
- ["40da66d41e9c79172a84eef745739521"] = 12,
- ["2863ab7e0e7371f9a6b3f0440c06c560"] = 13,
- ["34146dc35d583f2b34693a83469fac2a"] = 14,
- ["b315d022891afedf2e6bc7e5aaf2d357"] = 15,
- ["81f9c914b3402c2702a12dc1405247ee"] = 16,
- ["63bf3d5a51b292cd0702135f6f566bd1"] = 17,
- ["6891d0a75336a75f9d03bb5e51a53095"] = 18,
- ["325a53c37324e4adb484d7a9c6741314"] = 19,
- ["0e3c41078d06f7f502e4bb5bd886772a"] = 20,
- ["fc65cda372eeb75fc1a2e7d19e91a86f"] = 21,
- ["f35309a653ae6243dab90c203fa50000"] = 22,
- ["50bbef5ebf4e0393016d129a545bd09d"] = 23,
- ["a77ee0be91bd38a0635b65991bc4b686"] = 24,
- ["3126fab3615a94119d5fe9eead1e88c1"] = 25,
- ["d41d8cd98f00b204e9800998ecf8427e"] = 26
- }
- local threads = {} -- list of all live threads
- local unique_table = TM(setmetatable({total = 0}, {__len = function(self) return self.total end}))
- local valid_maps = {}
- local valid_gametypes = {}
- -- Send Debug Messages
- local function sendDebugMessage(message)
- local playerId
- for playerId = 0,15 do
- if debug_players[playerId] then
- sendconsoletext(playerId, message)
- end
- end
- end
- -- Private Functions
- -- Phasor doesn't automatically check limits for write functions, it just errors, so let's make our own check.
- local function writewithinlimit(address, value, writefunc, minlimit, maxlimit)
- writefunc(address, value <= minlimit and minlimit or value >= maxlimit and maxlimit or value)
- end
- local function writebyte(address, offset, value)
- if value then
- address = address + offset
- else
- value = offset
- end
- writewithinlimit(address, value, _G.writebyte, 0, 0xFF)
- end
- local function writechar(address, offset, value)
- if value then
- address = address + offset
- else
- value = offset
- end
- writewithinlimit(address, value, _G.writechar, -0x80, 0x7F)
- end
- local function writeword(address, offset, value)
- if value then
- address = address + offset
- else
- value = offset
- end
- writewithinlimit(address, value, _G.writeword, 0, 0xFFFF)
- end
- local function writeshort(address, offset, value)
- if value then
- address = address + offset
- else
- value = offset
- end
- writewithinlimit(address, value, _G.writeshort, -0x8000, 0x7FFF)
- end
- local function writedword(address, offset, value)
- if value then
- address = address + offset
- else
- value = offset
- end
- writewithinlimit(address, value, _G.writedword, 0, 0xFFFFFFFF)
- end
- local function writeint(address, offset, value)
- if value then
- address = address + offset
- else
- value = offset
- end
- writewithinlimit(address, value, _G.writeint, -0x80000000, 0x7FFFFFFF)
- end
- -- Phasor's read/writestring in previous versions are broken.
- local function readstring(address, length)
- address = type(address) == "number" and address or error("bad argument #1 to 'readstring' expected number, got '" .. type(address) .. "'")
- if length then
- length = type(length) == "number" and length or error("bad argument #2 to 'readstring' expected number, got '" .. type(length) .. "'")
- else
- length = length or 256
- end
- local char_table = {}
- local char = string.char
- local word, dword, byte1, byte2, byte3, byte4
- local i = 0
- while i < length do
- -- quickens read calls (screw you oxide for using virtualprotect)
- if (length-i) >= 4 then
- dword = readdword(address + i)
- byte1 = bit32.band(dword, 0xFF)
- if byte1 == 255 or byte1 == 0 then break end
- char_table[#char_table+1] = char(byte1)
- byte2 = bit32.band(bit32.rshift(dword, 8), 0xFF)
- if byte2 == 255 or byte2 == 0 then break end
- char_table[#char_table+1] = char(byte2)
- byte3 = bit32.band(bit32.rshift(dword, 16), 0xFF)
- if byte3 == 255 or byte3 == 0 then break end
- char_table[#char_table+1] = char(byte3)
- byte4 = bit32.band(bit32.rshift(dword, 24), 0xFF)
- if byte4 == 255 or byte4 == 0 then break end
- char_table[#char_table+1] = char(byte4)
- i = i + 4
- elseif (length-i) >= 2 then
- word = readword(address + i)
- byte1 = bit32.band(word, 0xFF)
- if byte1 == 255 or byte1 == 0 then break end
- char_table[#char_table+1] = char(byte1)
- byte2 = bit32.band(bit32.rshift(word, 8), 0xFF)
- if byte2 == 255 or byte2 == 0 then break end
- char_table[#char_table+1] = char(byte2)
- i = i + 2
- else
- byte1 = readbyte(address + i)
- if byte1 == 0 or byte1 == 255 then break end
- char_table[#char_table+1] = char(byte1)
- i = i + 1
- end
- end
- return table.concat(char_table)
- end
- local function readwidestring(address, length)
- address = type(address) == "number" and address or error("bad argument #1 to 'readwidestring' expected number, got '" .. type(address) .. "'")
- if length then
- length = type(length) == "number" and length or error("bad argument #2 to 'readwidestring' expected number, got '" .. type(length) .. "'")
- else
- length = length or 51001
- end
- local char_table = {}
- local char = string.char
- local word, dword, byte1, byte2, byte3, byte4
- local i = 0
- while i < length do
- -- quickens read calls (screw you oxide for using virtualprotect)
- if (length-i) >= 4 then
- dword = readdword(address + i)
- byte1 = bit32.band(dword, 0xFF)
- if byte1 == 255 or byte1 == 0 then break end
- char_table[#char_table+1] = char(byte1)
- byte2 = bit32.band(bit32.rshift(dword, 8), 0xFF)
- if byte2 ~= 255 or byte2 ~= 0 then break end
- byte3 = bit32.band(bit32.rshift(dword, 16), 0xFF)
- if byte3 == 255 or byte3 == 0 then break end
- char_table[#char_table+1] = char(byte3)
- byte4 = bit32.band(bit32.rshift(dword, 24), 0xFF)
- if byte4 ~= 255 or byte4 ~= 0 then break end
- i = i + 4
- else
- word = readword(address + i)
- byte1 = bit32.band(word, 0xFF)
- if byte1 == 255 or byte1 == 0 then break end
- char_table[#char_table+1] = char(byte1)
- byte2 = bit32.band(bit32.rshift(word, 8), 0xFF)
- if byte2 ~= 255 or byte2 ~= 0 then break end
- i = i + 2
- end
- end
- return table.concat(char_table)
- end
- local function writestring(address, offset, str)
- address = type(address) == "number" and address or error("bad argument #1 to 'writestring' expected number, got '" .. type(address) .. "'")
- if str then
- offset = type(offset) == "number" and offset or error("bad argument #2 to 'writestring' expected number, got '" .. type(offset) .. "'")
- str = type(str) == "string" and str or error("bad argument #3 to 'writestring' expected string, got '" .. type(str) .. "'")
- else
- str = type(offset) == "string" and offset or error("bad argument #2 to 'writestring' expected string, got '" .. type(offset) .. "'")
- offset = nil
- end
- address = address + (offset or 0x0)
- local byte_table = {}
- local byte = string.byte
- for char in string.gmatch(str, '.') do
- byte_table[#byte_table+1] = byte(char)
- end
- local length = #byte_table
- local i = 0
- while i < length do
- -- quickens write calls (screw you oxide for using virtualprotect)
- if (length-i) >= 4 then
- 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))
- i = i + 4
- elseif (length-i) >= 2 then
- writeword(address + i, tonumber(string.format("%02X%02X", byte_table[i+2], byte_table[i+1]), 16))
- i = i + 2
- else
- writebyte(address + i, byte_table[i+1])
- i = i + 1
- end
- end
- end
- local function writewidestring(address, offset, str)
- address = type(address) == "number" and address or error("bad argument #1 to 'writewidestring' expected number, got '" .. type(address) .. "'")
- if str then
- offset = type(offset) == "number" and offset or error("bad argument #2 to 'writewidestring' expected number, got '" .. type(offset) .. "'")
- str = type(str) == "string" and str or error("bad argument #3 to 'writewidestring' expected string, got '" .. type(str) .. "'")
- else
- str = type(offset) == "string" and offset or error("bad argument #2 to 'writewidestring' expected string, got '" .. type(offset) .. "'")
- offset = nil
- end
- address = address + (offset or 0x0)
- local byte_table = {}
- local byte = string.byte
- for char in string.gmatch(str, '.') do
- byte_table[#byte_table+1] = byte(char)
- end
- local length = #byte_table
- while i < length do
- -- quickens write calls (screw you oxide for using virtualprotect)
- if i % 4 == 0 and length - i >= 4 then
- writedword(address + i, tonumber((byte_table[i+2]*100) .. (byte_table[i+1]*100)))
- i = i + 2
- else
- writeword(address + i, byte_table[i+1])
- i = i + 1
- end
- end
- end
- -- crash prevention code.
- local function createobject(mapId, ...)
- if mapId and mapId ~= 0 and mapId ~= -1 then
- return _G.createobject(mapId, ...)
- end
- end
- local function getteam(playerId)
- if defaults.multiteam_vehicles or not team_play then
- return playerId
- end
- return _G.getteam(playerId)
- end
- -- Get Unused Table if available.
- function TM.New()
- local unused_tables = TM.unused_tables
- local length = #unused_tables
- local t = unused_tables[length]
- if t then
- -- use an unused table
- unused_tables[length] = nil
- t:deleteEntries()
- else
- -- no tables available, make a new one
- t = setmetatable({}, TM)
- end
- return t
- end
- local function validate_ipv4(ip)
- if not ip then return nil end
- ip = gsub(gsub(ip, "[%s]*", ""), "x+", "*")
- local a,b,c,slash,d,finish = match(ip, "^([^%.]+)%.([^%.]*)%.?([^%./]*)%.?(/?)([^%.]*)()")
- a = a == "" and "*" or match(a or "", "[%d%*]+")
- b = b == "" and "*" or match(b or "", "[%d%*]+")
- c = c == "" and "*" or match(c or "", "[%d%*]+")
- slash = slash ~= ""
- d = d or ""
- --print("IP VALIDATION I:",a,b,c,d,slash,finish)
- if slash then
- if d:find("/") or not match(d, "[%d%*]+") then return false end -- can't have two slashes
- d = "0/"..d -- Alternate form 194.1.4/24
- else
- d = d == "" and "*" or match(d, "[%d%*/]+")
- end
- if not a or not b or not c then
- return false -- bad ip
- end
- local found,a2,b2,c2,d2 = match(ip, "(%-)(%d+)%.(%d*)%.?(%d*)%.?(%d*)%c*$", finish)
- --print("IP VALIDATION II:",found,a2,b2,c2,d2)
- if not found then
- if a2 and a ~= "" then return false end -- this should just never happen lol
- return format("%s.%s.%s.%s",a,b,c,d)
- elseif slash then
- return false -- can't have a slash, and an iplimit.. lol
- end
- a2 = a2 == "" and "*" or match(a2, "[%d%*]+")
- b2 = b2 == "" and "*" or match(b2, "[%d%*]+")
- c2 = c2 == "" and "*" or match(c2, "[%d%*]+")
- d2 = d2 == "" and "*" or match(d2, "[%d%*]+")
- if not a2 or not b2 or not c2 then
- return false -- bad ip
- end
- if c2:find("/") and d2:find("/") then return false end
- return format("%s.%s.%s.%s-%s.%s.%s.%s", a,b,c,d,a2,b2,c2,d2)
- end
- local function check_ip(ip)
- local i = 1
- local octets = 1
- local octet = ""
- local err = ""
- local errors = 0
- local blocks = {}--TM.New()
- local c, block
- while (i <= #ip + 1) do
- c = sub(ip, i, i)
- if c == "." or #ip+1 == i then
- octets = octets + 1
- block = tonumber(octet)
- if not block or block > 255 or block < 0 or octets > 5 then
- errors = errors + 1
- err = err .. " \f3>" .. (block or "?") .. "<\f8"
- else
- blocks[#blocks+1] = octet
- err = err .. "\f0 " .. block .. "\f8"
- end
- octet = ""
- else
- octet = octet .. c
- end
- i = i + 1
- end
- local result = {}--TM.New()
- result[1] = err
- if errors > 0 then
- return result
- end
- result[2] = blocks
- return result
- end
- local function ip2long(ip_addr)
- local blocks = check_ip(ip_addr)[2] or error("Invalid IP-Address. IP_ADDR: " .. tostring(ip_addr) .. "\r\nError: " .. check_ip(ip_addr)[1])
- local a = bit32.lshift(blocks[1], 24)
- local b = #blocks >= 2 and bit32.lshift(blocks[2], 16)
- local c = #blocks >= 3 and bit32.lshift(blocks[3], 8)
- if not b or not c then return nil end
- return bit32.bor(bit32.bor(a, b, c), blocks[4])
- end
- local function convertSign(num, maxSize)
- return num - bit32.band(num, maxSize)*2
- end
- local function long2ip(addr)
- addr = tonumber(addr) or error("Invalid 32-bit Long: " .. addr)
- local a = bit32.rshift(bit32.band(addr, bit32.lshift(0xFF, 24)), 24)
- local b = bit32.rshift(bit32.band(addr, bit32.lshift(0xFF, 16)), 16)
- local c = bit32.rshift(bit32.band(addr, bit32.lshift(0xFF, 8)), 8)
- local d = bit32.band(addr, 0xFF)
- return format("%i.%i.%i.%i", convertSign(a, 255), convertSign(b, 255), convertSign(c, 255), convertSign(d, 255))
- end
- local function netMatch(network, ip)
- network = validate_ipv4(network)
- if not network then return end
- -- if no ip to check, then just validate the network.
- if not ip then return network end
- ip = validate_ipv4(ip)
- local orig_network = network
- if ip == network then
- --print("used network " .. network .. " for ip " .. ip)
- return network
- end
- network = gsub(network, ' ', '')
- if find(network, '*') then
- if find(network, '/') then
- network = tokenizestring(network, '/')[1]
- end
- local nCount
- network, nCount = gsub(network, '*', '*')
- network = gsub(network, '*', '0')
- if nCount == 1 then
- network = network .. '/24'
- elseif nCount == 2 then
- network = network .. '/16'
- elseif nCount == 3 then
- network = network .. '/8'
- elseif nCount > 3 then
- return network -- if *.*.*.*, then all, so matched
- end
- end
- if find(ip, '*') then
- if find(ip, '/') then
- ip = tokenizestring(ip, '/')[1]
- end
- local nCount
- ip, nCount = gsub(ip, '*', '*')
- ip = gsub(ip, '*', '0')
- if nCount == 1 then
- ip = ip .. '/24'
- elseif nCount == 2 then
- ip = ip .. '/16'
- elseif nCount == 3 then
- ip = ip .. '/8'
- elseif nCount > 3 then
- return ip -- if *.*.*.*, then all, so matched
- end
- end
- --print("from original network " .. orig_network .. ", used network " .. network .. " for " .. ip)
- local d = find(network, '-')
- if not d then
- local ip_arr = tokenizestring(network, "/")
- local network_long = ip2long(ip_arr[1])
- local mask = bit32.lshift(0xFFFFFFFF, (32 - (ip_arr[2] or 32)))
- local ip_arr2 = tokenizestring(ip, "/")
- local ip_long = ip2long(ip_arr2[1])
- local mask2 = bit32.lshift(0xFFFFFFFF, (32 - (ip_arr2[2] or 32)))
- return bit32.band(network_long, mask, mask2) == bit32.band(ip_long, mask, mask2)
- else
- local from = ip2long(sub(network, 1, d-1))
- local to = ip2long(sub(network, d+1))
- ip = ip2long(ip)
- return ip >= from and ip <= to
- end
- end
- local function iptoplayer(ip)
- for playerId = 0,15 do
- if getplayer(playerId) and netMatch(getip(playerId) .. "/24", ip) then
- return playerId
- end
- end
- end
- local function getobject(objectId)
- return objectId and _G.getobject(objectId) or nil
- end
- -- hides a phasor bug where player 1 gets output from privatesay in their console...
- local function privatesay(playerId, message, appendServer)
- _G.privatesay(playerId, message, appendServer)
- if getplayer(0) then
- 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 ")
- end
- end
- local function privateSayAdmins(message)
- for playerId = 0,15 do
- if getplayer(playerId) and PlayerClass[playerId].admin_entry then
- sendconsoletext(playerId, message)
- privatesay(playerId, message)
- end
- end
- end
- local function getname(playerId)
- return playerId and _G.getname(playerId) or "the Server"
- end
- local function getMorePowerfulAdmin(adminEntry1, adminEntry2)
- local access1 = #access_table[adminEntry1.level]
- local access2 = #access_table[adminEntry2.level]
- return access1 > access2 and adminEntry1 or access1 < access2 and adminEntry2 or access1 > 0
- end
- local function lookupAdminEntry(playerId)
- local ip = getip(playerId)
- local retIndex = gethash(playerId)
- local highestEntry = admin_table[retIndex]
- local morePowerfulAdmin
- for index,thisAdmin in next,admin_table do
- if thisAdmin.type == "ip" and netMatch(index, ip) then
- morePowerfulAdmin = highestEntry and getMorePowerfulAdmin(thisAdmin, highestEntry) or thisAdmin
- if type(morePowerfulAdmin) == "table" then
- highestEntry = morePowerfulAdmin
- retIndex = index
- end
- end
- end
- return highestEntry, highestEntry and retIndex
- end
- -- Table Methods and Metamethods.
- function getOrCreateIdentities(hash, ip, name, playerId) -- arguments: hash, ip, name, playerId
- local length, probably_unique_name, ip_addresses, names, hash_identity, ip_identity, name_identity
- hash_identity = identities[hash]
- ip_identity = identities[ip]
- name_identity = identities[name]
- -- check the ip range to see if it matches an already existing entry.
- if not ip_identity then
- for ip_key,v in next,identities do
- if validate_ipv4(ip_key) and netMatch(ip, ip_key) then
- ip_identity = identities[ip_key]
- break
- end
- end
- end
- if hash_identity then
- if not ip_identity then
- ip_addresses = hash_identity.ip_addresses
- length = #ip_addresses+1
- ip_addresses[length] = ip
- ip_addresses[ip] = length
- for i = 1,#ip_addresses do
- ip_identity = identities[ip_addresses[i]]
- if ip_identity then
- identities[ip] = ip_identity
- break
- end
- end
- end
- if not name_identity then
- names = hash_identity.names
- length = #names+1
- names[length] = name
- names[name] = length
- for i = 1,#names do
- name_identity = identities[names[i]]
- if name_identity then
- identities[name] = name_identity
- break
- end
- end
- end
- hash_identity.playerId = playerId
- end
- if ip_identity then
- if not hash_identity and not sharedhashes[hash] then
- hash_identity = identities[ip]
- identities[hash] = hash_identity
- identities[ip].hash = hash
- end
- if not name_identity and not randomNames[name] then
- names = ip_identity.names
- length = #names+1
- names[length] = name
- names[name] = length
- for i = 1,#names do
- name_identity = identities[names[i]]
- if name_identity then
- identities[name] = name_identity
- break
- end
- end
- end
- ip_identity.playerId = playerId
- end
- if name_identity then
- if not hash_identity and not sharedhashes[hash] then
- hash = name_identity.hash
- hash_identity = identities[hash]
- identities[hash] = hash_identity
- end
- if not ip_identity then
- ip_addresses = hash_identity.ip_addresses
- length = #ip_addresses+1
- ip_addresses[length] = ip
- ip_addresses[ip] = length
- for i = 1,#ip_addresses do
- ip_identity = identities[ip_addresses[i]]
- if ip_identity then
- identities[ip] = ip_identity
- break
- end
- end
- end
- name_identity.playerId = playerId
- end
- ::CreateIdentity::
- --Create a new identity for this new player.
- if not ip_identity then
- identity = {playerId = playerId}
- --identity.index = identifier
- identity.hash = sharedhashes[hash] and {} or hash
- identity.ip_addresses = {ip, [ip] = 1}
- identity.names = randomNames[name] and {} or {name, [name] = 1}
- identities[hash] = identity
- identities[ip] = identity
- identities[name] = identity
- identity.disarmed = false
- identity.tempadmin = false
- identity.spamcounter = 0
- identity.rcon_fails = 0
- identity.rconfail_timer = -1
- identity.muted = false
- identity.playerId = playerId
- -- Calculate unique identity id by count.
- identities[#identities+1] = identity
- --registered_names[name] = identity -- automatically register this name to this Hash/IP
- return identity, identity, identity
- end
- return hash_identity, ip_identity, name_identity
- end
- -- Not currently using this, if I remember correctly.
- --[[function PlayerClass:__newindex(key, value)
- if rawget(self, key) ~= nil then
- rawset(self, key, value)
- return
- end
- local hash_identity = identities[rawget(self, "hash")]
- if hash_identity then rawset(hash_identity, key, value) end
- local ip_identity = identities[rawget(self, "ip")]
- if ip_identity then rawset(ip_identity, key, value) end
- local name_identity = identities[rawget(self, "name")]
- if name_identity then rawset(name_identity, key, value) end
- end--]]
- function PlayerClass:__index(key)
- --hprintf(TM.__tostring(PlayerClass[2]))
- local identity = rawget(self, "hash_identity") or rawget(identities, rawget(self, "hash"))
- if identity then
- return rawget(identity, key)
- end
- local fallback_identity = rawget(self, "ip_identity") or rawget(identities, rawget(self, "ip"))
- if fallback_identity then
- return rawget(fallback_identity, key)
- end
- identity = rawget(self, "name_identity") or rawget(identities, rawget(self, "name"))
- if identity then
- return rawget(identity, key)
- end
- -- This will be used if all player identifiers are not unique
- return rawget(fallback_identity, key)
- end
- function PlayerClass:Initialize(playerId)
- local player = rawget(PlayerClass, playerId)
- local hash, ip, name = gethash(playerId), getip(playerId), getname(playerId)
- rawset(player, "admin_entry", lookupAdminEntry(playerId) or false)
- player.drones:deleteEntries()
- rawset(player, "hash", hash)
- rawset(player, "ip", ip)
- rawset(player, "name", name)
- -- Update our identities.
- local hash_identity, ip_identity, name_identity = getOrCreateIdentities(hash, ip, name, playerId)
- rawset(player, "hash_identity", hash_identity)
- rawset(player, "ip_identity", ip_identity)
- rawset(player, "name_identity", name_identity)
- rawset(player, "afk", false)
- rawset(player, "bulletmode", false)
- rawset(player, "colorspawn", false)
- rawset(player, "crouch", false)
- rawset(player, "dmgmultiplier", 1)
- rawset(player, "godmode", false)
- rawset(player, "ghostmode", false)
- rawset(player, "invisible", false)
- rawset(player, "hidden", false)
- rawset(player, "objspawnid", false)
- rawset(player, "player_struct", getplayer(playerId) or false)
- rawset(player, "playerId", playerId)
- rawset(player, "playerIndex", resolveplayer(playerId) or -1)
- rawset(player, "tbagname", "")
- rawset(player, "x", 0)
- rawset(player, "y", 0)
- rawset(player, "z", 0)
- return player
- end
- local function GetGameAddresses(game)
- if _SERVERAPP == "Sapp" then
- addresses = { -- check these against the module to confirm they're all the same (these should take preference)
- stats_globals = read_dword(sig_scan("33C0BF??????00F3AB881D") + 0x3), -- Confirmed. (Thanks Giraffe)
- ctf_globals = read_dword(sig_scan("C6000083C0303D??????00")+8), -- Confirmed.
- slayer_globals = read_dword(sig_scan("5733C0B910000000BFE8E05B00F3ABB910000000") + 19), -- Confirmed,
- oddball_globals = read_dword(sig_scan("BF??????00F3ABB951000000")+0x1), -- Confirmed.
- koth_globals = read_dword(sig_scan("BF??????00F3ABB96B000000")+0x1), -- Confirmed.
- race_globals = read_dword(sig_scan("BF??????00F3ABB952000000")+0x1), -- Confirmed.
- race_locs = 0x5F5078,
- gametype_base = read_dword(sig_scan("B9360000008BF3BF78545F00")+0x8), -- Confirmed.
- network_struct = read_dword(sig_scan("F3ABA1????????BA????????C740??????????E8????????668B0D") + 3),
- player_header_pointer = read_dword(sig_scan("DDD8A1??????008944244835") + 0x3), -- Confirmed (Thanks Giraffe)
- object_header_pointer = read_dword(sig_scan("8B0D????????8B513425FFFF00008D") + 2), -- Confirmed. (Thanks 002)
- collideable_objects_pointer = 0x6C69F4,
- map_header_base = 0x6E2C84,
- banlist_header = read_dword(sig_scan("A3??????00A1??????0033DB3BC3")+1), -- Confirmed.
- game_globals = nil, -- Don't care.
- gameinfo_header = read_dword(sig_scan("A1????????8B480C894D00") + 0x1), -- Confirmed. (Thanks Wizard)
- mapcycle_header = 0x598A8C,
- network_server_globals = 0x61FB44,
- hash_table_base = 0x5AFB14, -- Untested.
- -- Strings (Thanks to Giraffe for all the sigs in this section!)
- broadcast_version_address = read_dword(sig_scan("751768??????0068??????00BA") + 0x3), -- Confirmed.
- version_info_address = nil, -- Don't care.
- broadcast_game_address = read_dword(sig_scan("CCCCBA??????002BD08A08") + 0x3), -- Confirmed (halor = PC, halom = CE)
- server_ip_argument = read_dword(sig_scan("BA??????008BC72BD78A08880C024084C975F68B442404") + 0x1), -- Confirmed.
- server_port_address = read_dword(sig_scan("668B0D??????000BF2C605") + 0x3), -- Confirmed.
- server_path_address = read_dword(sig_scan("0000BE??????005657C605") + 0x3), -- Confirmed.
- computer_name_address = read_dword(sig_scan("68??????0068??????0068000401006A00") + 0x1), -- Confirmed
- profile_path_address = read_dword(sig_scan("68??????008D54245468") + 0x1), -- Confirmed.
- map_name_address =read_dword(sig_scan("66A3??????00890D??????00C3") + 0x2), -- Confirmed. (Full name)
- hardware_info_address = read_dword(sig_scan("BE??????008BC68B4DF064890D000000005F5E5B8BE55DC36A0C") + 0x1), -- Confirmed.
- map_name_address2 = read_dword(sig_scan("B8??????00E8??????0032C983F813") + 0x1), -- Confirmed. (File name)
- server_password_address = read_dword(sig_scan("F3ABA3??????00A3??????00A2??????00C705") + 0x3), -- Confirmed.
- logfile_path_address = read_dword(sig_scan("740ABB????5C00E8????0300") + 0x3), -- Confirmed. (CE Only)
- banlist_path_address = read_dword(sig_scan("68??????00E8??????0083C41068") + 0x1), -- Confirmed.
- banlist_path_address2 = read_dword(sig_scan("CCCCC605??????0000E8??????0085C0") + 0x4), -- Confirmed.
- --Patches
- rcon_password_address = read_dword(sig_scan("7740BA??????008D9B000000008A01") + 0x3), -- Confirmed.
- rcon_failed_address = read_dword(sig_scan("B8????????E8??000000A1????????55") + 1), -- Found by 002
- kill_message_address = read_dword(sig_scan("8B42348A8C28D500000084C9") + 3), -- Found by sehe (Write to 0x03EB01B1)
- color_patch1 = read_dword(sig_scan("741F8B482085C9750C")), -- Found by 002 (Write to 235 if not 0)
- color_patch2 = read_dword(sig_scan("EB1F8B482085C9750C")), -- Found by 002 (Write to 235)
- nonslayer_score_patch = sig_scan("8B??3883C404????74??57FFD0")+0x8, -- 0xEB = patched, 0x74 = normal
- slayer_score_patch = sig_scan("74178B94242808000052518B8C24280800005157FFD083C4108B8424240800003BF8530F94C383FFFF") -- 0xEB = patched, 0x74 = normal
- }
- --[[while true do
- cprint("nonslayer: " .. tostring(addresses.nonslayer_score_patch) .. " slayer: " .. tostring(addresses.slayer_score_patch))
- end--]]
- elseif game == "PC" then
- addresses = {
- -- Structs/headers.
- stats_header = 0x639720,
- stats_globals = 0x639898,
- ctf_globals = 0x639B98,
- slayer_globals = 0x63A0E8,
- oddball_globals = 0x639E58,
- koth_globals = 0x639BD0,
- race_globals = 0x639FA0,
- race_locs = 0x670F40,
- gametype_base = 0x671340,
- network_struct = 0x745BA0,
- camera_base = 0x69C2F8,
- player_header_pointer = 0x75ECE4,
- obj_header_pointer = 0x744C18,
- collideable_objects_pointer = 0x744C34,
- map_header_base = 0x630E74,
- banlist_header = 0x641280,
- game_globals = "???", -- (???) Why do I not have this for PC?
- gameinfo_header = 0x671420,
- mapcycle_header = 0x614B4C,
- network_server_globals = 0x69B934,
- sockaddr_pointer = 0x6A1F08,
- flags_pointer = 0x6A590C,
- hash_table_base = 0x6A2AE4,
- -- String/Data Addresses.
- init_file_address = 0x8EB38,
- broadcast_version_address = 0x5DF840,
- version_info_address = 0x5E02C0,
- broadcast_game_address = 0x5E4768,
- mapcycle_timeout = 0x614AC0,
- public_value_address = 0x6164C0,
- server_port_address = 0x625230,
- timelimit_address = 0x626630,
- server_path_address = 0x62C390,
- computer_name_address = 0x62CD60,
- profile_path_address = 0x635610,
- map_name_address = 0x63BC78,
- computer_specs_address = 0x662D04,
- map_name_address2 = 0x698F21,
- server_password_address = 0x69B93C,
- banlist_path_address = 0x69B950,
- rcon_password_address = 0x69BA5C,
- -- Patches
- nonslayer_score_patch = 0x47F382, -- 0xEB = patched, 0x74 = normal
- slayer_score_patch = 0x47F5D5, -- 0xEB = patched, 0x74 = normal
- ctf_msgs_patch = 0x481545, -- 0xEB = patched, 0x74 = normal
- color_patch = 0x4828FE, -- 0xEB = patched, 0x74 = normal
- devmode_patch1 = 0x4A4DBF, -- 0xEB = patched, 0x74 = normal
- devmode_patch2 = 0x4A4E7F, -- 0xEB = patched, 0x74 = normal
- servername_patch = 0x517D6B, -- 0x9090 = patched, 0x4B74 = normal
- hash_duplicate_patch = 0x59C518, -- 0x9090 = patched, 0xFD3B = normal
- hashcheck_patch = 0x59c280, -- 0xEB = patched, 0x74 = normal
- versioncheck_patch = 0x5152E7 -- 0xEB = patched, 0x7D = normal
- }
- elseif game == "CE" then
- addresses = {
- -- Structs/headers.
- stats_header = 0x5BD740,
- stats_globals = 0x5BD8B8,
- ctf_globals = 0x5BDBB8,
- slayer_globals = 0x5BE108,
- oddball_globals = 0x5BDE78,
- koth_globals = 0x5BDBF0,
- race_globals = 0x5BDFC0,
- race_locs = 0x5F5098,
- gametype_base = 0x5F5498,
- network_struct = 0x6C7980,
- camera_base = 0x62075C,
- player_globals = 0x6E1478, -- From OS.
- player_header_pointer = 0x6E1480,
- obj_header_pointer = 0x6C69F0,
- collideable_objects_pointer = 0x6C6A14,
- map_header_base = 0x6E2CA4,
- banlist_header = 0x5C52A0,
- game_globals = 0x61CFE0, -- (???)
- gameinfo_header = 0x5F55BC,
- mapcycle_header = 0x598A8C,
- network_server_globals = 0x61FB64,
- sockaddr_pointer = 0x626388,
- hash_table_base = 0x5AFB34,
- -- String/Data Addresses.
- init_file_address = 0x8EB26,
- broadcast_version_address = 0x564B34,
- version_info_address = 0x565104,
- broadcast_game_address = 0x569EAC,
- mapcycle_timeout = 0x598A00,
- public_value_address = 0x59A424,
- server_port_address = 0x5A91A0,
- timelimit_address = 0x5AA5B0,
- server_path_address = 0x5B0670,
- computer_name_address = 0x5B0D40,
- profile_path_address = 0x5B9630,
- map_name_address = 0x5BFC98,
- computer_specs_address = 0x5E6E5C,
- map_name_address2 = 0x61D151,
- server_password_address = 0x61FB6C,
- banlist_path_address = 0x61FB80,
- rcon_password_address = 0x61FC8C,
- -- Patches
- nonslayer_score_patch = 0x45BCB0, -- 0xEB = patched, 0x74 = normal
- slayer_score_patch = 0x45BE15, -- 0xEB = patched, 0x74 = normal
- ctf_msgs_patch = 0x45DA95, -- 0xEB = patched, 0x74 = normal
- color_patch = 0x45EB5E, -- 0xEB = patched, 0x74 = normal
- devmode_patch1 = 0x47DF0C, -- 0xEB = patched, 0x74 = normal
- devmode_patch2 = 0x47DFBC, -- 0xEB = patched, 0x74 = normal
- servername_patch = 0x4CE0CD, -- 0x9090 = patched, 0x4B74 = normal
- hash_duplicate_patch = 0x5302E8, -- 0x9090 = patched, 0xFD3B = normal
- hashcheck_patch = 0x530130, -- 0xEB = patched, 0x74 = normal
- versioncheck_patch = 0x4CB587, -- 0xEB = patched, 0x7D = normal
- }
- end
- end
- -- This is my ingenius way to execute a command and bypass ALL of my code.
- -- So I can do sv_kick without having to worry about creating an infinite loop.
- local function halo_svcmd(command, retBool)
- dont_call_onservercommand = true
- --print("BEFORE HALO_SVCMD")
- local response = svcmd(command, retBool)
- --print("AFTER HALO_SVCMD")
- dont_call_onservercommand = false
- return retBool and response
- end
- local function halo_svcmdplayer(command, playerId, retBool)
- dont_call_onservercommand = true
- --print "BEFORE HALO_SVCMDPLAYER"
- local response = svcmdplayer(command, playerId, retBool)
- --print "AFTER HALO_SVCMDPLAYER"
- dont_call_onservercommand = false
- return retBool and response
- end
- local function svcmd(command, retBool)
- --print "BEFORE SVCMD"
- if OnServerCommandAttempt(nil, command) ~= false then
- --print "AFTER SVCMD"
- return _G.svcmd(command, retBool)
- end
- end
- local function svcmdplayer(command, playerId, retBool)
- --print("BEFORE SVCMDPLAYER)
- if OnServerCommandAttempt(playerId, command) ~= false and OnServerCommand(playerId, command) ~= false then
- --print("AFTER SVCMDPLAYER)
- return halo_svcmd(command, retBool) or ""
- end
- end
- math.randomseed(ceil(os.clock()) + os.time())
- local getsuckyrand = math.random
- getsuckyrand(1, 10) getsuckyrand(1, 10) getsuckyrand(1, 10)
- --Low and High are INCLUSIVE.
- local function rand(low, high)
- low = assert(tonumber(low), "bad argument #1 to 'rand' (number expected, got " .. type(low) .. ")")
- high = assert(tonumber(high), "bad argument #2 to 'rand' (number expected, got " .. type(high) .. ")")
- return getsuckyrand(low, high)
- end
- local getrandomnumber = rand
- -- I am having weird issues with resolveplayer not working correctly, so I'm overriding it.
- local function resolveplayer(playerId)
- return playerId and PlayerClass[playerId].playerIndex
- end
- -- This function will get the XYZ coordinates of an object, and return them as 3 separate variables.
- -- It will also determine if the object has a parent (i.e player in a vehicle) and return those coords instead.
- -- I don't trust Phasor's getobjectcoords, and this way I know exactly how it will work.
- local function getobjectcoords(objectId)
- local m_object = getobject(objectId)
- local vehicleObjId = readdword(m_object + 0x11C)
- local m_vehicleObj = getobject(vehicleObjId)
- -- Replace m_object with vehicle object struct (if there is one)
- m_object = m_vehicleObj or m_object
- return readfloat(m_object + 0x5C),readfloat(m_object + 0x60),readfloat(m_object + 0x64)
- end
- -- This is the same as getplayerobjectid except it returns BOTH the player's object struct and playerObjId
- -- Returns the object struct and the object ID, or nil.
- local function getplayerobject(playerId)
- local playerObjId = playerObjId or getplayerobjectid(playerId)
- return getobject(playerObjId), playerObjId
- end
- -- Gets the object ID of the player's vehicle.
- -- Accepts argument 'playerId' (memory ID)
- -- Returns the vehicle's object ID, or nil
- local function getplayervehicleid(playerId)
- local m_playerObj = getplayerobject(playerId)
- return m_playerObj and readdword(m_playerObj + 0x11C)
- end
- -- This is the same as getplayervehicleid except it returns BOTH the vehicle's object struct and vehicleObjId.
- -- Returns the vehicle's object struct and vehicle's object ID, or nil.
- local function getplayervehicle(playerId)
- local vehicleObjId = getplayervehicleid(playerId)
- return getobject(vehicleObjId), vehicleObjId
- end
- -- Gets the object ID of the player's weapon.
- -- Accepts arguments 'playerId' (memory ID) and 'slot' (weapon slot) which is a number from 0 to 3.
- -- Slot is an optional argument. If not passed, then getplayerweaponid returns player's current weapon ID.
- -- Returns the weapon's object ID, or 0xFFFFFFFF if no weapon, or nil if the player is dead
- local function getplayerweaponid(playerId, slot)
- local m_playerObj = getplayerobject(playerId)
- if not m_playerObj then
- return
- end
- -- Return vehicle's weapon if they are in a vehicle.
- local m_vehicleObj = getplayervehicle(playerId)
- if m_vehicleObj then
- return readdword(m_vehicleObj + 0x2F8)
- end
- -- Return current weapon if no slot passed.
- if not slot then
- return readdword(m_playerObj + 0x118)
- end
- -- Return weapon at the specified slot.
- return readdword(m_playerObj + 0x2F8 + slot*4)
- end
- -- This is the same as getplayerweaponid except it returns BOTH the weapon's object struct and weaponObjId.
- -- Returns the weapon's object struct and weapon's object ID, or nil.
- local function getplayerweapon(playerId, slot)
- local weaponObjId = getplayerweaponid(playerId, slot)
- return getobject(weaponObjId), weaponObjId
- end
- -- This function will determine if the given playerId is currently in a vehicle or not.
- -- This function will return a boolean.
- -- This function was created because I was having problems with Phasor's isinvehicle function.
- local function isinvehicle(playerId)
- return not not getplayervehicle(playerId)
- end
- local function cleanupdrones(playerId)
- local player = PlayerClass[playerId]
- local vehicleObjId
- for i = 1,#player.drones do vehicleObjId = player.drones[i]
- if getobject(vehicleObjId) then
- destroyobject(vehicleObjId)
- end
- player.drones[i] = nil
- end
- end
- local function setspeed(playerId, speed)
- local m_player = assert(getplayer(playerId), "bad argument #1 to 'setspeed' (valid playerId expected, got '" .. type(playerId) .. "')")
- speed = assert(tonumber(speed), "bad argument #2 to 'setspeed' (number expected, got '" .. type(speed) .. "')")
- writefloat(m_player + 0x6C, speed and speed < 999999999999999999999999999999 and speed or 999999999999999999999999999999)
- end
- -- This function will set a player's color
- -- Accepts playerId, and color carried as a number enumerator.
- local function setcolor(playerId, color)
- local m_player = assert(getplayer(playerId), "bad argument #1 to 'setspeed' (valid playerId expected, got '" .. type(playerId) .. "')")
- color = assert(tonumber(color), "bad argument #2 to 'setcolor' (number expected, got '" .. type(color) .. "')")
- writebyte(m_player + 0x60, color)
- local m_playerObj, playerObjId = getplayerobject(playerId)
- if not m_playerObj then
- return
- end
- local player = PlayerClass[playerId]
- local x,y,z = getobjectcoords(playerObjId)
- player.colorspawn = true
- player.x,player.y,player.z = x,y,z
- destroyobject(playerObjId)
- end
- -- This local function gets the player's memory ID from their object struct
- -- Accepts the object ID of the player as an argument
- -- Returns the playerId, or nil.
- local function objectidtoplayer(objectId)
- local m_object = getobject(objectId)
- if m_object then
- local playerId = readword(m_object + 0xC0)
- local m_player = getplayer(playerId)
- if m_player then
- return playerId
- end
- end
- end
- --[[ General lua functions ]]--
- local function round(val, place)
- place = place or 0 return floor(val * (10 ^ place) + 0.5) * (10 ^ -place)
- end
- local function formatTime(time)
- time = tonumber(time)
- if time == -1 then
- return "--"
- elseif time then
- local temp = time
- local centuries = floor(temp / 3153600000)
- temp = temp - centuries * 3153600000
- local years = floor(temp / 31536000)
- temp = temp - years * 31536000
- local weeks = floor(temp / 604800)
- temp = temp - weeks * 604800
- local days = floor(temp / 86400)
- temp = temp - days * 86400
- local hours = floor(temp / 3600)
- temp = temp - hours * 3600
- local minutes = floor(temp / 60)
- temp = temp - minutes * 60
- local seconds = floor(temp)
- return format("%02d:%02d:%02d:%02d:%02d:%02d", years, weeks, days, hours, minutes, seconds)
- else
- return time
- end
- end
- local function wordtotime(timeStr, bancount)
- local length = #timeStr
- local time
- -- Check if timeStr is in the correct format before we do anything.
- if tonumber(sub(timeStr, 1, length-1)) and match(sub(timeStr, length, length), "[cywdhms]") then
- time = 0
- local num = ""
- local holder, tempnum, char
- for i = 1,length do
- char = sub(timeStr, i, i)
- if tonumber(char) then
- num = num .. char
- else
- tempnum = tonumber(num)
- holder = 0
- holder = char == "s" and tempnum
- holder = char == "m" and tempnum * 60 or holder
- holder = char == "h" and tempnum * 3600 or holder
- holder = char == "d" and tempnum * 86400 or holder
- holder = char == "w" and tempnum * 604800 or holder
- holder = char == "y" and tempnum * 31536000 or holder
- holder = char == "c" and tempnum * 3153600000 or holder
- holder = holder or 1
- time = time + holder
- end
- end
- if time > 0 then
- return time, char
- end
- end
- time = tonumber(timeStr)
- if time == 0 and bancount then
- return ban_penalty[bancount], "?"
- elseif time then
- return time, "*"
- end
- end
- local function timetoword(time)
- time = tonumber(time)
- if time then
- local returntime = ""
- local centuries = floor(time / 3153600000)
- time = time - centuries * 3153600000
- local years = floor(time / 31536000)
- time = time - years * 31536000
- local weeks = floor(time / 604800)
- time = time - weeks * 604800
- local days = floor(time / 86400)
- time = time - days * 86400
- local hours = floor(time / 3600)
- time = time - hours * 3600
- local minutes = floor(time / 60)
- time = time - minutes * 60
- local seconds = floor(time)
- returntime = seconds > 0 and (seconds == 1 and "1 second" or seconds .. " seconds") or returntime
- returntime = minutes > 0 and (minutes == 1 and "1 minute" or minutes .. " minutes " .. returntime) or returntime
- returntime = hours > 0 and (hours == 1 and "1 hour" or hours .. " hours " .. returntime) or returntime
- returntime = days > 0 and (days == 1 and "1 day" or days .. " days " .. returntime) or returntime
- returntime = weeks > 0 and (weeks == 1 and "1 week" or weeks .. " weeks " .. returntime) or returntime
- returntime = years > 0 and (years == 1 and "1 year" or years .. " years " .. returntime) or returntime
- returntime = centuries > 0 and (centuries == 1 and "1 century" or centuries .. " centuries " .. returntime) or returntime
- return returntime ~= "" and returntime or "0 seconds"
- end
- end
- local function getTimeAndReason(timeandreason)
- local words = tokenizecmdstring(timeandreason)
- local count = #words
- local time
- local reasons = {}--TM.New()
- local timetypes_used = ""
- local word, addTime, timetype, reasons_started
- for i = 1,count do word = words[i]
- if not reasons_started then
- addTime, timetype = wordtotime(word)
- if timetype and (find(timetypes_used, timetype) or find(timetypes_used, "[%?%*]")) then
- 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"
- elseif addTime then
- time = (time or 0) + addTime
- if not find(timetypes_used, timetype) then
- timetypes_used = timetypes_used .. timetype
- end
- else
- reasons_started = true
- reasons[#reasons+1] = word
- end
- else
- reasons[#reasons+1] = word
- end
- end
- return (time or -1), (reasons[2] and concat(reasons, " ") or reasons[1] or "None Given")
- end
- local function gettag(type_or_id, tagname)
- if tagname then
- return tag_table[type_or_id] and tag_table[type_or_id][tagname] or nil
- elseif tag_table[type_or_id] then
- return tag_table[type_or_id].tag_class, tag_table[type_or_id].tag_name
- end
- end
- local function getObjType(objectId)
- local m_object = getobject(objectId)
- return m_object and readword(m_object + 0xB4) or nil
- end
- local function resetweapons(playerId)
- if getplayerweapon(playerId) then
- for slot = 0,3 do
- local m_weapon, weaponObjId = getplayerweapon(playerId, slot)
- if m_weapon then
- destroyobject(weaponObjId)
- end
- end
- end
- local obj_tag_id = readdword(true and getplayerobject(playerId)) -- Confirmed with HMT. Tag Meta ID / MapID / TagID.
- local tag_address = gettagaddress(obj_tag_id)
- local address_tag_data = readdword(tag_address + 0x14)
- local number_of_starting_weapons = readdword(address_tag_data, 0x2D8)
- local tagdata_unit_weapons = readdword(address_tag_data + 0x2D8+0x4)
- for i = 0,3 do
- local weapon_mapId = readdword(tagdata_unit_weapons + i*0x24 + 0xC)
- if weapon_mapId and weapon_mapId ~= 0 then
- assignweapon(playerId, createobject(weapon_mapId, 0, 60, false, 3, 2, 1))
- end
- end
- --[[local address_starting_profile = readdword(address_tag_data + 0x348 + 0x4)
- local primary_weapon_mapId = readdword(address_tag_data + 0x348 + 0x4 + 0x28 + 0xC)
- local secondary_weapon_mapId = readdword(address_tag_data + 0x348 + 0x4 + 0x3C + 0xC)
- say(tostring(primary_weapon_mapId))
- if primary_weapon_mapId then
- assignweapon(playerId, createobject(primary_weapon_mapId, 0, 60, false, 3, 2, 1))
- end
- if secondary_weapon_mapId then
- assignweapon(playerId, createobject(secondary_weapon_mapId, 0, 60, false, 1, 2, 3))
- end--]]
- end
- local function ResetPlayer(playerId)
- local player = PlayerClass[playerId]
- local m_playerObj, playerObjId = getplayerobject(playerId)
- if playerObjId ~= 0xFFFFFFFF and m_playerObj then
- player.godmode = false
- cleanupdrones(playerId)
- resetweapons(playerId)
- end
- player.bulletmode = false
- player.disarmed = false
- player.dmgmultiplier = 1
- player.ghostmode = false
- player.hidden = false
- player.objspawnid = false
- player.suspended = false
- end
- local function remoteBanCheck(ban_entry)
- local centralbanlist = defaults.remote_bansystem
- return not centralbanlist or (ban_entry.remote and centralbanlist.mode >= 1 or not ban_entry.remote and centralbanlist.mode ~= 2)
- end
- local function findBanlistEntry(name, hash, ip, bantype)
- local retBanEntry
- local cur_time = os.time()
- for id = 1,#ban_table do ban_entry = ban_table[id]
- if remoteBanCheck(ban_entry) then
- if not ban_entry.time or (ban_entry.time == -1 or ban_entry.time > cur_time) then
- if not bantype or bantype == ban_entry.type then
- if ban_entry.type == "hash" and ban_entry.hash == hash or ban_entry.type == "ip" and netMatch(ban_entry.ip, ip) then
- --hprintf("NAME: " .. tostring(ban_entry.name) .. " REMOTECHECK: " .. tostring(remoteBanCheck(ban_entry)) .. " BANENTRY TIME: " .. tostring(ban_entry.time) .. " CURTIME: " .. tostring(cur_time))
- return ban_entry
- elseif (ban_entry.type == "name" and ban_entry.name == name) or ban_entry.type == "chat" and (ban_entry.hash == hash or netMatch(ban_entry.ip, ip)) then
- retBanEntry = ban_entry
- end
- end
- end
- end
- end
- if retBanEntry then
- --hprintf("NAME: " .. tostring(retBanEntry.name) .. " REMOTECHECK: " .. tostring(remoteBanCheck(retBanEntry)) .. " BANENTRY TIME: " .. tostring(retBanEntry.time) .. " CURTIME: " .. tostring(cur_time))
- end
- return retBanEntry
- end
- local function punishIfOnBanlist(playerId)
- local ban_entry = findBanlistEntry(getname(playerId), gethash(playerId), getip(playerId))
- if ban_entry then
- if ban_entry.type == "hash" or ban_entry.type == "ip" then
- tempBanPlayer(resolveplayer(playerId))
- elseif ban_entry.type == "chat" then
- PlayerClass[playerId].muted = true
- elseif ban_entry.type == "name" and ban_entry.name == name then
- svcmd("sv_kick " .. resolveplayer(playerId) .. " Found on the Name Banlist.")
- end
- return true
- end
- return false
- end
- local function loadBanTextEntry(line, bantype, filename)
- -- Sometimes a random blank line appears in the file, let's make sure not to error for those
- if not match(line, "%g%g%g+") or sub(line, 1, 1) == "#" then
- return
- end
- local t = {}--TM.New()
- local pos, endline, timestr, formatBantype, count, unique_index
- -- create a new table for the ban entry
- local b = {}--TM.New()
- -- A line can ONLY have the following format: Name,HashOrIp[:IP][,Bancount[,Time[,Bantype]]]
- -- The exception is namebans, which will always be: Name[,,,,Bantype] where Bantype can only be the string 'name' and nothing else
- -- Examples of valid chat bans:
- -- ,123456789abcdef123456789abcdef:127.0.0.1
- -- wizard,123456789abcdef123456789abcdef:127.0.0.1
- -- wizard,123456789abcdef123456789abcdef:127.0.0.1,1
- -- wizard,123456789abcdef123456789abcdef:127.0.0.1,1,--
- -- wizard,123456789abcdef123456789abcdef:127.0.0.1,1,--,chat
- -- wizard,123456789abcdef123456789abcdef:127.0.0.1,1,2015-03-27 04:10:52,chat,he was spamming
- -- First half: Match chatban (name,hash:ip) or hashban (name,hash) or nameban (name[,,,,bantype])
- -- if this matches then this is a chatban
- 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+)[:,]([^,]+)(.-)$")
- b.ip = b.ip and (b.ip == "" and b.ip or validate_ipv4(b.ip))
- if b.hash and b.ip then
- formatBantype = "chat"
- unique_index = b.hash .. (b.ip or "") .. "chat"
- goto ReadSecondHalf
- end
- -- this will match a hash ban
- 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+)(.*)$")
- if b.hash then
- formatBantype = "hash"
- unique_index = b.hash .. "hash"
- goto ReadSecondHalf
- end
- -- this will match an IP ban.
- b.name,b.ip,endline = match(line, "^(.-[^,]?),([^,]+)(.-)$")
- b.ip = b.ip and validate_ipv4(b.ip)
- if not b.ip then
- -- sapp's ipbans.txt
- b.name,b.ip,b.reason = match(line, "^(.-[^:]?):([^:]+)(.-)$")
- b.ip = b.ip and validate_ipv4(b.ip)
- end
- if b.ip then
- formatBantype = "ip"
- unique_index = b.ip .. "ip"
- goto ReadSecondHalf
- end
- -- and lastly this will match a name ban.
- b.name,b.type = match(line, "^(.-),+(%w-)")
- if b.name then
- formatBantype = "name"
- unique_index = b.name .. "name"
- goto ReadSecondHalf
- end
- error(filename .. " is formatted incorrectly! Line: " .. line)
- ::ReadSecondHalf::
- -- This part matches the rest of the line. Here are some examples that it will match (starting from the end of the string)
- -- (nothing here)
- -- ,1 ,(count)
- -- ,5,-- ,(count),(infinite time)
- -- ,2,2015-06-13 05:29:51,chat ,(count),(time),(bantype)
- -- ,3,-1,chat,offensive language ,(count),(infinite time),(bantype),(reason)
- if not b.reason and endline and endline ~= "" then
- count,timestr,b.type,b.reason = match(endline, "^,(%d+),?([%d%s%-:]*),?(%w*),?(.-)$")
- b.reason = b.reason and b.reason ~= "" and gsub(b.reason, ",", "") or "None Given"
- -- these don't exist in a nameban
- elseif not b.type or b.type == "" then
- b.count = nil
- b.type = nil
- b.reason = nil
- timestr = nil
- end
- -- Check if the ban types are what they should be.
- -- I try to make my code stop using tons of checks, but this is the one time where it actually needs them
- b.type = b.type and b.type ~= "" and b.type
- assert(not b.type or b.type == formatBantype, filename .. " is formatted incorrectly! expected bantype " .. formatBantype .. " instead got " .. tostring(b.type) .. " on line: " .. line)
- assert(not bantype or bantype == formatBantype, filename .. " should only have '" .. tostring(bantype) .. "' bans. Ban of type '" .. formatBantype .. "' was found in the line: " .. line)
- b.type = formatBantype
- if timestr then
- -- Match the time.
- -- Time format: YYYY-MM-DD HH:MM:SS
- 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)$")
- -- convert 'ban expiration date' to 'seconds remaining until ban expires'
- if t.sec then
- b.time = os.time(t)
- -- else time will become -1 (infinite)
- else
- b.time = -1
- end
- -- time not specified in ban file, should be indefinite.
- else
- b.time = -1
- end
- if formatBantype ~= "name" then
- count = tonumber(count)
- b.count = count and count > 0 and count or 1
- end
- b.name = b.name == "" and "Unnamed" or gsub(b.name, ",", "")
- return b, unique_index
- end
- local function toBanTextEntry(entry)
- local time, bantype = entry.time, entry.type
- time = time == -1 and "--" or os.date("%Y-%m-%d %X", time)
- if bantype == "chat" then
- return entry.name..","..entry.hash..":"..(entry.ip or "1.2.3.4")..","..entry.count..","..time..","..bantype..","..entry.reason
- elseif bantype == "hash" then
- return entry.name..","..entry.hash..","..entry.count..","..time..","..bantype..","..entry.reason
- elseif bantype == "ip" then
- return entry.name..","..entry.ip..","..entry.count..","..time..","..bantype..","..entry.reason
- elseif bantype == "name" then
- return entry.name..",,,,"..bantype--..","..reason reasons don't exist for namebans.. yet
- end
- end
- local function download(host, file, port, output)
- port = port or 80
- local client = socket.tcp()
- client:settimeout(1, 'b')
- client:settimeout(1, 't')
- local status, status2, err = pcall(client.connect, client, host, port)
- if not status or not status2 then
- print("Connection failed with error : " .. err)
- return
- end
- coroutine.yield(client)
- -- Stop luasocket from blocking. You can play with these values
- client:settimeout(0.01, 'b')
- client:settimeout(0.01, 't')
- client:send("GET " .. file .. " HTTP/1.1\r\nHOST: " .. host .. ":" .. port .. "\r\n\r\n")
- local count = 0 -- counts number of bytes read
- local buffer, status, overflow
- while true do
- coroutine.yield(client)
- buffer, status, overflow = client:receive(65536)
- -- If buffer is not nil the call was a success (changed in LuaSocket 2.0)
- if buffer then
- --print("Successfully received " .. #buffer .. " without timeout.")
- output[#output+1] = buffer
- count = count + #buffer
- else
- --print('"' .. status .. '" with ' .. #overflow .. ' bytes of ' .. file)
- output[#output+1] = overflow
- count = count + #overflow
- end
- if status == "closed" then break end
- end
- client:close()
- end
- local function OnHttpReceive(output)
- local entry, unique_index, hash, ip, name, bantype
- local cur_time = os.time()
- for line in string.gmatch(output, "[^\r\n]*") do
- entry, unique_index = loadBanTextEntry(line, nil, "remote banlist")
- if entry and not ban_table[unique_index] then
- entry.remote = true
- ban_table[#ban_table+1] = entry
- ban_table[unique_index] = #ban_table
- if not entry.time or entry.time > cur_time then
- for playerId = 0,15 do
- if getplayer(playerId) then
- hash, ip, name = gethash(playerId), getip(playerId), getname(playerId)
- bantype = entry.type
- if bantype == "hash" and hash == entry.hash or entry.type == "ip" and netMatch(entry.ip, ip) then
- tempBanPlayer(resolveplayer(playerId))
- break
- elseif bantype == "chat" and (entry.hash == hash or netMatch(entry.ip, ip)) then
- PlayerClass[playerId].muted = true
- elseif bantype == "name" and entry.name == name then
- svcmd("sv_kick " .. resolveplayer(playerId) .. " Found in a Remote Ban Entry during a reload.")
- break
- end
- end
- end
- end
- end
- end
- end
- function handleHttpRequest(id, count, userdata) -- userdata = {[1] = coroutine thread, [2] = extraArg}
- --local start = os.clock()
- local status, res = coroutine.resume(userdata[1])
- --local finish = os.clock()
- --print("TIME: " .. (finish - start) * 1000 .. " ms")
- if not res then -- thread finished its task?
- --print("Finished")
- output = concat(userdata[3])
- local sizeOfFile = match(output, "Content%-Length: (%d+)")
- OnHttpReceive(sizeOfFile and sub(output, -sizeOfFile, -2) or output, userdata[2])
- http_receiving = false
- return false
- end
- return true
- end
- local function HTTPGET(host, file, port, extraArg)
- if http_receiving then
- return
- end
- local output = {}
- -- create coroutine, and return the handle for the timer.
- local timerID = registertimer(
- 1000,
- "handleHttpRequest",
- {
- coroutine.create(
- function()
- download(host, file, port, output)
- end
- ),
- extraArg,
- output
- }
- )
- http_receiving = true
- return timerID
- end
- local function reloadRemoteBanlist()
- local args = defaults.remote_bansystem
- HTTPGET(args.host, args.banfile, args.port)
- end
- local function loadBanFile(filename, bantype)
- local file = io.open(filename)
- if not file then
- return
- end
- local ban_entry, unique_index
- for line in file:lines() do
- ban_entry, unique_index = loadBanTextEntry(line, bantype, filename)
- -- Make sure this entry hasn't already been added before we add it.
- if ban_entry and not ban_table[unique_index] then
- ban_table[#ban_table+1] = ban_entry
- ban_table[unique_index] = #ban_table
- end
- end
- file:close()
- end
- -- Save all bans to banned.txt
- local function updateBanFiles(bantype)
- local writetbl = {}--TM.New()
- local entry
- local file, err = io.open(profilepath .. defaults.banlist_file .. ".txt", "w")
- local time, type
- local args = defaults.remote_bansystem
- for id = 1,#ban_table do entry = ban_table[id]
- if not args or (entry.remote and args.mode >= 1 or not entry.remote and args.mode ~= 2) then
- writetbl[#writetbl+1] = toBanTextEntry(entry)
- end
- end
- local output = concat(writetbl, "\n")
- file:write(output)
- file:close()
- -- Update the remote banlist.
- if args and args.mode >= 2 then
- http.request(args.http_source, "&bans=" .. output .. ",&unban=false")
- end
- end
- local function updateAdminFiles()
- local file = io.open(profilepath .. defaults.admin_file .. ".txt", "w")
- local writetbl = {}--TM.New()
- for index,admin_entry in next,admin_table do
- writetbl[#writetbl+1] = admin_entry.name .. "," .. index .. "," .. admin_entry.level .. "," .. admin_entry.type
- end
- file:write(concat(writetbl, "\n"))
- file:close()
- end
- local function loadAllAdminFiles()
- local timestamp = os.date"%Y_%m_%d_%H_%M_%S"
- local file = io.open(profilepath .. "admin.txt")
- if file then
- local name, hash, level
- for line in file:lines() do
- -- format the line (name, hash, level)
- 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*$")
- if hash then
- admin_table[hash] = {name = name, level = tonumber(level), type = "hash"}
- end
- end
- file:close()
- os.rename(profilepath .. "admin.txt", profilepath .. "old_admin_" .. timestamp .. ".txt")
- end
- -- Now stores IP admins as well.
- file = io.open(profilepath .. defaults.admin_file .. ".txt")
- if file then
- local name, hash, ip, level, admintype
- for line in file:lines() do
- -- format the line (name, hash, level)
- 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+)")
- if hash then
- admin_table[hash] = {name = name, level = tonumber(level), type = "hash"}
- else
- -- format the line (name, hash, level, ip)
- name, ip, level = match(line, "^(%w-),(%g-),(%d+)")
- ip = validate_ipv4(ip)
- assert(ip, defaults.admin_file .. ".txt is incorrectly formatted! Line: " .. line)
- admin_table[ip] = {name = name, level = tonumber(level), type = "ip"}
- end
- end
- file:close()
- end
- -- IP Admins now use admins.txt, but this is here for backwards compatibility.
- file = io.open(profilepath .. "ipadmins.txt")
- if file then
- local name, level, ip
- for line in file:lines() do
- -- format the line (name, hash, level, ip)
- name, ip, level = match(line, "^(%w-),(%g-),(%d+)%c*$")
- ip = validate_ipv4(ip)
- if ip then
- admin_table[ip] = {name = name, level = tonumber(level), type = "ip"}
- end
- end
- file:close()
- os.rename(profilepath .. "ipadmins.txt", profilepath .. "old_ipadmins_" .. timestamp .. ".txt")
- end
- updateAdminFiles()
- end
- function remoteTimer(id, count)
- -- This code will check if someone is trying to login to this TCP server.
- local client, err = server:accept()
- local length = #clients
- if not err then
- client:send"Welcome to the Remote Control interface provided in Wizard's Command Script!\r\n Type 'rcon password command' to execute a command. The Rcon password you use MUST be a global rcon (with sv_rcon_add)\r\n"
- length = length + 1
- clients[length] = {socket = client, info = client:getpeername(), client.logged_in}
- client:settimeout(0)
- elseif err ~= "timeout" then
- hprintf("There was an error accepting a client.\r\nError: " .. err)
- end
- local command, rcon
- for i = 1,length do client = clients[i]
- command, err = client.socket:receive()
- -- Problem getting response from client.
- if err == "timeout" then
- goto continue
- elseif err then
- client.socket:close()
- hprintf("Remote client '" .. client.info .. "' disconnected with error: " .. err)
- remove(clients, i)
- goto continue
- -- Logout code.
- elseif command == "logout" or command == "quit" or command == "exit" or command == "close" then
- client.socket:send"You have been disconnected. Have a good day"
- client.socket:close()
- remove(clients, i)
- goto continue
- end
- rcon, command = match(command, "^rcon (%w%w%w%w%w%w%w%w) (%g+)%c*$")
- -- Validate the command.
- if not rcon or not command then
- client.socket:send"Invalid Command attempt.\r\nrcon <password> <command>\r\n"
- goto continue
- elseif OnServerCommandAttempt(-1, command, rcon) == false then
- client.socket:send"Bad rcon password given. This will be reported."
- goto continue
- end
- hprintf("Remote client '" .. client.info .. "' executed '" .. command .. "'")
- local response
- if command ~= "sv_script_unload" and command ~= "sv_script_reload" and command ~= "sv_script_load" and command ~= "reload" and command ~= "load" and command ~= "unload" and command ~= "lua_load" and command ~= "lua_unload" then
- response = svcmd(command, true)
- end
- response = type(response) == "table" and response[1] and concat(response) or "Failed to receive output for command."
- client.socket:send(response .. "\r\nType your command here:")
- ::continue::
- end
- return true
- end
- -- changes 'sv_myCommand', '/myCommand', and '\myCommand' into 'myCommand'
- local function getvalidformat(command)
- if not command then return end
- local sv_found, slash_found, both_found = sub(command, 1, 3), sub(command, 1, 1), sub(command, 1, 4)
- command = gsub(gsub(command, "_", ""), " ", "")
- if sv_found == "sv_" then
- return sub(command, 3)
- elseif slash_found == "\\" or slash_found == "/" then
- return sub(command, 2)
- elseif both_found == "\\sv_" or both_found == "/sv_" then
- return sub(command, 4)
- end
- return command
- end
- local function getaccess(playerId)
- if playerId then
- local adminEntry = PlayerClass[playerId].admin_entry
- return adminEntry and adminEntry.level
- else
- return 0
- end
- end
- local function SelectRandomPlayer(team)
- local t = {}--TM.New()
- local size = 0
- for playerId = 0,15 do
- if getplayer(playerId) and (not team or getteam(playerId) == team) then
- size = size + 1
- t[size] = playerId
- end
- end
- if size > 0 then
- return t[rand(1, size)]
- end
- end
- -- Origstring is the string to search in, wild is the string to search for.
- local function wildstring(origstring, wild, case_sensative)
- -- If not case sensitive then make all arguments lowercase.
- if not case_sensative then
- origstring, wild = lower(origstring), lower(wild)
- end
- wild = gsub(gsub(gsub(wild, "?", "."), "*", ".*"), " ", "%s")
- local found = match(origstring, wild)
- if found and #found == #origstring then
- return true
- end
- return false
- end
- local function getvalidplayers(expression, executorPlayerId)
- local players = {}--TM.New()
- if cur_players ~= 0 and expression then
- if expression == "*" then
- for playerId = 0,15 do
- if getplayer(playerId) then
- players[#players+1] = playerId
- end
- end
- elseif expression == "me" then
- if executorPlayerId then
- players[1] = executorPlayerId
- end
- elseif player_colors[expression] then
- local color = player_colors[expression]
- local m_player
- for playerId = 0,15 do
- m_player = getplayer(playerId)
- if m_player then
- if color == readword(m_player + 0x60) then
- players[#players+1] = playerId
- end
- end
- end
- elseif expression == "red" then
- for playerId = 0,15 do
- if getplayer(playerId) and getteam(playerId) == 0 then
- players[#players+1] = playerId
- end
- end
- elseif expression == "blue" then
- for playerId = 0,15 do
- if getplayer(playerId) and getteam(playerId) == 1 then
- players[#players+1] = playerId
- end
- end
- elseif expression == "randomred" or expression == "randred" then
- players[1] = SelectRandomPlayer(0)
- elseif expression == "randomblue" or expression == "randblue" then
- players[1] = SelectRandomPlayer(1)
- elseif (tonumber(expression) or 0) >= 1 and tonumber(expression) <= 16 then
- local playerId = tonumber(expression)
- if getplayer(rresolveplayer(playerId)) then
- players[1] = rresolveplayer(playerId)
- end
- elseif expression == "rand" or expression == "random" then
- players[1] = SelectRandomPlayer()
- elseif expression == "admins" then
- for playerId = 0,15 do
- if getplayer(playerId) and getaccess(playerId) then
- players[#players+1] = playerId
- end
- end
- elseif expression == "nearest" or expression == "closest" then
- local m_playerObj, playerObjId = getplayerobject(executorPlayerId)
- local m_playerObj2, X, Y, Z, dist, closest_player
- if m_playerObj then
- local x,y,z = getobjectcoords(playerObjId)
- local min_dist = 9001
- for playerId = 0,15 do
- if playerId ~= executorPlayerId then
- m_playerObj2, playerObjId2 = getplayerobject(playerId)
- if m_playerObj2 then
- X,Y,Z = getobjectcoords(playerObjId2)
- dist = (X - x)^2 + (Y - y)^2 + (Z - z)^2 -- dont need square root since its a comparison
- if min_dist > dist then
- min_dist = dist
- closest_player = playerId
- end
- end
- end
- end
- players[1] = closest_player
- end
- elseif expression == "farthest" then
- local m_playerObj, playerObjId = getplayerobject(executorPlayerId)
- local m_playerObj2, X, Y, Z, dist, farthest_player
- if m_playerObj then
- local x,y,z = getobjectcoords(playerObjId)
- local max_dist = 0
- for playerId = 0,15 do
- if playerId ~= executorPlayerId then
- m_playerObj2, playerObjId2 = getplayerobject(playerId)
- if m_playerObj2 then
- X,Y,Z = getobjectcoords(playerObjId2)
- dist = (X - x)^2 + (Y - y)^2 + (Z - z)^2 -- dont need square root since its a comparison
- if max_dist < dist then
- max_dist = dist
- farthest_player = playerId
- end
- end
- end
- end
- players[1] = farthest_player
- end
- else
- for playerId = 0,15 do
- if getplayer(playerId) and wildstring(getname(playerId), expression) then
- players[#players+1] = playerId
- end
- end
- end
- return next(players) and players
- end
- return false
- end
- local tag_vehi_types = { -- 0x2F4
- [0] = "Human Tank",
- "Human Jeep",
- "Human Boat",
- "Human Plane",
- "Alien Scout",
- "Alien Fighter",
- "Turret",
- }
- local tag_weap_types = { -- 0x30C
- [0] = "None",
- [1694528097] = "AI: Sentinel Beam (ar)",
- [98] = "Special: Skull Ball (b)",
- [1811939430] = "Special: Flag (f)",
- [7239015] = "Vehicle (Covenant): Type-26 Banshee; Type-32 RAV Ghost; Type-25 (and Type-52?) Wraith (gun)",
- [29799] = "Vehicle (Covenant): Type-26 ASG Shade Gun Turret; DX-class Spirit Dropship (gt)",
- [26467] = "Vehicle (Human): M12 Warthog (cg)",
- [1852727651] = "Vehicle (Human): M808B MBT Scorpion (cannon)",
- [1811968609] = "Weapon (Human): MA5 Assault Rifle; Gravity Rifle (ar)",
- [1811969126] = "Weapon (Human): M7057 Flamethrower (ft)",
- [28776] = "Weapon (Human): M6 Pistol (hp)",
- [1811967090] = "Weapon (Human): M19 SSM / M41 SSR Rocket Launcher (rl)",
- [1811965811] = "Weapon (Human): M90 CAWS Shotgun (sg)",
- [1811968627] = "Weapon (Human): 99D-S2 Sniper Rifle (sr)",
- [25190] = "Weapon, Melee (Covenant): Energy Sword (fb)",
- [1811968614] = "Weapon (Covenant): Type-33 Fuel Rod Gun (fr)",
- [1811965294] = "Weapon (Covenant): Type-33 GML Needler (ne)",
- [1811968112] = "Weapon (Covenant): Plasma Pistol (pp)",
- [1811968624] = "Weapon (Covenant): Plasma Rifle (pr)",
- [1811964784] = "Weapon (Covenant): Plasma Cannon (pc)"
- }
- local function LoadTags()
- local map_base = 0x40440000
- local tag_table_base = readdword(map_base) -- Confirmed. (0x40440028)
- local tag_table_count = readdword(map_base + 0xC) -- Confirmed. Number of tags in the tag table.
- local tag_table_size = 0x20 -- Confirmed.
- local reverse = string.reverse
- local tag_class, tag_id, tag_name_address, tag_name, address_tag_data, vehi_type, weap_type
- for i=0,(tag_table_count - 1) do
- tag_class = reverse(readstring(tag_table_base + (tag_table_size * i), 4))
- tag_id = readdword(tag_table_base + 0xC + (tag_table_size * i))
- tag_name_address = readdword(tag_table_base + 0x10 + tag_table_size * i)
- tag_name = readstring(tag_name_address)
- tag_table[tag_class] = tag_table[tag_class] or {tag_id}
- tag_table[tag_class][tag_name] = tag_id
- tag_table[tag_class][#tag_table[tag_class]+1] = tag_id
- tag_table[tag_id] = {}--{}--TM.New()
- tag_table[tag_id].tag_name = tag_name
- tag_table[tag_id].tag_class = tag_class
- tag_address = readdword(map_base) + i * tag_table_size -- 0x40440028
- if tag_class == "vehi" then
- address_tag_data = readdword(tag_address, 0x14)
- vehi_type = readword(address_tag_data + 0x2F4)
- tag_table[tag_id].vehi_type = tag_vehi_types[vehi_type]
- if vehi_type and vehi_type >= 0 and vehi_type <= 6 and not tag_table[vehi_type] then
- tag_table[vehi_type] = tag_id
- end
- elseif tag_class == "weap" then
- address_tag_data = readdword(tag_address, 0x14)
- weap_type = readword(address_tag_data + 0x2F4)
- tag_table[tag_id].weap_type = tag_weap_types[weap_type]
- if not weap_type or not tag_table[weap_type] then
- tag_table[weap_type] = tag_id
- end
- end
- end
- hprintf("Found " .. tostring(#tag_table.vehi) .. " vehicles and " .. tostring(#tag_table.weap) .. " weapons")
- flameid = gettagid("proj", "weapons\\flamethrower\\flame")
- objects = {
- cyborg = {"bot, masterchief", type = "bipd", mapId = gettag("bipd", "characters\\cyborg_mp\\cyborg_mp"), name = "Cyborg"},
- captain = {"keyes", type = "bipd", mapId = gettag("bipd", "characters\\captain\\captain"), name = "Captain Keyes"},
- cortana = {type = "bipd", mapId = gettag("bipd", "characters\\cortana\\cortana"), name = "Cortana"},
- cortana2 = {type = "bipd", mapId = gettag("bipd", "characters\\cortana\\halo_enhanced\\halo_enhanced"), name = "Cortana2"},
- crewman = {type = "bipd", mapId = gettag("bipd", "characters\\crewman\\crewman"), name = "Crewman"},
- elite = {type = "bipd", mapId = gettag("bipd", "characters\\elite\\elite"), name = "Elite"},
- elite2 = {type = "bipd", mapId = gettag("bipd", "characters\\elite\\elite special"), name = "Elite Special"},
- engineer = {type = "bipd", mapId = gettag("bipd", "characters\\engineer\\engineer"), name = "Engineer"},
- flood = {type = "bipd", mapId = gettag("bipd", "characters\\flood_captain\\flood_captain"), name = "Flood Captain"},
- flood2 = {type = "bipd", mapId = gettag("bipd", "characters\\flood_infection\\flood_infection"), name = "Flood Infection"},
- flood3 = {type = "bipd", mapId = gettag("bipd", "characters\\floodcarrier\\floodcarrier"), name = "Flood Carrier"},
- floodelite = {type = "bipd", mapId = gettag("bipd", "characters\\floodcombat elite\\floodcombat elite"), name = "FloodCombat Elite"},
- floodhuman = {type = "bipd", mapId = gettag("bipd", "characters\\floodcombat_human\\floodcombat_human"), name = "FloodCombat Human"},
- grunt = {"pedobear", type = "bipd", mapId = gettag("bipd", "characters\\grunt\\grunt"), name = "Pedobear"},
- hunter = {type = "bipd", mapId = gettag("bipd", "characters\\hunter\\hunter"), name = "Hunter"},
- marine = {type = "bipd", mapId = gettag("bipd", "characters\\marine\\marine"), name = "Marine"},
- marine2 = {"marinesuicide", type = "bipd", mapId = gettag("bipd", "characters\\marine_suicidal\\marine_suicidal"), name = "Marine Suicidal"},
- monitor = {type = "bipd", mapId = gettag("bipd", "characters\\monitor\\monitor"), name = "Monitor"},
- sentinel = {type = "bipd", mapId = gettag("bipd", "characters\\sentinel\\sentinel"), name = "Sentinel"},
- johnson = {type = "bipd", mapId = gettag("bipd", "characters\\johnson\\johnson"), name = "Sgt. Johnson"},
- camouflage = {"camo", type = "eqip", mapId = gettag("eqip", "powerups\\active camouflage"), name = "Camouflage"},
- doublespeed = {"dblspd", type = "eqip", mapId = gettag("eqip", "powerups\\double speed"), name = "Double Speed"},
- fullspec = {"fullspectrum", type = "eqip", mapId = gettag("eqip", "powerups\\full-spectrum vision"), name = "Full-Spectrum Vision"},
- fnade = {"nades", "frag", "frags", type = "eqip", mapId = gettag("eqip", "weapons\\frag grenade\\frag grenade"), name = "Frag Grenade"},
- pnade = {"plasmas", "plasma", type = "eqip", mapId = gettag("eqip", "weapons\\plasma grenade\\plasma grenade"), name = "Plasma Grenade"},
- overshield = {"os", type = "eqip", mapId = gettag("eqip", "powerups\\over shield"), name = "Overshield"},
- rifleammo = {type = "eqip", mapId = gettag("eqip", "powerups\\assault rifle ammo\\assault rifle ammo"), name = "Assault Rifle Ammo"},
- healthpack = {"health", type = "eqip", mapId = gettag("eqip", "powerups\\health pack"), name = "Health Pack"},
- needlerammo = {"needleammo", type = "eqip", mapId = gettag("eqip", "powerups\\needler ammo\\needler ammo"), name = "Needler Ammo"},
- pistolammo = {type = "eqip", mapId = gettag("eqip", "powerups\\pistol ammo\\pistol ammo"), name = "Pistol Ammo"},
- rocketammo = {type = "eqip", mapId = gettag("eqip", "powerups\\rocket launcher ammo\\rocket launcher ammo"), name = "Rocket Ammo"},
- shottyammo = {"shotgunammo", type = "eqip", mapId = gettag("eqip", "powerups\\shotgun ammo\\shotgun ammo"), name = "Shotgun Ammo"},
- sniperammo = {type = "eqip", mapId = gettag("eqip", "powerups\\sniper rifle ammo\\sniper rifle ammo"), name = "Sniper Ammo"},
- flameammo = {type = "eqip", mapId = gettag("eqip", "powerups\\flamethrower ammo\\flamethrower ammo"), name = "Flamethrower Ammo"},
- energysword = {"esword", type = "weap", mapId = gettag("weap", "weapons\\energy sword\\energy sword"), name = "Energy Sword"},
- oddball = {"ball", type = "weap", mapId = gettag("weap", "weapons\\ball\\ball"), name = "Oddball"},
- flag = {type = "weap", mapId = gettag("weap", "weapons\\flag\\flag"), name = "Flag"},
- fuelrod = {"frg", "rod", "plasmacannon", type = "weap", mapId = gettag("weap", "weapons\\plasma_cannon\\plasma_cannon"), name = "Fuel Rod"},
- gravitygun = {"ggun", type = "weap", mapId = gettag("weap", "weapons\\gravity rifle\\gravity rifle"), name = "Gravity Gun"},
- needler = {type = "weap", mapId = gettag("weap", "weapons\\needler\\mp_needler"), name = "Needler"},
- pistol = {type = "weap", mapId = gettag("weap", "weapons\\pistol\\pistol"), name = "Pistol"},
- plasmapistol = {"ppistol", type = "weap", mapId = gettag("weap", "weapons\\plasma pistol\\plasma pistol"), name = "Plasma Pistol"},
- plasmarifle = {"prifle", type = "weap", mapId = gettag("weap", "weapons\\plasma rifle\\plasma rifle"), name = "Plasma Rifle"},
- assaultrifle = {"rifle", "arifle", "assault", type = "weap", mapId = gettag("weap", "weapons\\assault rifle\\assault rifle"), name = "Assault Rifle"},
- rocketlauncher = {"rocket", "rox", type = "weap", mapId = gettag("weap", "weapons\\rocket launcher\\rocket launcher"), name = "Rocket Launcher"},
- shotgun = {"shotty", type = "weap", mapId = gettag("weap", "weapons\\shotgun\\shotgun"), name = "Shotgun"},
- sniper = {"sniperrifle", type = "weap", mapId = gettag("weap", "weapons\\sniper rifle\\sniper rifle"), name = "Sniper Rifle"},
- flamethrower = {"flamer", type = "weap", mapId = gettag("weap", "weapons\\flamethrower\\flamethrower"), name = "Flamethrower"},
- wraith = {type = "vehi", mapId = gettag("vehi", "vehicles\\wraith\\wraith"), name = "Wraith"},
- pelican = {"peli", type = "vehi", mapId = gettag("vehi", "vehicles\\pelican\\pelican"), name = "Pelican"},
- ghost = {type = "vehi", type = "vehi", mapId = gettag("vehi", "vehicles\\ghost\\ghost_mp"), name = "Ghost"},
- warthog = {"hog", type = "vehi", mapId = gettag("vehi", "vehicles\\warthog\\mp_warthog"), name = "Warthog"},
- rocketwarthog = {"rhog", type = "vehi", mapId = gettag("vehi", "vehicles\\rwarthog\\rwarthog"), name = "Rocket Warthog"},
- banshee = {"shee", type = "vehi", mapId = gettag("vehi", "vehicles\\banshee\\banshee_mp"), name = "Banshee"},
- tank = {"scorpion", type = "vehi", mapId = gettag("vehi", "vehicles\\scorpion\\scorpion_mp"), name = "Tank"},
- turret = {"shade", type = "vehi", mapId = gettag("vehi", "vehicles\\c gun turret\\c gun turret_mp"), name = "Gun Turret"},
- sheebolt = {type = "proj", mapId = gettag("proj", "vehicles\\banshee\\banshee bolt"), name = "Shee Bolt"},
- sheerod = {type = "proj", mapId = gettag("proj", "vehicles\\banshee\\mp_banshee fuel rod"), name = "Shee Rod"},
- turretbolt = {type = "proj", mapId = gettag("proj", "vehicles\\c gun turret\\mp gun turret"), name = "Turret Bullet"},
- ghostbolt = {type = "proj", mapId = gettag("proj", "vehicles\\ghost\\ghost bolt"), name = "Ghost Bolt"},
- tankshot = {type = "proj", mapId = gettag("proj", "vehicles\\scorpion\\bullet"), name = "Tank Bullet"},
- tankshell = {type = "proj", mapId = gettag("proj", "vehicles\\scorpion\\tank shell"), name = "Tank Shell"},
- hogshot = {type = "proj", mapId = gettag("proj", "vehicles\\warthog\\bullet"), name = "Hog Bullet"},
- rifleshot = {type = "proj", mapId = gettag("proj", "weapons\\assault rifle\\bullet"), name = "Rifle Bullet"},
- flame = {type = "proj", mapId = gettag("proj", "weapons\\flamethrower\\flame"), name = "Flame Projectile"},
- needlershot = {type = "proj", mapId = gettag("proj", "weapons\\needler\\mp_needle"), name = "Needler Shard"},
- pistolshot = {type = "proj", mapId = gettag("proj", "weapons\\pistol\\bullet"), name = "Pistol Bullet"},
- priflebolt = {type = "proj", mapId = gettag("proj", "weapons\\plasma pistol\\bolt"), name = "Plasma Rifle Bolt"},
- ppistolbolt = {type = "proj", mapId = gettag("proj", "weapons\\plasma rifle\\bolt"), name = "Plasma Pistol Bolt"},
- ppistolcbolt = {type = "proj", mapId = gettag("proj", "weapons\\plasma rifle\\charged bolt"), name = "Plasma Pistol Charged Bolt"},
- rocketproj = {type = "proj", mapId = gettag("proj", "weapons\\rocket launcher\\rocket"), name = "Rocket Projectile"},
- shottyshot = {type = "proj", mapId = gettag("proj", "weapons\\shotgun\\pellet"), name = "Shotgun Pellet"},
- snipershot = {type = "proj", mapId = gettag("proj", "weapons\\sniper rifle\\sniper bullet"), name = "Sniper Bullet"},
- fuelrodshot = {type = "proj", mapId = gettag("proj", "weapons\\plasma_cannon\\plasma_cannon"), name = "Fuel Rod Bolt"},
- }
- -- Use enum in vehi_type as a backup way to determine default vehicles tag ids without their tagnames.
- objects.tank.mapId = objects.tank.mapId or tag_table[0] and tag_table[0]
- objects.warthog.mapId = objects.warthog.mapId or tag_table[1] and tag_table[1]
- objects.rocketwarthog.mapId = objects.rocketwarthog.mapId or tag_table[1] and tag_table[1]
- objects.pelican.mapId = objects.pelican.mapId or tag_table[3] and tag_table[3]
- objects.ghost.mapId = objects.ghost.mapId or tag_table[4] and tag_table[4]
- objects.banshee.mapId = objects.banshee.mapId or tag_table[5] and tag_table[5]
- objects.turret.mapId = objects.turret.mapId or tag_table[6] and tag_table[6]
- objects.oddball.mapId = objects.oddball.mapId or tag_table[98] and say("Oddball: USING BACKUP TAG") or tag_table[98]
- objects.energysword.mapId = objects.energysword.mapId or tag_table[25190] and say("Energy Sword: USING BACKUP TAG") or tag_table[25190]
- objects.pistol.mapId = objects.pistol.mapId or tag_table[28776] and say("Pistol: USING BACKUP TAG") or tag_table[28776]
- objects.flag.mapId = objects.flag.mapId or tag_table[1811939430] and say("Flag: USING BACKUP TAG") or tag_table[1811939430]
- objects.needler.mapId = objects.needler.mapId or tag_table[1811965294] and say("Needler: USING BACKUP TAG") or tag_table[1811965294]
- objects.plasmapistol.mapId = objects.plasmapistol.mapId or tag_table[1811968112] and say("Plasma Pistol: USING BACKUP TAG") or tag_table[1811968112]
- objects.fuelrod.mapId = objects.fuelrod.mapId or tag_table[1811968614] and say("Fuelrod: USING BACKUP TAG") or tag_table[1811968614]
- objects.plasmarifle.mapId = objects.plasmarifle.mapId or tag_table[1811968624] and say("Plasma Rifle: USING BACKUP TAG") or tag_table[1811968624]
- objects.assaultrifle.mapId = objects.assaultrifle.mapId or tag_table[1811968609] and say("Assault Rifle: USING BACKUP TAG") or tag_table[1811968609]
- objects.rocketlauncher.mapId = objects.rocketlauncher.mapId or tag_table[1811967090] and say("Rocket Launcher: USING BACKUP TAG") or tag_table[1811967090]
- objects.shotgun.mapId = objects.shotgun.mapId or tag_table[1811965811] and say("Shotgun: USING BACKUP TAG") or tag_table[1811965811]
- objects.sniper.mapId = objects.sniper.mapId or tag_table[1811968627] and say("Sniper: USING BACKUP TAG") or tag_table[1811968627]
- objects.flamethrower.mapId = objects.flamethrower.mapId or tag_table[1811969126] and say("Flamethrower: USING BACKUP TAG") or tag_table[1811969126]
- -- Set Object Aliases.
- for name,thisObject in next,objects do
- for i = 1,#thisObject do
- objects[thisObject[i]] = thisObject
- end
- objects[name] = thisObject
- end
- end
- function votekickTimer(id, count)
- say("The VoteKick on " .. getname(votekickPlayerId) .. " has expired!")
- votekicktimer = nil
- votekickPlayerId = nil
- votekick_counter = -defaults.votekick_timeout
- for playerId = 0,15 do
- PlayerClass[playerId].used_votekick = false
- end
- return false
- end
- local function WriteLog(filename, logStr)
- local file = io.open(filename, "a")
- if file then
- file:write(format("%s\t%s\n", os.date"%Y/%m/%d %H:%M:%S", logStr))
- file:close()
- end
- end
- local function cmdlog(message)
- WriteLog(profilepath .. "logs\\" .. defaults.commands_file .. ".log", message)
- end
- -- This local function makes sure that we never have any commands that output more than 8 lines
- -- We need this because Halo only lets you see 8 lines of text at a time in the chat
- -- This local function will also split lines into more lines if a line is too long.
- -- 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.
- -- Arguments are output, maximum number of lines to use (MIGHT go over maxlines if the line length is already too long)
- -- maxlinesize is the maximum number of characters a line can have
- -- 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.
- local function formatOutput(output, maxlines, maxlinesize)
- -- error if the arguments were passed incorrectly.
- if type(output) ~= "string" and type(output) ~= "table" then
- error("bad argument #1 to 'formatOutput' (expected table or string, got " .. type(output) .. ")" .. " Value: " .. tostring(output))
- elseif maxlines and type(maxlines) ~= "number" then
- error("bad argument #2 to 'formatOutput' (expected number, got " .. type(maxlines) .. " Value: " .. tostring(maxlines))
- elseif maxlinesize and type(maxlinesize) ~= "number" then
- error("bad argument #3 to 'formatOutput' (expected number, got " .. type(maxlinesize) .. " Value: " .. tostring(maxlinesize))
- end
- -- handle our arguments
- maxlines = maxlines or 9001
- maxlinesize = maxlinesize or 9001
- local newOutput = type(output) == "string" and tokenizestring(output, "\n") or output
- -- Get number of lines from our output. Respects __len metamethod.
- local mt = type(output) == "table" and getmetatable(output)
- local len = mt and mt.__len
- local numOfLines = len and len(newOutput) or #newOutput
- local function insert(t, pos, v)
- if v then
- assert(type(pos) == "number", "bad argument #2 to 'insert' expected number, got " .. type(pos))
- for i = numOfLines+1,pos+1,-1 do
- rawset(t, i, rawget(t, i-1))
- end
- t[pos] = v
- else
- t[numOfLines+1] = pos
- end
- numOfLines = numOfLines + 1
- end
- local function remove(t, key)
- t = type(t) == "table" and t or error("bad argument #1 to 'remove' expected table, got " .. type(t))
- key = key or numOfLines
- t[key] = nil
- if type(key) == "number" then
- for i = key,numOfLines do
- rawset(t, i, rawget(t, i+1))
- end
- end
- numOfLines = numOfLines - 1
- end
- local header = newOutput.header
- local linesCombined = ceil((numOfLines + (header and 1 or 0))/maxlines)
- -- duplicate the header by linesCombined times.
- if header then
- assert(type(header) == "string", "Output header needs to be a string, got " .. type(header))
- for i = 1,linesCombined do
- insert(newOutput, 1, header)
- end
- end
- -- If we have no more output, then we don't need to do anything more.
- if numOfLines == 1 and header or numOfLines == 0 then
- return newOutput[1]
- end
- if newOutput.align then
- local delimiter = newOutput.delim or "|"
- local separator = newOutput.separator or delimiter
- local mins = {}--TM.New()
- local length, lineParts
- -- This loop gets the largest possible size for each line part.
- for i = 1,numOfLines do
- lineParts = tokenizestring(newOutput[i], delimiter)
- for j = 1,#lineParts do
- -- Format every string to the biggest length possible for that entry.
- length = #lineParts[j]
- if not mins[j] or length > mins[j] then
- mins[j] = length
- end
- end
- end
- -- This loop will make all line parts the same size (by adding spaces). string.format makes this easy for us.
- local numOfLineParts
- for i = 1,numOfLines do
- lineParts = tokenizestring(newOutput[i], delimiter)
- numOfLineParts = #lineParts
- for j = 1,numOfLineParts do
- lineParts[j] = format("%-" .. mins[j] .. "s", lineParts[j])
- end
- lineParts[numOfLineParts] = sub(lineParts[numOfLineParts], 1, -1) -- removes the last delimiter in the line
- newOutput[i] = concat(lineParts, separator)
- end
- end
- -- If our output uses too many lines, then we now need to combine lines until we are within maxlines
- local lineIter = 1
- local numOfLinesToCombine = floor(numOfLines / linesCombined)
- while numOfLines > maxlines do
- -- combine 'linesCombined' lines into 1 line.
- for i = 2,linesCombined do -- should be 1,linesCombined-1 but 2,linesCombined works fine
- if lineIter+1 > numOfLines then break end
- newOutput[lineIter] = newOutput[lineIter] .. " - " .. newOutput[lineIter+1]
- remove(newOutput, lineIter+1)
- end
- lineIter = lineIter + 1
- -- Check if we need to increase the number of lines to combine per iteration.
- -- Also checks if we're done
- if numOfLinesToCombine == 1 then
- linesCombined = linesCombined - 1
- if linesCombined < 2 then break end
- numOfLinesToCombine = floor(numOfLines / linesCombined)
- -- This is our counter.
- else
- numOfLinesToCombine = numOfLinesToCombine - 1
- end
- end
- -- Make sure the line isn't too long.
- -- If it is, we put the part that's too long into a new table which we will put back into output later.
- lineIter = 1
- local line, length
- while newOutput[lineIter] do
- line = newOutput[lineIter]
- length = #line
- if length > maxlinesize then
- newOutput[lineIter] = sub(line, 1, maxlinesize) -- first part of line
- insert(newOutput, lineIter+1, sub(line, maxlinesize)) -- insert a new line right after this one with the second part
- end
- lineIter = lineIter + 1
- end
- return concat(newOutput, "\n", 1, numOfLines)
- end
- function delayMsg(id, count, arguments)
- local msg, playerId = arguments[1], arguments[2]
- msg = type(msg) == "table" and concat(msg, "\n") or msg
- if playerId then
- if output_environment == 2 then
- say(msg, false)
- elseif output_environment == 3 then
- privatesay(playerId, msg, false)
- end
- end
- return false
- end
- local function sendresponse(message, playerId, log)
- if not message then
- -- this will reset all the properties of cmdreply
- cmdreply(true)
- return
- end
- local playerCheck = getplayer(playerId)
- local tempmessage = message
- if not playerCheck then
- message = formatOutput(message)
- hprintf(message)
- elseif output_environment == 1 then
- message = formatOutput(message, 20, 76)
- sendconsoletext(playerId, message)
- elseif output_environment == 2 or output_environment == 3 then
- message = formatOutput(message, 6, 100)
- registertimer(0, "delayMsg", {message, playerId})
- end
- if log and playerCheck then
- cmdlog("Response to " .. getname(playerId) .. " (" .. PlayerClass[playerId].admin_entry.name .. "): " .. message)
- end
- -- this will reset all the properties of cmdreply
- if tempmessage == cmdreply then cmdreply(true) end
- end
- local function getscorelimit()
- if gametype == 1 then
- return readint(addresses.ctf_globals + 0x18)
- elseif gametype == 2 then
- return scorelimit
- --return readbyte(addresses.gametype_base + 0x58, score)
- elseif gametype == 3 then
- return readint(addresses.oddball_globals)
- elseif gametype == 4 then
- return readint(addresses.koth_globals + team*4)
- elseif gametype == 5 then
- return readint(addresses.race_globals + team*4 + 0x88)
- else
- return readbyte(addresses.gametype_base + 0x58)
- end
- end
- local function setscorelimit(score)
- if gametype == 1 then
- writeint(addresses.ctf_globals + 0x18, score)
- elseif gametype == 2 then
- scorelimit = score
- --writebyte(addresses.gametype_base + 0x58, score)
- elseif gametype == 3 then
- writeint(addresses.oddball_globals, score)
- elseif gametype == 4 then
- writeint(addresses.koth_globals + team*4, score)
- elseif gametype == 5 then
- writeint(addresses.race_globals + team*4 + 0x88, score)
- else
- writebyte(addresses.gametype_base + 0x58, score)
- end
- end
- local function getscore(playerId)
- if gametype == 1 then
- return readshort(getplayer(playerId) + 0xC8)
- elseif gametype == 2 then
- return player_scores[playerId]
- --return readint(addresses.slayer_globals + 0x40 + playerId*4)
- elseif gametype == 3 then
- local oddball_game = readbyte(addresses.gametype_base + 0x8C)
- if oddball_game == 0 or oddball_game == 1 then
- return readint(addresses.oddball_globals + 0x84 + playerId*4)
- else
- return readint(addresses.oddball_globals + player*4 + 0x104)
- end
- elseif gametype == 4 then
- return readshort(getplayer(playerId) + 0xC4)
- elseif gametype == 5 then
- return readshort(getplayer(playerId) + 0xC6)
- end
- end
- local function setscore(playerId, score)
- if gametype == 1 then
- writeshort(getplayer(playerId)+0xC8, score)
- elseif gametype == 2 then
- if team_play then
- local curscore = player_scores[playerId]
- local diff = math.abs(score - curscore)
- if curscore > score then
- team_scores[getteam(playerId)] = team_scores[getteam(playerId)] + curscore
- elseif curscore < score then
- team_scores[getteam(playerId)] = team_scores[getteam(playerId)] - curscore
- end
- end
- player_scores[playerId] = score
- writeshort(addresses.slayer_globals + 0x40 + playerId*4, score)
- elseif gametype == 3 then
- local oddball_game = readbyte(addresses.gametype_base + 0x8C)
- if oddball_game == 0 or oddball_game == 1 then
- writeint(addresses.oddball_globals + 0x84 + playerId*4, score * 30)
- else
- writeint(addresses.oddball_globals + 0x84 + playerId*4, score)
- end
- elseif gametype == 4 then
- writeshort(getplayer(playerId) + 0xC4, score * 30)
- elseif gametype == 5 then
- writeshort(getplayer(playerId) + 0xC6, score)
- end
- end
- local function getteamscore(team)
- if gametype == 1 then
- return readint(addresses.ctf_globals + team*4 + 0x10)
- elseif gametype == 2 then
- return team_scores[team]
- --return readint(addresses.slayer_globals + team*4)
- elseif gametype == 3 then
- return readint(addresses.oddball_globals + team*4 + 0x4)
- elseif gametype == 4 then
- return readint(addresses.koth_globals + team*4)
- elseif gametype == 5 then
- return readint(addresses.race_globals + team*4 + 0x88)
- end
- end
- local function setteamscore(team, score)
- if gametype == 1 then
- writeint(addresses.ctf_globals + team*4 + 0x10, score)
- elseif gametype == 2 then
- team_scores[team] = score
- --writeint(addresses.slayer_globals + team*4, score)
- elseif gametype == 3 then
- writeint(addresses.oddball_globals + team*4 + 0x4, score)
- elseif gametype == 4 then
- writeint(addresses.koth_globals + team*4, score)
- elseif gametype == 5 then
- writeint(addresses.race_globals + team*4 + 0x88, score)
- end
- end
- local function WriteChangeLog()
- local file = io.open("changelog_" .. script_version .. ".txt", "w")
- local changelog = {}--TM.New()
- changelog[#changelog+1] = "Changelog for Commands Script"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 5.2 The 'Nimbus' Release (Released __, 2015)"
- changelog[#changelog+1] = "--Added a firefist command, to be explained later."
- changelog[#changelog+1] = "--Readded the ghost and unghost commands due to many requests"
- changelog[#changelog+1] = "--Added a central (remote) banlist feature. Please check out the readme for information on how to use it."
- changelog[#changelog+1] = "--Ban reasons will now show 'unbanned by (admin name)' when they have been unbanned."
- changelog[#changelog+1] = "--Even more bug fixes and small features, including compatibility with Sapp."
- changelog[#changelog+1] = "--Removed all the memoizing crap that I put in the previous version. It was causing a lot of rare issues, and probably wasn't helping performance much"
- changelog[#changelog+1] = "--Fixed an issue that happened onload that was caused by people using windows default notepad to edit the init.txt"
- changelog[#changelog+1] = "--Added 'farthest' expression for player arguments, so you can now do things like /kill farthest to kill the farthest player to you."
- changelog[#changelog+1] = "--Added 'nearest' expression for player arguments, so you can now do things like /kill nearest to kill the nearest player to you."
- changelog[#changelog+1] = "--Added colors as player arguments, you can now pass colors as player expressions like /kill yellow will kill all yellow people in the server"
- changelog[#changelog+1] = "--Improved the killingspree feature. It will now announce when someone's spree has ended, and how many kills they racked up."
- changelog[#changelog+1] = "--Removed 'log' as an alias for the login command so as not to interfere with the already existing 'log' command from Sapp."
- changelog[#changelog+1] = "--Fixed a bug that would cause the 'list' command to crash if there were no admins on the server."
- changelog[#changelog+1] = "--Fixed a bug with the Noweapons command."
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 5.13 The 'Nimbus' Release (Released February 21th, 2015)"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "--Fixed a few minor bugs, there was a couple of issues with the banlist saving/reloading that happened in rare situations"
- changelog[#changelog+1] = "--Revamped even more code for optimization, and added lots of memoizing."
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 5.01 The 'Nimbus' Release (Released February 20th, 2015)"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "--Fixed a very minor issue with banlist reloading. (was still loading from unused_banlist.txt, not a major problem)"
- changelog[#changelog+1] = "--Found out that the 'tbag' feature Aelite added was only supposed to apply to kills, so that is now a thing"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 5.0 The 'Nimbus' Release (**WIZARD IS BACK** Released February 19, 2015)"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- 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"
- changelog[#changelog+1] = "--This script will no longer load the defaults.txt if this script was loaded from the persistent folder (Phasor Only)"
- 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."
- 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."
- 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)"
- 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)"
- changelog[#changelog+1] = "--This script will now load sapp's 'ipbans.txt' file."
- changelog[#changelog+1] = "--Loading/saving of admins/bans are much more reliable now, the script will error if your file is formatted incorrectly"
- 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"
- changelog[#changelog+1] = "--Kick/Ban/Mute commands now let you pass reason and time normally, you don't have to use _ for reasons anymore."
- changelog[#changelog+1] = "--All structures now follow a global naming scheme that I plan to use in all my scripts from now on"
- changelog[#changelog+1] = "--All code now uses my phasor functions to get addresses (getplayerobject, getplayerweapon, etc) for increased performance"
- changelog[#changelog+1] = "--This script now uses local variables to optimize performance."
- 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."
- changelog[#changelog+1] = "--Added a /disconnect and sv_disconnect command which will give a player a 'lost network connection' screen"
- changelog[#changelog+1] = "--Removed a few useless commands that never did work but somehow people found out about (probably because of /list lol)"
- changelog[#changelog+1] = "--Gethelp added. Usage: sv_gethelp (command) or /help (command) without ()"
- changelog[#changelog+1] = "--Global rcons functionality updated (see guide for details)"
- 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"
- changelog[#changelog+1] = "--Organized all commands by table so now all commands are fully documented with help notes and everything"
- 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."
- changelog[#changelog+1] = "--Commands now uses admins.txt for both hash admins and IP admins, ipadmins.txt will still be read for backwards compatibility."
- changelog[#changelog+1] = "--The old deprecated ban files will now have 'archived_' in front of them. Same goes for the admin files."
- 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."
- 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."
- changelog[#changelog+1] = "--Anyone joining with a hacked hash (like hash 'myfakehashtrollu') will not be allowed into the server"
- changelog[#changelog+1] = "--Chat commands now directly execute server commands (/e is now deprecated) and the script is much smaller because of it"
- changelog[#changelog+1] = "--Rewrote BOS functionality"
- changelog[#changelog+1] = "--Rewrote the Spawn functionality and made the code 10x smaller by using better and more efficient coding"
- changelog[#changelog+1] = "--I've fixed things here and there, added things that were removed from my original Commands."
- changelog[#changelog+1] = "--Fixed /read (it never worked). Also accepts number structs."
- changelog[#changelog+1] = "--Fixed /write to not break on invalid syntax. Also accepts number structs.."
- changelog[#changelog+1] = "--Added randomred and randomblue to expressions list."
- changelog[#changelog+1] = "--Added a control command (FINALLY)"
- changelog[#changelog+1] = "--Fixed sending negative numbers to setplasmas and setfrags"
- changelog[#changelog+1] = "--Fixed occasional glitches with setammo."
- 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"
- changelog[#changelog+1] = "--Script also tells you if your access.ini is not formatted correctly and why and then raises an error."
- changelog[#changelog+1] = "--Changed sv_status to sv_status_more as to not interfere with normal sv_status"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 4.2(Released August 3rd, 2013)"
- changelog[#changelog+1] = "--Update Reason: Bug fixes and Added Features"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Added the time limit address thanks to wizard. sv_time_cur is now compatible with Halo CE"
- changelog[#changelog+1] = "--Added the sendconsoletext overload to the command scripts. Thank you Nuggetz."
- changelog[#changelog+1] = "--Added 'sv_hash_duplicates' command which enables/disables the checking of duplicate keys in the server."
- changelog[#changelog+1] = "--Added 'sv_multiteam_vehicles' Enables/Disables the ability to enter a vehicle with another playerId in FFA."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Modified all tables that used the hash for identication, and changed it to IP"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Fixed minor bug with votekick"
- changelog[#changelog+1] = "--Fixed issue with sv_superban"
- changelog[#changelog+1] = "--Fixed AntiCaps command. WARNING: If you use a chatfilter script. Load that script before this one."
- changelog[#changelog+1] = "--Fixed issue with team play detection"
- changelog[#changelog+1] = "--Fixed minor bugs."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 4.1(Released July 23rd, 2013)"
- changelog[#changelog+1] = "--Update Reason: Bug fixes"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Fixed minor bugs"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 4.0(Released July 21st, 2013)"
- changelog[#changelog+1] = "--Update Reason: make it compatible with new Phasor"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Added 'sv_addrcon' This gives you the ability to have more than one rcon."
- changelog[#changelog+1] = "--Added 'sv_delrcon' Removes rcons from the rcon list."
- changelog[#changelog+1] = "--Added 'sv_rconlist' Displays all available rcons"
- changelog[#changelog+1] = "--Added 'sv_iprangeban' bans entire IP Range"
- changelog[#changelog+1] = "--Added 'sv_iprangeunban' Removes an IP from the banlist"
- changelog[#changelog+1] = "--Added 'sv_iprangebanlist' Shows all IP's banned"
- changelog[#changelog+1] = "--Added 'sv_read' command."
- changelog[#changelog+1] = "--Added 'sv_load' shortcut for sv_script_load."
- changelog[#changelog+1] = "--Added 'sv_unload' shortcut for sv_script_unload."
- changelog[#changelog+1] = "--Added 'sv_resetplayer' and '/resetplayer' removes all troll command settings."
- changelog[#changelog+1] = "--Added 'sv_damage' Increases playerId damage."
- changelog[#changelog+1] = "--Added reason to sv_textban"
- changelog[#changelog+1] = "--Added Command_Balance local function since sv_team_balance is not a command anymore for the moment."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Modified Reason is said to the public"
- changelog[#changelog+1] = "--Modified Adminblocker the admin is notified if a command is being executed on them."
- changelog[#changelog+1] = "--Modified AntiSpam changed from boolean to a type: all, players, off"
- changelog[#changelog+1] = "--Modified 'sv_commands' -> 'sv_cmds'"
- changelog[#changelog+1] = "--Modified 'sv_ipban' now accepts IP's'"
- changelog[#changelog+1] = "--Modified AFK detection. Works better"
- changelog[#changelog+1] = "--Modified NameBan. Banned names are changed to 'playerId' on join."
- changelog[#changelog+1] = "--Modified Tbag Detection: Detects victim location. You must be near the victims death to be able to tbag him/her."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Fixed most bugs with the new phasor"
- changelog[#changelog+1] = "--Fixed 'sv_scrimmode'"
- changelog[#changelog+1] = "--Fixed @ bug"
- changelog[#changelog+1] = "--Fixed AccessMerging bug when -1 was given to any other level other than 0"
- changelog[#changelog+1] = "--Fixed minor Bos Bug"
- changelog[#changelog+1] = "--Fixed setscore bug"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Removed sv_pinglist command"
- changelog[#changelog+1] = "--Removed sv_hash_check, sv_version, and sv_version_check. Phasor has them built in."
- changelog[#changelog+1] = "--Removed Portal Blocking"
- changelog[#changelog+1] = "--Removed /setname until further notice"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 3.0.1 (Released February 28th, 2013)"
- changelog[#changelog+1] = "--Update Reason: Mainly Bug Fixes"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Added sv_scrimmode"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Modified ipadminadd now accepts IP's"
- changelog[#changelog+1] = "--Modified 'sv_admin_add: Combined sv_admin_add and sv_admin_addh"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Fixed /e bug"
- changelog[#changelog+1] = "--Fixed spam_max and spam_timeout bugs"
- changelog[#changelog+1] = "--Fixed textban bugs"
- changelog[#changelog+1] = "--Fixed superban bugs"
- changelog[#changelog+1] = "--Fixed ipban bug"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 3.0.0 (released February 11th, 2013)"
- changelog[#changelog+1] = "--Update Reason: Bug Fixes and New Features"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Added safe guards for the admin system."
- changelog[#changelog+1] = "--Added Ping List command. Displays the Players ID, Name and Ping level."
- changelog[#changelog+1] = "--Added System for no Hash and/or IP admins"
- 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"
- changelog[#changelog+1] = "--Added a sv_status command. It will show the current status of defaults.txt commands."
- changelog[#changelog+1] = "--Added info shown to the sv_info command"
- changelog[#changelog+1] = "--Added 'sv_chatcommands' to enable or disable admin chat commands"
- changelog[#changelog+1] = "--Added 'sv_adminblocker' enables,disables or limits the abiliy of an admin to kick/ban another admin"
- changelog[#changelog+1] = "--Added 'sv_anticaps' Enables or Disables the use of caps in the server"
- changelog[#changelog+1] = "--Added 'sv_antispam' Enables or Disables the antispam system of the script"
- changelog[#changelog+1] = "--Added 'sv_spammax' Changes the max amount of messages that can be sent in 1 minute"
- changelog[#changelog+1] = "--Added 'sv_spamtimeout' Changes the time you are muted for spamming"
- 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."
- changelog[#changelog+1] = "--Added a way to use any command without the 'sv_' Ex: 'sv_admin_add' can be written as 'admin_add' "
- 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."
- changelog[#changelog+1] = "--Added 'sv_bosplayers' to see the available players that can be banned on sight."
- changelog[#changelog+1] = ""
- 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."
- changelog[#changelog+1] = "--Modified Tbag function"
- changelog[#changelog+1] = "--Modified ban, you are now able to send reason(s) for the ban which will be written a file."
- changelog[#changelog+1] = "--Modified kick, you are now able to send reason(s) for the kick which will be written a file."
- changelog[#changelog+1] = "--Modified Ipban, you are now able to send reason(s) for the ipban which will be written a file."
- changelog[#changelog+1] = "--Modified Superban, you are now able to send reason(s) for the superban which will be written a file."
- changelog[#changelog+1] = "--Modified Votekick. You can only votekick again after 1 minute has passed since last votekick."
- changelog[#changelog+1] = "--Modified ChangeLevel. The coding for this command has been improved."
- changelog[#changelog+1] = "--Modified GetHelp"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Fixed Ipban bug"
- changelog[#changelog+1] = "--Fixed the '/e' command."
- changelog[#changelog+1] = "--Fixed the 'sv_unmute' command."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Removed sv_command_type and all content related to it"
- changelog[#changelog+1] = "--Removed redundant code."
- changelog[#changelog+1] = "--Renamed 'sv_sa_message' to 'sv_serveradmin_message'"
- changelog[#changelog+1] = "--Renamed 'sv_fj_message' to 'sv_firstjoin_message'"
- changelog[#changelog+1] = "--Renamed 'sv_wb_message' to 'sv_welcomeback_message'"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 2.4.3 (released September 23rd,2012"
- changelog[#changelog+1] = "--Update Reason: Fixed issues with ServerChat Function."
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Fixed OnServerChat local function error caused Chat Commands to fail."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 2.4.2 (released August 29th,2012"
- changelog[#changelog+1] = "--Update Reason: Fixed issues from version 2.4.1 and new commands."
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = ""
- 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'"
- 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'"
- changelog[#changelog+1] = "--Added a Command Type command to the default.txt"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--ReAdded Private say command"
- changelog[#changelog+1] = "--ReAdded '/e' command."
- changelog[#changelog+1] = "--ReAdded Nuke Command."
- changelog[#changelog+1] = "--ReAdded SetName Command."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Modified Tbag function"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Fixed 'sv_info' command error"
- changelog[#changelog+1] = "--Fixed OnServerChat, now you wont get 'You are not allowed to use this command' every time you type."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 2.4.1 (released August 22nd,2012"
- changelog[#changelog+1] = "--Update Reason: Fixed issues from version 2.4"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Fixed 'sv_players_more' issue."
- changelog[#changelog+1] = "--Fixed 'sv_players' issue."
- 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."
- 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."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Removed Restriction of Portal Blocking. Warning: Modded Maps with portals might cause the server to crash. Hope to fix soon."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 2.4 (released August 19th,2012"
- changelog[#changelog+1] = "--Update Reason: New Features, Fix minor bugs, Remove non-working commands(will be re-add later), and Organize the Script"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = ""
- 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."
- changelog[#changelog+1] = "--Added a Portal Blocking Command. If someone is blocking a portal they will be killed. 'sv_pbdet'"
- changelog[#changelog+1] = "--Added a Private Messaging boolean for the @ in chat. 'sv_pvtmessage'"
- changelog[#changelog+1] = "--Added Private Messaging to the default.txt"
- changelog[#changelog+1] = "--Added a Tbagging function."
- changelog[#changelog+1] = "--Added a Tbagging Boolean Command. 'sv_tbagdet'"
- changelog[#changelog+1] = "--Added Tbagging Command to the default.txt"
- changelog[#changelog+1] = "--Added Killing spree Notifications"
- changelog[#changelog+1] = "--Added a Killing spree Notification command 'sv_killspree'"
- changelog[#changelog+1] = "--Added Killing spree Notification to the default.txt"
- changelog[#changelog+1] = "--Added a 'Welcome back' message in EventPlayerJoin. It will only say it if you are not an IP/Hash Admin"
- changelog[#changelog+1] = "--Added a Welcome back message command. 'sv_welcomeback_message'"
- changelog[#changelog+1] = "--Added Welcome Back Message to the default.txt"
- changelog[#changelog+1] = "--Added a 'This is the players first time joining the server' message in EventPlayerJoin"
- changelog[#changelog+1] = "--Added a Command for Server Admin Message. 'sv_sa_message'"
- changelog[#changelog+1] = "--Added Server Admin message to the default.txt"
- changelog[#changelog+1] = "--Added a Command for First Joining Message 'sv_firstjoin_message'"
- changelog[#changelog+1] = "--Added First Joining Message to the default.txt"
- changelog[#changelog+1] = "--Added a Command for Unique Counting. 'sv_uniques_enabled'"
- changelog[#changelog+1] = "--Added Unique Counting to the default.txt"
- 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."
- changelog[#changelog+1] = "--Added IP to the info Command."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Fixed RTV Enabled Command "
- changelog[#changelog+1] = "--Fixed VoteKick Enabled Command "
- changelog[#changelog+1] = "--Fixed info command. "
- changelog[#changelog+1] = "--Fixed time current command. "
- changelog[#changelog+1] = "--Fixed Set Teleport Shortcut. 'sv_st' "
- changelog[#changelog+1] = "--Fixed Teleport Delete Shortcut. 'sv_t del'"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Modified 'sv_players' command. Now it only gives you playerId ID, playerId Name, and playerId Team."
- changelog[#changelog+1] = "--Modified 'sv_count' command. Now disables if 'sv_uniques_enabled' is disabled."
- changelog[#changelog+1] = "--Modified Chat Commands: all commands can now be used in chat. Note: Some shortcuts have been transfered but not all."
- changelog[#changelog+1] = "--Modified GetHelp Commnad"
- changelog[#changelog+1] = "--Modified List Command"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Removed 'sv_unban' command from the script. Caused the OnSeverCommand local function to crash."
- changelog[#changelog+1] = "--Removed Private say command"
- changelog[#changelog+1] = "--Removed '/e' command."
- changelog[#changelog+1] = "--Removed Nuke Command."
- changelog[#changelog+1] = "--Removed SetName Command."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Access level crash fixes and a few other features"
- changelog[#changelog+1] = "--Organized all of the Functions"
- changelog[#changelog+1] = "--Commented all Main Functions. This will only show on the Commented version of the script"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 2.3 (released June 13th 2012"
- changelog[#changelog+1] = "Mainly fixed up the admin system"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = ""
- 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..."
- changelog[#changelog+1] = "--Added a /scorelimit and a sv_scorelimit command"
- changelog[#changelog+1] = "--Added a /a del command."
- changelog[#changelog+1] = "--Added sv_ipadminadd to the rcon"
- changelog[#changelog+1] = "--Added a patch that will allow new gametypes to be added without restarting the server"
- changelog[#changelog+1] = "--Added textbanning. It's like the mute command except it's a permanent"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Modified the AdminList command. Shows a lot more now."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Fixed rcon commands so that the responses show up with the /e command"
- changelog[#changelog+1] = "--Fixed the ipban command (whoops)"
- changelog[#changelog+1] = "--Fixed a very small problem with the setcolor command."
- changelog[#changelog+1] = "--Fixed up the timelimit command :)"
- changelog[#changelog+1] = "--Fixed ipadmins. They can now use the rcon."
- changelog[#changelog+1] = ""
- 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"
- changelog[#changelog+1] = "turned into admins.txt, don't worry, it's supposed to do that."
- changelog[#changelog+1] = "--This script enables CE devmode commands (cheat_deathless_player, cheat_medusa, etc)"
- changelog[#changelog+1] = "--IP admins no longer get removed when you unload the commands script"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 2.201 (released on June 5th 2012)"
- changelog[#changelog+1] = "This is mainly just a bug fix version"
- changelog[#changelog+1] = "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Added a /setscore and sv_setscore command."
- changelog[#changelog+1] = "--Added New functionality to /hax and /unhax"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Modified setkills, setassists, and setdeaths to work a little cleaner"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Fixed /commands to show all of the commands."
- changelog[#changelog+1] = "--Fixed a weird problem with the /enter command (when you ejected it would crash your game)"
- 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)"
- changelog[#changelog+1] = "--Fixed falldamage (and also made it so longer falls don't kill you)"
- 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)"
- 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)"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 2.2 (Released on June 1st 2012)"
- changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Added unique player tracking. It will keep track of the number of unique players who joined the server"
- changelog[#changelog+1] = "--Added '/count' Get the number of unique players"
- changelog[#changelog+1] = "--Added /balance, it executes sv_teams_balance in console"
- changelog[#changelog+1] = "--Added sv_privatesay. Looks like i forgot the sv_command for that"
- changelog[#changelog+1] = "--Added private chat. Use @(playerId expression) to message someone"
- changelog[#changelog+1] = "--Added /setcolor. Only works in FFA gametypes."
- changelog[#changelog+1] = "--Added namebanning to superban."
- changelog[#changelog+1] = "--Added a \ameban command."
- changelog[#changelog+1] = "--Added ipadmin deleting"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Modifed 'sv_map' made it so that the sv_map and /m loads the commands script by default"
- changelog[#changelog+1] = "--Modified the AdminList local function to be a lot more useful"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Fixed Bugs"
- changelog[#changelog+1] = "--Fixed votekick."
- changelog[#changelog+1] = "--Fixed /privatesay. It would only let you message one word before"
- changelog[#changelog+1] = "--Fixed access levels for the script. It kind of worked, but not really."
- changelog[#changelog+1] = "--Fixed an issue with /timelimit and sv_time_cur"
- changelog[#changelog+1] = "--Fixed deathless glitch"
- changelog[#changelog+1] = ""
- 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)"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 2.001"
- changelog[#changelog+1] = "--Fixed /ipadminadd "
- changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 2.0(Released April 22nd, 2012)"
- 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:"
- changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = ""
- 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)."
- 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."
- changelog[#changelog+1] = "--Added /os, this will give you an Overshield (syntax is /os [playerId])"
- changelog[#changelog+1] = "--Added a command to view all admins on the server, syntax is: /a list"
- changelog[#changelog+1] = "--Added a command to view the current admins in the server. Syntax is: /viewadmins"
- changelog[#changelog+1] = "--Added a command to view the server specs (processor speed, model name, manufacturer). Syntax is /specs, or sv_specs in console"
- 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"
- changelog[#changelog+1] = "--Added version changing. You can change to any version of Halo. Syntax is: /version {version} or sv_version {version} in console."
- 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)"
- changelog[#changelog+1] = "--Added a defaults.txt. This text file gets called on server startup."
- changelog[#changelog+1] = "--Added a sv_commands and a /commands. This will show all the commands that exist for this script."
- 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."
- changelog[#changelog+1] = "--Added a parameter to '/spd'. Syntax is /spd [playerId] {speed}. Doing /spd [playerId] will show you their current speed."
- changelog[#changelog+1] = "--Added another parameter to '/t'. Syntax is '/t list', this will show you the list of teleports for the map."
- changelog[#changelog+1] = "--Added infinite nades to sv_infinite_ammo"
- changelog[#changelog+1] = "--Added a '/banlist' command to chat. This will show you the banlist."
- 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."
- changelog[#changelog+1] = "--Added sv_rtv_needed [decimal 0 to 1]"
- changelog[#changelog+1] = "--Added sv_votekick_needed [decimal 0 to 1]"
- changelog[#changelog+1] = "--Added sv_rtv_enabled [true or false, 1 or 0]"
- changelog[#changelog+1] = "--Added sv_votekick_enabled [true or false, 1 or 0]"
- changelog[#changelog+1] = "--Added ipbanning. Syntax is sv_ipban, sv_ipbanlist, sv_ipunban, and for chat: /ipban, /ipbanlist, /ipunban."
- changelog[#changelog+1] = "--Added 'sv_launch' and '/launch'. Syntax is 'sv_launch [playerId]' or '/launch [playerId]'"
- changelog[#changelog+1] = "--Added a control command. Syntax is 'sv_control [victim] [controller]' or '/c [victim] [controller]' in chat."
- changelog[#changelog+1] = "--Added a privatesay command. Syntax is 'sv_privatesay [playerId] [message]' or '/privatesay [playerId] [message]' in chat"
- 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)"
- 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."
- changelog[#changelog+1] = "--Added: Now includes logging. This will log directly to commands.log in the log folder"
- changelog[#changelog+1] = "--Added: If you do not have an access file, this script will make one for you."
- changelog[#changelog+1] = "--Added '/e' command."
- changelog[#changelog+1] = ""
- 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."
- changelog[#changelog+1] = "--Modified sv_afk was changed to 'sv_setafk'. Thought it was a better name for the command."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Fixed /setname, it will change your name, but for others to see it it requires a rejoin."
- changelog[#changelog+1] = "--Fixed the admin system, before you had to do sv_reloadscripts after you added someone, that's been fixed."
- 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."
- 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."
- changelog[#changelog+1] = "--Fixed smiley's BOS commands, thanks to bvigil for telling me what it was supposed to do."
- changelog[#changelog+1] = "--Fixed a bug with /tp and sv_teleport_pl, which were crashing when the other playerId was dead."
- changelog[#changelog+1] = "--Fixed /setplasmas, thank you sanity for the notice..."
- changelog[#changelog+1] = "--Fixed a reported bug with /noweapons... I was never able to reproduce it, so I must have indirectly fixed it."
- changelog[#changelog+1] = "--Fixed /info which would crash when you used a playerId expression that was not a number."
- changelog[#changelog+1] = "--Fixed a couple of bugs with rtv and votekick (whoops)"
- changelog[#changelog+1] = "--Fixed a bug with 'sv_mute' and '/mute'. You can no longer mute admins."
- changelog[#changelog+1] = "--Fixed /st. This will set a teleport location to wherever you are standing. Syntax is: /st [teleport name]"
- changelog[#changelog+1] = "--Fixed the spawngun. Syntax is /setmode (playerId) spawngun (object)"
- 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."
- changelog[#changelog+1] = ""
- 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."
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = "Commands Version 1.0"
- changelog[#changelog+1] = "First Official Release (January or something 2012)"
- changelog[#changelog+1] = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
- changelog[#changelog+1] = ""
- changelog[#changelog+1] = "--Script Created"
- file:write(concat(changelog, "\n"))
- file:close()
- end
- function tempBanPlayer(playerIndex)
- halo_svcmd("sv_ban " .. playerIndex .. " 1s")
- return false
- end
- local function addBan(player_name, player_hash, player_ip, ban_time, ban_type, ban_reason)
- local banid, ban_entry, bancount, name, reason
- local args = defaults.remote_bansystem
- -- check if they've already been banned before
- for id = 1,#ban_table do ban_entry = ban_table[id]
- if not args or (ban_entry.remote and args.mode >= 1 or not ban_entry.remote and args.mode ~= 2) then
- if ban_type == ban_entry.type then
- if player_hash and player_hash == ban_entry.hash then
- banid = id
- break
- elseif player_ip and ban_entry.ip and netMatch(ban_entry.ip, player_ip) then
- banid = id
- break
- end
- end
- end
- end
- if banid then
- bancount = ban_entry.count + 1
- name = ban_entry.name
- reason = ban_entry.reason
- else
- bancount = 1
- banid = #ban_table+1
- ban_entry = {}--TM.New()
- end
- ban_entry.count = bancount
- ban_entry.name = (name and not find(name, player_name) and (name .. " / ") or "") .. player_name
- ban_entry.hash = player_hash
- ban_entry.ip = player_ip
- ban_entry.time = ban_time > 0 and ban_time + os.time() or ban_time == -1 and -1 or ban_penalty[bancount]
- ban_entry.type = ban_type
- ban_entry.reason = (reason and not find(reason, ban_reason) and (reason .. " / ") or "") .. ban_reason
- ban_table[banid] = ban_entry
- if args and args.mode >= 2 then
- --print("ADDING TO REMOTE BANLIST. Host: " .. tostring(args.http_source) .. " Body: " .. tostring("&bans=" .. toBanTextEntry(ban_entry)))
- print(http.request(args.http_source, "&bans=" .. toBanTextEntry(ban_entry)) .. ",&unban=false")
- end
- updateBanFiles(bantype)
- end
- local function checkaccess(command, access)
- command = Commands[command] or command
- local access_entry = access_table[access]
- return access_entry and (access_entry.allcommands or access_entry[command]) or false
- end
- -- Returns true if equal, false if both not admin, or the playerId more powerful.
- -- It's important to note that if the Server is being compared as a playerId, it's value is nil.
- local function getMorePowerfulPlayer(playerId1, playerId2)
- -- the Server is the most powerful admin.
- if not playerId1 then
- return not playerId2 or playerId1
- elseif not playerId2 then
- return not playerId1 or playerId2
- end
- local access1 = access_table[getaccess(playerId1)]
- access1 = access1 and #access1 or -1
- local access2 = access_table[getaccess(playerId2)]
- access2 = access2 and #access2 or -1
- return access1 > access2 and playerId1 or access1 < access2 and playerId2 or access1 > 0
- end
- local function checkAdminBlockerAccess(executorPlayerId, playerId)
- local allowed = getMorePowerfulPlayer(executorPlayerId, playerId)
- return defaults.adminblocker == "Unsafe" or defaults.adminblocker == "Lenient" and (allowed == executorPlayerId or allowed == true) or defaults.adminblocker == "Moderate" and allowed == executorPlayerId or access_table[getaccess(executorPlayerId)] == -1
- end
- local function Say(message)
- for playerId = 0,15 do
- if getplayer(playerId) then
- sendconsoletext(playerId, message)
- end
- end
- end
- local function capitalizeWords(str, amount)
- return gsub(str, '(%a)(%a+)', function(cap, rest) return ('%1'):upper() .. '%2' end)
- end
- local function trim(str)
- return gsub(str, "^%s*(.-)%s*$", "%1")
- end
- local function tokenizecmdstring(str, tblToReuse)
- local strParts = --[[type(tblToReuse) == "table" and tblToReuse:deleteEntries() and tblToReuse or--]] {}--TM.New()
- --remove spaces at beginning and end
- str = trim(str) .. " "
- -- return if no delims found
- if not find(str, '[%s"]') then strParts[1] = str return strParts end
- local strPart, newPos, pos
- repeat
- strPart,newPos = match(str, '^"(.-)"%s+()', pos)
- if not strPart then
- strPart,newPos = match(str, '([^%s]+)%s+()', pos)
- elseif find(strPart, " ") then
- strPart = '"' .. strPart .. '"' -- keep quotes around em
- end
- pos = newPos
- strParts[#strParts+1] = strPart
- until not strPart
- ::returnSplits::
- return strParts
- end
- local function tokenizestring(str, ...)
- local tblToReuse = select(-1, ...)
- 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
- local subs = type(tblToReuse) == "table" and tblToReuse or {}--TM.New()
- if (...) == "" then
- for i = 1,#str do
- subs[#subs+1] = sub(str, i, i)
- end
- return subs
- end
- local strPart = ""
- local char, iter, delim
- for i = 1,#str do
- char = sub(str, i, i)
- iter = 1
- delim = select(iter, ...)
- repeat
- if delim == char then
- strPart = sub(strPart, 1, -1)
- if strPart ~= "" then
- subs[#subs+1] = strPart
- strPart = ""
- goto continue
- end
- end
- iter = iter + 1
- delim = select(iter, ...)
- until not delim or delim == select(-1, ...)
- strPart = strPart .. char
- ::continue::
- end
- if strPart ~= "" then
- subs[#subs+1] = strPart
- end
- return subs
- end
- -- This function is responsible for creating a command.
- -- I am using table functions in this manner because it is easier to parse commands in groups, it saves me from copying and pasting already existing code.
- -- It also allows me to check to see if the command was coded correctly (before LUA sends an unhelpful error message)
- -- This also allows me to use command aliases, merge help info. It basically keeps all information about a command in one place.
- -- To an average joe reading this script, it may be harder to use this method if you aren't familiar with table structures, but it's better in the end because it is more organized.
- -- Arguements are the name of the command, the commandInfo (as a table, containing aliases, help, and boolean information like scrimMode usage, and each function called for different command arguments (for example, /enter (player) (player2) (seat) vs /enter (vehicleName))
- function Commands.Create(cmdName, commandInfo, ...)
- -- Display errors if a command was created incorrectly.
- if not commandInfo.help then error("NO HELP INFO IN COMMAND CREATION: " .. cmdName) end
- local thisCmdFunc
- for i = 1,select("#", ...) do
- thisCmdFunc = select(i, ...)
- assert(thisCmdFunc.arguments, "NO ARGUMENTS IN COMMAND CREATION: " .. cmdName)
- assert(thisCmdFunc.arguments.minArgs, "NO MINIMUM ARGUMENTS IN COMMAND CREATION: " .. cmdName)
- assert(thisCmdFunc.arguments.maxArgs, "NO MAXIMUM ARGUMENTS IN COMMAND CREATION: " .. cmdName)
- assert(type(thisCmdFunc.func) == "function", "BAD FUNCTION IN COMMAND CREATION: " .. type(thisCmdFunc.func) .. ": " .. cmdName)
- end
- --stupid tabs...
- commandInfo.help = gsub(commandInfo.help, "\t", "")
- -- Create this command with properties from the Commands class.
- local newCommand = {name = cmdName, info = commandInfo, ...}
- setmetatable(newCommand, Commands)
- -- set command aliases
- local aliases = commandInfo.aliases
- if aliases then
- local commandAliases = Commands.commandAliases
- local alias_name
- for i = 1,#aliases do alias_name = aliases[i]
- commandAliases[alias_name] = cmdName
- Commands[alias_name] = newCommand
- end
- end
- -- Add this command to the Command list.
- Commands[cmdName] = newCommand
- Commands[#Commands+1] = cmdName
- end
- -- This function is called whenever a command is attempting to execute.
- -- Execution function is responsible for determining which overloaded command function to execute
- -- In the case of the user using incorrect arguments, this function will parse an error message to respond with.
- function Commands.Execute(thisCommand, arguments, command, executorPlayerId)
- local parsedArguments, newErr
- local err = ""
- -- Loop through all overloaded functions for this command.
- for i = 1,#thisCommand do
- -- Validate and parse all arguments
- parsedArguments, newErr = thisCommand:validateArguments(arguments, thisCommand[i].arguments, command, executorPlayerId)
- -- have they passed the correct arguments for this overloaded command?
- if parsedArguments == true then
- sendresponse(newErr, executorPlayerId)
- return
- elseif newErr == "" then
- -- call the command, and stop looping.
- thisCommand[i].func(executorPlayerId, thisCommand:unpackArguments(parsedArguments))
- return
- else
- err = err .. "\n" .. newErr
- end
- end
- sendresponse(err .. gsub(thisCommand.info.help, ".-Syntax: %%s(.-)", "\nInvalid Syntax: " .. command .. "%1"), executorPlayerId)
- end
- -- Needed because I need to pass a specific amount of arguments to command functions.
- function Commands:unpackArguments(myTable)
- for i = 1,#myTable do
- if myTable[i] == nil then
- myTable[i] = false
- end
- end
- return table.unpack(myTable, 1, #myTable)
- end
- -- Validates and parses an argument table
- -- Returns command arguments into lua arguments the Execute function can use.
- -- This function alone is one of the main reasons I converted my if-elseif commands into a metatable. It saved me sooo much duplicate lines of code in the individual commands.
- function Commands:validateArguments(arguments, argumentTypes, command, executorPlayerId)
- local err = ""
- local minArgs, maxArgs = argumentTypes.minArgs, argumentTypes.maxArgs
- -- Make sure they are actually passing a second argument.
- if not arguments[1] and minArgs > 0 then
- return true, gsub(self.info.help, "^.-Syntax:.-%%s(.-)$", "\nCorrect Syntax: " .. command .. "%1")
- end
- local argument, argType, length
- local parsedArguments = {}--TM.New()
- for i = 1,#argumentTypes do argument = arguments[i]
- argType = argumentTypes[i]
- if not argument then
- if #parsedArguments < minArgs then
- err = err .. "\nToo few arguments passed to this command! Expected " .. minArgs .. " - " .. maxArgs .. " got " .. #parsedArguments
- goto ReturnArgs
- end
- else
- length = #argument
- end
- if argType == "Boolean" then
- if argument == "true" or argument == "1" then
- argument = true
- elseif argument == "false" or argument == "0" then
- argument = false
- elseif arguments[i] then
- 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"
- end
- elseif argType == "Percent" then
- argument = tonumber(argument)
- argument = argument and (argument <= 1 and argument >= 0 and argument * 100 or argument <= 100 and argument)
- err = not argument and "Invalid Percentage. Percent arguments must be between 0 and 100." or err
- elseif argType == "Player" then
- local players = getvalidplayers(argument, executorPlayerId)
- if players then
- argument = players
- elseif argument == nil and #arguments >= minArgs and executorPlayerId then
- argument = {executorPlayerId}
- elseif not argument then
- err = err .. "\nYou did not specify a Player!"
- else
- err = err .. "\n'" .. arguments[i] .. "' is not a valid Player!"
- end
- elseif argType == "Single Player" then
- local players = getvalidplayers(argument, executorPlayerId)
- if players then
- argument = players[1]
- err = players[2] and err .. "\n'" .. arguments[i] .. "' cannot reference more than one player in this command!" or err
- -- if player wasn't specified, use the executing player.
- elseif argument == nil and #arguments >= minArgs and executorPlayerId then
- argument = executorPlayerId
- elseif not argument then
- err = err .. "\nYou did not specify a player!"
- else
- err = err .. "\n'" .. arguments[i] .. "' is not a valid player!"
- end
- elseif argType == "Hash" then
- 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+")
- err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid Hash!" or err
- elseif argType == "IP Address" then
- argument = validate_ipv4(argument)
- err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid IP Address!" or err
- elseif argType == "Team" then
- argument = team_play and ("Red" and 0 or "Blue" and 1) or tonumber(argument)
- argument = argument and argument >= 0 and argument <= 15 and argument
- err = not argument and "The '" .. arguments[i] .. "' team does not exist!" or err
- elseif argType == "Time And Reason" then
- argument, parsedArguments[i+1] = getTimeAndReason(concat(arguments, " ", i), self.usesBanCounts and (PlayerClass[parsedArguments[i-1]].bancount or 0) or nil)
- elseif argType == "Time" then
- local temp
- argument, temp = getTimeAndReason(concat(arguments, " ", i), self.usesBanCounts and (PlayerClass[parsedArguments[i-1]].bancount or 0) or nil)
- err = temp ~= "None Given" and err .. "\n'" .. concat(arguments, " ", i) .. "' is an Incorrect Time!\nCorrect Examples: 5d 2h 3m 4s" or err
- elseif argType == "Time String" then
- local timeErr = not argument and "'" .. argument .. "' is an Incorrect Time!\nCorrect Examples: 5d 2h 3m 4s"
- if timeErr then goto TimeStringEnd end
- for j = i+1,#arguments do
- timeErr = not arguments[j] and "'" .. arguments[j] .. "' is an Incorrect Time!\nCorrect Examples: 5d 2h 3m 4s"
- if timeErr then break end
- argument = argument .. " " .. arguments[j]
- end
- ::TimeStringEnd::
- err = timeErr and err .. "\n" .. timeErr or err
- elseif argType == "Remaining Arguments" then
- --hprintf(concat(arguments, " ", i))
- argument = concat(arguments, " ", i)
- elseif argType == "Access Level" then
- argument = tonumber(argument)
- argument = argument and access_table[argument] and argument
- 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
- elseif argType == "Whole Number" then
- argument = tonumber(argument)
- argument = argument and argument >= 0 and argument
- err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a Whole (Non-Negative) Number!" or err
- elseif argType == "Positive Number" then
- argument = tonumber(argument)
- err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a Positive Number!" or err
- elseif argType == "Number" then
- argument = tonumber(argument)
- err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a Number!" or err
- elseif argType == "Password" then
- argument = length and length >= 4 and length <= 8 and argument
- err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a Password between 4 and 8 characters!" or err
- elseif argType == "Map" then
- argument = valid_maps[argument] and argument
- err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid Map!" or err
- elseif argType == "Object" then
- argument = objects[argument]
- err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid Object!" or err
- elseif argType == "Gametype" then
- argument = valid_gametypes[argument] and argument
- err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid GameType!" or err
- elseif argType == "String" then
- err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid argument for this command!" or err
- elseif argType == "AdminBlocker Type" then
- argument = tonumber(argument) or argument
- argument = (argument == 0 or argument == "Unsafe") and 0 or (argument == 1 or argument == "Lenient") and 1 or (argument == 2 or argument == "Moderate") and 2 or (argument == 3 or argument == "Strict") and 3 or argument == false and 0
- err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid AdminBlocker Type!" or err
- elseif argType == "Remote Banlist Mode" then
- argument = tonumber(argument) or argument
- argument = (argument == 0 or argument == "read-only") and 0 or (argument == 1 or argument == "one-way sync") and 1 or (argument == 2 or argument == "remote-only") and 2 or (argument == 3 or argument == "sync") and 3
- elseif argType == "Datatype" then
- 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
- err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid DataType!" or err
- elseif argType == "Struct" then
- argument = (argument == "player" or argument == "object" or argument == "weapon" or argument == "vehicle") and argument
- err = not argument and arguments[i] and err .."\n'" .. arguments[i] .. "' is not a valid Struct!" or err
- elseif argType == "Bit" then
- if argument == "true" or argument == "1" then
- argument = 1
- elseif argument == "false" or argument == "0" then
- argument = 0
- else
- err = err .. "\n'" .. arguments[i] .. "' is not a valid Bit!\nBits must be one of the following: true or 1, false or 0"
- end
- end
- parsedArguments[i] = argument
- end
- if #parsedArguments > maxArgs and #arguments > maxArgs then
- err = err .. "\nToo many Arguments passed to this command! Expected " .. minArgs .. " - " .. maxArgs .. " got " .. #parsedArguments
- end
- ::ReturnArgs::
- return parsedArguments, err
- end
- function Commands:AliasToCommand(cmd)
- return self.realname
- end
- local function getOperatingSystem()
- local slash_ident = package.config:sub(1,1)
- if slash_ident == "\\" then
- return "Windows"
- elseif slash_ident == "/" then
- return "Unix"
- end
- end
- -- I don't remember why I didn't want to use LFS, maybe I was worried it wouldn't work with SAPP.
- local function lookupFiles(dir)
- local files = {}
- local OS = getOperatingSystem()
- local p
- if OS == "Windows" then
- p = io.popen("dir " .. dir .. " /B /O:gn")
- elseif OS == "Unix" then
- p = io.popen('find "' .. dir .. '" -type f')
- end
- for file in p:lines() do
- insert(files, file)
- end
- end
- -- Script Validation
- function Commands:validscripts(...)
- local dir = getprofilepath() .. "\\scripts\\"
- local scripts = {}
- --LuaFileSystem Method.
- --[[
- require "lfs"
- for f in lfs.dir(dir) do
- if string.find(f, ".lua") then
- local file = io.open(dir .. f, "r")
- local str = file:read("*all")
- if string.find(str, "function GetRequiredVersion()") then
- if f ~= "gametypes.lua" then
- local script = string.gsub(f, ".lua", "")
- if not table.find(scripts, script) then
- table.insert(scripts, script)
- end
- end
- end
- end
- end--]]
- local bool
- local files = lookupFiles(dir)
- local scriptname = ""
- for i = 1,select("#", ...) do
- bool = false
- for i = 1,files do
- if files[i] == select(1, ...) then
- bool = true
- break
- end
- end
- if not bool then
- break
- end
- end
- end
- Commands.Create(
- "rconadd",
- {
- aliases = {"addrcon"},
- help = [[-- Add Rcon Password
- -- Syntax: %s [Password] {Level}
- -- Adds a global Rcon password to the list.
- -- These RCon passwords are different from the normal sv_rcon_password
- -- The difference is non-admins can use these, while sv_rcon_password only admins can use]]
- },
- {
- arguments = {"Password", "Access Level", minArgs = 1, maxArgs = 2},
- func = function(executorPlayerId, password, level)
- if rcon_passwords[password] then
- sendresponse(password .. " is already a rcon password", executorPlayerId)
- return
- end
- rcon_passwords[password] = level or 0
- sendresponse(password .. " has been added as a rcon password", executorPlayerId)
- end
- }
- )
- Commands.Create(
- "adminadd",
- {
- aliases = {"a", "addadmin"},
- help = [[-- Admin Add
- -- Syntax: %s [Player or Hash or IP Address] [Nickname] {Level} {Admin Type 'Hash' or 'IP'}
- -- Adds a person to the admin list.
- -- This command can take a Hash, IP, or Player as an argument.
- -- If you do not pass a level, they will automatically be added as a level 0 admin.
- -- The default for Admin Type is 'hash'. This argument is also case insensitive.]]
- },
- {
- arguments = {"Single Player", "String", "Access Level", "String", minArgs = 2, maxArgs = 4},
- func = function(executorPlayerId, playerId, nickname, level, admin_type)
- admin_type = admin_type and lower(admin_type) or "hash"
- if admin_type ~= "hash" and admin_type ~= "ip" then
- sendresponse("'" .. admin_type .. "' is not a valid Admin Type!", executorPlayerId)
- return
- end
- if not match(nickname, "[%l%u]+") then
- sendresponse("Admin nicknames must only contain letters.", executorPlayerId)
- return
- end
- if PlayerClass[playerId].admin_entry then
- sendresponse(getname(playerId) .. " is already a " .. admin_type .. " admin", executorPlayerId)
- return
- end
- -- Create a new admin entry
- local newAdmin = {}--TM.New()
- newAdmin.name = nickname
- newAdmin.level = level or 0
- newAdmin.type = admin_type
- -- Add the admin entry to the admin table.
- admin_table[admin_type == "hash" and gethash(playerId) or (getip(playerId) .. "/24")] = newAdmin
- PlayerClass[playerId].admin_entry = newAdmin
- updateAdminFiles()
- sendresponse(getname(playerId) .. " is now a " .. admin_type .. " admin!", executorPlayerId)
- end
- },
- {
- arguments = {"Hash", "String", "Access Level", minArgs = 2, maxArgs = 3},
- func = function(executorPlayerId, hash, nickname, level)
- if not match(nickname, "%l+") then
- sendresponse("Admin nicknames must only contain letters.", executorPlayerId)
- return
- end
- for i = 1,#sharedhashes do
- if hash == sharedhashes[i] then
- sendresponse("This is a shared hash, and therefore cannot become an admin.", executorPlayerId)
- return
- end
- end
- if admin_table[hash] then
- sendresponse("That Hash is already an admin.", executorPlayerId)
- return
- end
- -- Create a new admin entry
- local newAdmin = {}--TM.New()
- newAdmin.name = nickname
- newAdmin.level = level or 0
- newAdmin.type = "hash"
- -- Add the admin entry to the admin table.
- admin_table[hash] = newAdmin
- for playerId = 0,15 do
- if gethash(playerId) == hash then
- PlayerClass[playerId].admin_entry = newAdmin
- end
- end
- updateAdminFiles()
- sendresponse("That hash has been successfully added to the admin list.", executorPlayerId)
- end
- },
- {
- arguments = {"IP Address", "String", "Access Level", minArgs = 2, maxArgs = 3},
- func = function(executorPlayerId, ip_address, nickname, level)
- if not match(nickname, "%l+") then
- sendresponse("Admin nicknames must only contain letters.", executorPlayerId)
- return
- end
- for index,thisAdmin in next,admin_table do
- if thisAdmin.type == "ip" and netMatch(index, ip_address) then
- sendresponse("That IP Address is already an admin.", executorPlayerId)
- return
- end
- end
- -- Create a new admin entry
- local newAdmin = {}--TM.New()
- newAdmin.name = nickname
- newAdmin.level = level or 0
- newAdmin.type = "ip"
- -- Add the admin entry to the admin table.
- admin_table[ip_address] = newAdmin
- for playerId = 0,15 do
- if getplayer(playerId) then
- if netMatch(ip_address, getip(playerId)) then
- PlayerClass[playerId].admin_entry = newAdmin
- end
- end
- end
- updateAdminFiles()
- sendresponse("That IP Address has been successfully added to the admin list.", executorPlayerId)
- end
- }
- )
- Commands.Create(
- "admindel",
- {
- aliases = {"deladmin", "revoke", "a del", "adminrevoke", "revokeadmin"},
- help = [[-- Admin Delete
- -- Syntax: %s [Player or Admin Nickname]
- -- Removes an admin from the admin list by nickname or playerIndex.
- -- Use 'sv_admin_list' to get a list of admins for their nickname.
- -- You can also pass a player to this command.]]
- },
- {
- arguments = {"Player", minArgs = 1, maxArgs = 1},
- func = function(executorPlayerId, players)
- local playerId, ip
- for i = 1,#players do playerId = players[i]
- if not PlayerClass[playerId].admin_entry then
- cmdreply[cmdreply()] = getname(playerId) .. " was never an admin"
- goto continue
- end
- admin_table[gethash(playerId)] = nil
- ip = getip(playerId)
- for index,thisAdmin in next,admin_table do
- if thisAdmin.type == "ip" and netMatch(index, ip) then
- admin_table[index] = nil
- end
- end
- PlayerClass[playerId].admin_entry = false
- updateAdminFiles()
- cmdreply[cmdreply()] = getname(playerId) .. " is no longer an admin"
- ::continue::
- end
- sendresponse(cmdreply, playerId)
- end
- },
- {
- arguments = {"String", minArgs = 1, maxArgs = 1},
- func = function(executorPlayerId, nickname)
- if not next(admin_table) then
- sendresponse("There are no admins on this server.", executorPlayerId)
- return
- end
- for k,thisAdmin in next,admin_table do
- if thisAdmin.name == nickname then
- admin_table[k] = nil
- sendresponse(nickname .. " is no longer an admin", executorPlayerId)
- updateAdminFiles()
- local player
- for playerId = 0,15 do player = PlayerClass[playerId]
- if getplayer(playerId) and player and player.admin_entry == thisAdmin then
- player.admin_entry = false
- end
- end
- return
- end
- end
- sendresponse("There are no admins with a nickname of '" .. nickname .. "'", executorPlayerId)
- end
- }
- )
- Commands.Create(
- "setafk",
- {
- aliases = {"afk"},
- help = [[-- Set AFK Player
- -- Syntax: %s [Player]
- -- Sets the specified player to the AFK status.]]
- },
- {
- arguments = {"Player", minArgs = 1, maxArgs = 1},
- func = function(executorPlayerId, players)
- local playerId
- for i = 1,#players do playerId = players[i]
- PlayerClass[playerId].afk = true
- cmdreply[cmdreply()] = getname(playerId) .. " is now afk"
- end
- sendresponse(cmdreply, executorPlayerId)
- end
- }
- )
- local function check_in_circle(x,y, X, Y, R)
- return (X - x)^2 + (Y - y)^2 <= R
- end
- -- Not finished
- Commands.Create(
- "bubble",
- {
- help = [[-- Bubble
- -- Syntax: %s [Player] {Radius}
- -- Puts a bubble around the player, so people cannot enter it.]]
- },
- {
- arguments = {"Player", minArgs = 1, maxArgs = 2},
- func = function(executorPlayerId, players, radius)
- radius = radius or 5
- local playerId
- for i = 1,#players do playerId = players[i]
- PlayerClass[playerId].bubble = true
- cmdreply[cmdreply()] = getname(playerId) .. " is now in a bubble with radius of " .. radius
- end
- sendresponse(cmdreply, executorPlayerId)
- end
- }
- )
- Commands.Create(
- "adminlist",
- {
- aliases = {"admins", "listadmins", "alist"},
- help = [[-- Admin List
- -- Syntax: %s {Type}
- -- Shows a list of all Admins
- -- Type can be either 'IP', 'Hash', or 'Temp' for filtering.]]
- },
- {
- arguments = {"String", minArgs = 0, maxArgs = 1},
- func = function(executorPlayerId, admin_type)
- cmdreply.header = "[Name | Level | Admin Type]"
- cmdreply.align = true
- cmdreply.delim = "|"
- local hash_admin, ip_admin
- for index,thisAdmin in next,admin_table do
- cmdreply[cmdreply()] = thisAdmin.name .. " | " .. thisAdmin.level .. " | " .. thisAdmin.type .. " Admin"
- end
- sendresponse(cmdreply, executorPlayerId)
- end
- }
- )
- Commands.Create(
- "aliasold",
- {
- aliases = {"oldalias"},
- help = [[-- Alias
- -- Syntax: %s [player]
- -- Shows all names used with the hash]]
- },
- {
- arguments = {"Player", minArgs = 1, maxArgs = 1},
- func = function(executorPlayerId, players)
- local playerId
- for i = 1,#players do playerId = players[i]
- halo_svcmdplayer("sv_alias_hash " .. resolveplayer(playerId), executorPlayerId)
- end
- end
- }
- )
- -- 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.
- local function ReturnScriptBooleanCheck(boolName, boolCheck, argBool)
- local are_is = sub(boolName, -1, -1) == "s" and "are" or "is" -- lol
- if argBool == nil then
- return nil, boolName .. " is currently " .. (boolCheck == true and "On" or boolCheck == false and "Off" or tostring(boolCheck))
- end
- local response
- if argBool then
- if not boolCheck then
- response = boolName .. " " .. are_is .. " now on"
- else
- argBool = nil
- response = "(*) " .. boolName .. " " .. are_is .. " already enabled"
- end
- elseif not argBool then
- if boolCheck then
- response = boolName .. " " .. are_is .. " now off"
- else
- argBool = nil
- response = "(*) " .. boolName .. " " .. are_is .. " already off"
- end
- end
- return argBool, response
- end
- -- Scripted Game Boolean Commands
- Commands.Create(
- "remotecontrol",
- {
- help = [[-- Remote Control
- -- Syntax: %s {Port or Boolean}
- -- Starts or shuts down the remote control feature.
- -- Use a telnet client like Putty to connect
- -- This command REQUIRES using global rcons (sv_rcon_add). This may be changed later.]],
- },
- {
- arguments = {"Positive Number", minArgs = 0, maxArgs = 1},
- func = function(executorPlayerId, port)
- if not socket then
- socket = require"socket"
- http = require"socket.http"
- http.TIMEOUT = 1
- end
- port = port <= 65535 and port > 800 and port or error("Ports must be between 65535 and 800. 2303 is recommended.")
- if port then
- server = socket.tcp()
- assert(server:bind("*", port))
- assert(server:listen(9001))
- server:settimeout(0)
- sendresponse("The Remote Control server has been opened on port " .. tostring(port))
- defaults.remotecontrol = registertimer(500, "remoteTimer")
- else
- sendresponse("Remote Control is enabled and currently has " .. #clients .. " clients connected.", executorPlayerId)
- end
- end
- },
- {
- arguments = {"Boolean", minArgs = 0, maxArgs = 1},
- func = function(executorPlayerId, strBool)
- local newBool = ReturnScriptBooleanCheck("Remote Control", defaults.remotecontrol, strBool)
- if newBool then
- if not socket then
- socket = require"socket"
- http = require"socket.http"
- http.TIMEOUT = 1
- end
- server = socket.tcp()
- assert(server:bind("*", 2303))
- assert(server:listen(9001))
- server:settimeout(0)
- sendresponse("The Remote Control server has been opened on port 2303", executorPlayerId)
- defaults.remotecontrol = registertimer(500, "remoteTimer")
- elseif newBool == false then
- for i = 1,#clients do
- clients[i].socket:close()
- end
- server:close()
- server = nil
- end
- end
- }
- )
- Commands.Create(
- "anticaps",
- {
- aliases = {"disablecaps", "nocaps"},
- help = [[-- AntiCaps
- -- Syntax: %s {Boolean}
- -- Enables or Disables the use of caps in the server]]
- },
- {
- arguments = {"Boolean", minArgs = 0, maxArgs = 1},
- func = function(executorPlayerId, strBool)
- local newBool, response = ReturnScriptBooleanCheck("Anticaps", defaults.anticaps, strBool)
- if newBool ~= nil then
- defaults.anticaps = newBool
- end
- sendresponse(response, executorPlayerId)
- end
- }
- )
- Commands.Create(
- "chatcommands",
- {
- help = [[-- ChatCommands
- -- Syntax: %s {Boolean}
- -- Enable/Disable Chat Commands for Admins]]
- },
- {
- arguments = {"Boolean", minArgs = 0, maxArgs = 1},
- func = function(executorPlayerId, strBool)
- local newBool, response = ReturnScriptBooleanCheck("Chat Commands", defaults.chatcommands, strBool)
- if newBool ~= nil then
- defaults.chatcommands = newBool
- end
- sendresponse(response, executorPlayerId)
- end
- }
- )
- Commands.Create(
- "chatids",
- {
- aliases = {"chatid", "showplayernumbers"},
- help = [[-- Show Player IDs In Chat
- -- Syntax: %s {Boolean}
- -- Enable/Disable the showing of Player IDs in the chat.]]
- },
- {
- arguments = {"Boolean", minArgs = 0, maxArgs = 1},
- func = function(executorPlayerId, strBool)
- local newBool, response = ReturnScriptBooleanCheck("Chat IDs", defaults.chatids, strBool)
- if newBool ~= nil then
- defaults.chatids = newBool
- end
- sendresponse(response, executorPlayerId)
- end
- }
- )
- function invisCrouch(id, count)
- if not defaults.crouch_camo then return false end
- for playerId = 0,15 do
- local m_playerObj = getplayerobject(playerId)
- if m_playerObj and readbyte(m_playerObj + 0x2A0) == 3 then
- applycamo(playerId, 1)
- end
- end
- return true
- end
- Commands.Create(
- "crouchcamo",
- {
- aliases = {"tigermode", "ninja", "ninjamode"},
- help = [[--Enable or Disable Crouch Camo
- -- Syntax: %s {Boolean}
- -- Enables or Disables the use of crouch camo]],
- },
- {
- arguments = {"Boolean",