--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 \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", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, players, strBool) local newBool, response = ReturnScriptBooleanCheck("Crouch Camo", defaults.crouch_camo, strBool) if newBool then registertimer(200, "invisCrouch") defaults.crouch_camo = true elseif newBool ~= nil then defaults.crouch_camo = false end sendresponse(response, executorPlayerId) end } ) --REM possibly rehaul this later, to include output to server consoles, to change the verbosity level of info, etc -- Currently, this function enables certain debug messages I've deemed important enough to display. -- Will output to the server's console, and to the player's in-game console. Commands.Create( "debug", { aliases = {"debugmode", "toggledebug", "enabledebug", "verbose"}, help = [[--Debug Mode -- Syntax: %s {Boolean} {Player} -- Turns on this scripts Debug messages, to help identify an issue with the script. -- Note: Will enable debug mode for executing player even if a player is specified]] }, { arguments = {"Boolean", "Player", minArgs = 0, maxArgs = 2}, func = function(executorPlayerId, strBool, players) local newBool, response = ReturnScriptBooleanCheck("Debug Mode", defaults.debug_mode, strBool) if newBool ~= nil then defaults.debug_mode = newBool if players then local playerId for i = 1,#players do playerId = players[i] debug_players[playerId] = newBool end elseif executorPlayerId ~= nil then debug_players[executorPlayerId] = newBool end end sendresponse(response, executorPlayerId) end } ) Commands.Create( "uniquesenabled", { aliases = {"uniqueplayercounting"}, help = [[-- Unique Player Counting -- Syntax: %s {Boolean} -- Enables/Disables the Unique Player Counting feature.]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("Unique Player Counting", defaults.uniques_enabled, strBool) if newBool then local file = io.open(profilepath .. "uniques.txt") if not file then return end local index,ip,joincount,names for line in file:lines() do -- ignore blank lines if match(line, "%g%g%g+") then unique_table.total = unique_table.total + 1 index,joincount,names = match(line, "^(.+),(%d+),(.-)$") if index then names = tokenizestring(names, ",") unique_table[index] = {joincount = joincount, names = names} else names,index,ip = match(line, "^(.-),(%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x+),(.-)$") if names and validate_ipv4(ip) then joincount = 1 unique_table[ip] = {joincount = 1, names = {names}} unique_table[match(ip, "%d+%.%d+%.%d+%.")] = {joincount = 1, names = {names}} end end end end file:close() elseif newBool ~= nil then defaults.uniques_enabled = false end sendresponse(response, executorPlayerId) end } ) Commands.Create( "deathless", { aliases = {"d", "deathlessplayer", "deathlessmode"}, scrimBlock = true, help = [[-- Deathless Players -- Syntax: %s {Boolean} -- Enables/Disables the Deathless Players mode. -- Players cannot die while this mode is enabled (obviously). -- The default for this command is (obviously) Off]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("Deathless Player", defaults.deathless, strBool) if newBool ~= nil then defaults.deathless = newBool end sendresponse(response, executorPlayerId) end } ) Commands.Create( "falldamage", { scrimBlock = true, help = [[-- Fall Damage -- Syntax: %s [Boolean] -- Enable/Disable the damage players receive from falling. -- The default for this command is: Enabled]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("Falldamage", defaults.falldamage, strBool) if newBool ~= nil then defaults.falldamage = newBool end sendresponse(response, executorPlayerId) end } ) Commands.Create( "firstjoinmessage", { help = [[-- First Join Message -- Syntax: %s [Boolean] -- Enable/Disable the First Join Message. -- The default for this command is: Enabled.]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("First Join Message", defaults.firstjoin_message, strBool) if newBool ~= nil then defaults.firstjoin_message = newBool end sendresponse(response, executorPlayerId) end } ) Commands.Create( "centralbanlist", { aliases = {"centralbansystem", "remotebansystem", "remotebanlist", "globalbansystem", "globalbanlist", "masterbansystem", "masterbanlist"}, help = [[-- Remote Ban System -- Syntax: %s [Host or Boolean] {PHP Script} {Ban File} {Method} -- Changes how the remote ban system works -- Check out the manual for information on this feature. -- This feature is off by default.]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("Remote Ban System", not not defaults.remote_bansystem, strBool) if newBool == false then defaults.remote_bansystem = newBool elseif newBool then sendresponse("This feature cannot simply be enabled. You must pass a hostname, file, mode, etc.\nCheck out the manual for more information", executorPlayerId) return end sendresponse(response, executorPlayerId) end }, { arguments = {"String", "String", "String", "Remote Banlist Mode", "Positive Number", minArgs = 4, maxArgs = 5}, func = function(executorPlayerId, host, phpscript, banfile, mode, port) if not socket then socket = require"socket" http = require"socket.http" http.TIMEOUT = 1 end defaults.remote_bansystem = { host = host, phpscript = phpscript, banfile = banfile, mode = mode, http_source = "http://" .. host .. "/" .. phpscript, port = port or 80 } if mode == 0 then -- read-only elseif mode == 1 then -- one way (read-only) sync elseif mode == 2 then -- remote-only elseif mode == 3 then -- sync end reloadRemoteBanlist() updateBanFiles() sendresponse("The Remote Ban System is now enabled!", executorPlayerId) end } ) Commands.Create( "firefist", { aliases = {'arsonist', 'firefister'}, help = [[-- Firefist -- Syntax: %s [Player] {Boolean} -- Enable/Disable Firefist for a player. ]], }, { arguments = {"Player", "Boolean", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, players, bool) local player for i = 1,#players do playerId = players[i] player = PlayerClass[playerId] if bool then player.firefist = bool sendresponse("Fire fist " .. tostring(bool) .. " for " .. tostring(getname(playerId)), executorPlayerId) registertimer(300, "FireFistTimer") else sendresponse("Fire fist for player " .. tostring(getname(playerId)) .. " is currently " .. tostring(bool), executorPlayerId) end end end } ) -- apply flame to receiving player. function ApplyFlame(receiverPlayerId, firefisterObjId) local playerObjId = getplayerobjectid(receiverPlayerId) local x,y,z = getobjectcoords(playerObjId) local flame = createobject(flameid, firefisterObjId, 5, true, x, y, z+0.65) local xflame = createobject(flameid, firefisterObjId, 5, true, x-0.08, y, z+0.43) local gflamefx = createobject(flameid, firefisterObjId, 5, true, x-0.12, y, z+0.04) local flameobject = getobject(flame) writefloat(flameobject + 0x68, 0) writefloat(flameobject + 0x6C, 0) writefloat(flameobject + 0x70, -0.2) end function getBodyPartLocation(m_object, offset) --m_object = m_object + (offset or 0x0) --unkFloats[10] (???) Probably rotations. bipd_bodypart_x = readfloat(m_object, offset + 0x28) bipd_bodypart_y = readfloat(m_object, offset + 0x2C) bipd_bodypart_z = readfloat(m_object, offset + 0x30) return bipd_bodypart_x,bipd_bodypart_y,bipd_bodypart_z end -- apply flame damage to fist of firefister function FireFistTimer(id, cc) local playerObjId, m_playerObj, hx, hy, hz, fistflame, ffobject local firefisterfound = false for playerId = 0,15 do if not getplayer(playerId) or not PlayerClass[playerId].firefist then goto nextIter end firefisterfound = true playerObjId = getplayerobjectid(playerId) m_playerObj = getobject(playerObjId) if not m_playerObj then goto nextIter end hx,hy,hz = getBodyPartLocation(m_playerObj, 0x8C4) fistflame = createobject(flameid, 0, 5, true, hx, hy, hz+0.08) fistflame2 = createobject(flameid, 0, 5, true, hx, hy, hz+0.1) ffobject = getobject(fistflame) ffobject2 = getobject(fistflame2) writefloat(ffobject + 0x68, 0) writefloat(ffobject + 0x6C, 0) writefloat(ffobject + 0x70, -0.2) writefloat(ffobject2 + 0x68, 0) writefloat(ffobject2 + 0x6C, 0) writefloat(ffobject2 + 0x70, -0.2) ::nextIter:: end if not firefisterfound then return false end return true end Commands.Create( "hashduplicates", { aliases = {'duplicates', 'allowduplicates'}, help = [[-- Allow Hash Duplicates -- Syntax: %s {Boolean} -- Allows/Deny's multiple players with the same hash to join the server -- The default for this command is: Enabled.]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("Hash Duplicate Checking", defaults.hash_duplicates, strBool) if newBool then writebyte(addresses.hash_duplicate_patch, 0x74) defaults.hash_duplicates = true elseif newBool ~= nil then writebyte(addresses.hash_duplicate_patch, 0xEB) defaults.hash_duplicates = false end sendresponse(response, executorPlayerId) end } ) Commands.Create( "infiniteammo", { aliases = {"infammo"}, scrimBlock = true, help = [[-- Infinite Ammo -- Syntax: %s [Boolean] -- Enable or disable infinite ammo"]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("Infinite Ammo", defaults.infinite_ammo, strBool) if newBool then defaults.infinite_ammo = true local player, m_playerObj, playerObjId, m_weaponObj, weaponObjId infammo_timer = registertimer(500, "playerWeaponCheckTimer") for playerId = 0,15 do if not getplayer(playerId) then goto continue end m_playerObj, playerObjId = getplayerobject(playerId) if not m_playerObj then goto continue end player = PlayerClass[playerId] for slot = 0,3 do weaponObjId = player.weapons[slot] m_weaponObj = getobject(weaponObjId) if m_weaponObj then writeshort(m_weaponObj + 0x2B6, 0x7CFF) writeshort(m_weaponObj + 0x2B8, 0x7CFF) updateammo(weaponObjId) player.weapons[slot] = weaponObjId end end ::continue:: end elseif newBool ~= nil then local m_playerObj, m_weaponObj, weaponObjId, mapId, tag_address, tag_data_address, address_magazines, rounds_total_initial, rounds_loaded_maximum for i = 0,15 do m_playerObj = getplayerobject(i) if not m_playerObj then goto continue end for x = 0,3 do m_weaponObj, weaponObjId = getplayerweapon(i, x) if not m_weaponObj then goto continue2 end mapId = readdword(m_weaponObj) tag_address = gettagaddress(mapId) tag_data_address = readdword(tag_address + 0x14) address_magazines = readdword(tag_data_address + 0x4F0 + 0x4) if not address_magazines or address_magazines == 0 then goto continue2 end rounds_total_initial = readshort(address_magazines + 0x8) rounds_loaded_maximum = readshort(address_magazines + 0xA) writeshort(m_weaponObj + 0x2B6, rounds_total_initial or 0) writeshort(m_weaponObj + 0x2B8, rounds_loaded_maximum or 0) updateammo(weaponObjId) ::continue2:: end ::continue:: end if infammo_timer then removetimer(infammo_timer) end defaults.infinite_ammo = false end sendresponse(response, executorPlayerId) end } ) Commands.Create( "killspree", { aliases = {"killingspree"}, help = [[-- Killing Spree Detection -- Syntax: %s [Boolean] -- Enable/Disable Killing Spree Notifications]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("Killing Spree Notifications", defaults.killing_spree, strBool) if newBool ~= nil then defaults.killing_spree = newBool end sendresponse(response, executorPlayerId) end } ) -- TODO: Use gametype scorelimit per-player or per-team instead of hardcoded values Commands.Create( "multiteamvehicles", { aliases = {"mtvehicles", "mtv"}, help = [[-- Multi Team Vehicles -- Syntax: %s {Boolean} -- Allows/Deny's players to enter enemy vehicles. -- Note: This command only works on Free-For-All GameTypes. -- The default for this command is: Disabled.]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("Multi-Team Vehicles", defaults.multiteam_vehicles, strBool) if not team_play then local m_player if newBool then --[[if not team_play_temp then team_play_temp = team_play end team_play = true--]] for playerId = 0,15 do m_player = getplayer(playerId) if m_player then team_scores[playerId] = player_scores[playerId] writebyte(m_player + 0x20, 0) end end writebyte(addresses.gametype_base + 0x58, 255) defaults.multiteam_vehicles = true elseif newBool ~= nil then --team_play = team_play_temp or team_play for playerId = 0,15 do m_player = getplayer(playerId) if m_player then writebyte(m_player + 0x20, readbyte(m_player + 0x66)) end end writebyte(addresses.gametype_base + 0x58, scorelimit) defaults.multiteam_vehicles = false end else sendresponse("Cannot be applied to team games.", executorPlayerId) end sendresponse(response, executorPlayerId) end } ) Commands.Create( "noweapons", { help = [[-- No Weapons -- Syntax: %s {Boolean} -- Enables/Disables the use of weapons in a server.]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("No-Weapons mode", defaults.noweapons, strBool) if newBool then local m_playerObj, m_weaponObj, weaponObjId for playerId = 0,15 do m_playerObj = getplayerobject(playerId) if m_playerObj then for j = 0,3 do m_weaponObj, weaponObjId = getplayerweapon(playerId, j) if m_weaponObj then destroyobject(weaponObjId) end end end end defaults.noweapons = true elseif newBool ~= nil then for playerId = 0,15 do if getplayer(playerId) then resetweapons(playerId) end end defaults.noweapons = false end sendresponse(response, executorPlayerId) end } ) Commands.Create( "pmenabled", { aliases = {"pvtmessage", "privatemessage", "privatemessageenabled"}, help = [[-- Private Messaging -- Syntax: %s {Boolean} -- Enable/Disable Private Messaging -- To use private messaging, type @(playerIndex) (message) in the chat, without the ( )]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("Private Messaging", defaults.pm_enabled, strBool) if newBool ~= nil then defaults.pm_enabled = newBool end sendresponse(response, executorPlayerId) end } ) Commands.Create( "rtvenabled", { help = [[-- RockTheVote -- Syntax: %s {Boolean} -- Enables or disables the use of RockTheVote in the server -- To initiate a rtv, type 'skip' or 'rtv' in the chat.]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("RockTheVote", defaults.rtv_enabled, strBool) if newBool ~= nil then defaults.rtv_enabled = newBool end sendresponse(response, executorPlayerId) end } ) Commands.Create( "serveradminmessage", { aliases = {"samessage"}, help = [[-- Server Admin Message -- Syntax: %s {Boolean} -- Enable/Disable Server Admin join notification.]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("Server Admin Message", defaults.sa_message, strBool) if newBool ~= nil then defaults.sa_message = newBool end sendresponse(response, executorPlayerId) end } ) Commands.Create( "scrimmode", { help = [[-- Scrim mode -- Syntax: %s {Boolean} -- Enables/Disables Scrim Mode -- This mode will disable certain commands, so people can't cheat during scrims.]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("Scrim mode", defaults.scrim_mode, strBool) if newBool then for i = 0,15 do ResetPlayer(i) end --controllers:deleteEntries() --slaving:deleteEntries() defaults.falldamage = true defaults.deathless = false defaults.infinite_ammo = false defaults.scrim_mode = true elseif newBool ~= nil then defaults.scrim_mode = false end sendresponse(response, executorPlayerId) end } ) Commands.Create( "tbagdet", { aliases = {"tbagdetection"}, help = [[-- Tbag Detection -- Syntax: %s [Boolean] -- Enable/Disable Tbag announcement]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("Tbag Detection", defaults.tbag_detection, strBool) if newBool ~= nil then defaults.tbag_detection = newBool end sendresponse(response, executorPlayerId) end } ) Commands.Create( "votekickenabled", { help = [[-- VoteKick -- Syntax: %s [Boolean] -- Enables/Disables the use of VoteKick in a server -- Once enabled, people can type 'votekick [player]' in the chat to start a votekick on that player.]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("VoteKick", defaults.votekick_enabled, strBool) if newBool ~= nil then defaults.votekick_enabled = newBool end sendresponse(response, executorPlayerId) end } ) Commands.Create( "defaultspawnweapons", { aliases = {"spawnweapons", "weaponsonspawn", "chooseweapons", "selectweapons", "poontang"}, help = [[-- Choose Default Spawn Weapons -- Syntax: %s {Primary Weapon or 'Default'} {Secondary Weapon} {Tertiary Weapon} {Quaternary Weapon} -- Will allow you to change the default weapons that you spawn with. -- Not sending arguments will show the current setting of this command. -- Sending a single argument 'Default' to this command will use the default weapon spawning.]] }, { arguments = {"Object", "Object", "Object", "Object", minArgs = 0, maxArgs = 4}, func = function(executorPlayerId, primary_weap_tagname, secondary_weap_tagname, tertiary_weap_tagname, quaternary_weap_tagname) if primary_weap_tagname then spawnWeapons[1] = primary_weap_tagname spawnWeapons[2] = secondary_weap_tagname spawnWeapons[3] = tertiary_weap_tagname spawnWeapons[4] = quaternary_weap_tagname else sendresponse("The current default spawn weapons are displayed below", executorPlayerId) local weap for i = 0,3 do weap = spawnWeapons[i] if weap then sendresponse("Spawn Weapon #" .. i .. ": " .. weap) end end end end } ) Commands.Create( "welcomebackmessage", { aliases = {"wbmessage"}, help = [[-- Welcome Back Message -- Syntax: %s [Boolean] -- Enable/Disable Welcome Back Message]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("Welcome Back Message", defaults.wb_message, strBool) sendresponse(response, executorPlayerId) if newBool ~= nil then defaults.wb_message = newBool end end } ) -- Scripted Game non-boolean Commands Commands.Create( "adminblocker", { help = [[-- Admin Blocker -- Syntax: %s {Type} -- Enables, disables or limits the abiliy of an admin to kick/ban -- Type 0: Admins can kick/ban another admin. -- Type 1: Admins can't kick/ban other admins with higher level. -- Type 2: Admins can't kick/ban other admins with higher or equal level. -- Type 3: Admins can't kick/ban other admins unless they can do all commands.]] }, { arguments = {"AdminBlocker Type", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, abtype) if abtype == 0 then defaults.adminblocker = "Unsafe" sendresponse("Admins now can kick/ban other admins", executorPlayerId) elseif abtype == 1 then defaults.adminblocker = "Lenient" sendresponse("Admins now cannot kick/ban other admins with higher levels.", executorPlayerId) elseif abtype == 2 then defaults.adminblocker = "Moderate" sendresponse("Admins now cannot kick/ban other admins with higher or equal levels.", executorPlayerId) elseif abtype == 3 then defaults.adminblocker = "Strict" sendresponse("Admins now cannot kick/ban other admins unless they can do all commands.", executorPlayerId) elseif defaults.adminblocker == "Unsafe" then sendresponse("Admins currently can kick/ban other admins", executorPlayerId) elseif defaults.adminblocker == "Lenient" then sendresponse("Admins currently cannot kick/ban other admins with higher levels.", executorPlayerId) elseif defaults.adminblocker == "Moderate" then sendresponse("Admins currently cannot kick/ban other admins with higher or equal levels.", executorPlayerId) elseif defaults.adminblocker == "Strict" then sendresponse("Admins currently cannot kick/ban another admins unless they have full access.", executorPlayerId) end end } ) Commands.Create( "antispam", { help = [[-- AntiSpam -- Syntax: %s {all | players | off} -- All = All Players cannot spam in the chat. -- Players = All Players EXCEPT Admins cannot spam in the chat. -- Off = Disables AntiSpam functionality]] }, { arguments = {"String", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, mode) if mode and mode ~= "all" and mode ~= "players" and mode ~= "off" then sendresponse("Invalid mode. Valid modes are 'all', 'players', and 'off'", executorPlayerId) return end if mode then defaults.antispam = mode sendresponse("AntiSpam now set to " .. defaults.antispam, executorPlayerId) else sendresponse("AntiSpam is set to " .. defaults.antispam, executorPlayerId) end end } ) Commands.Create( "balance", { help = [[-- Balance Teams -- Syntax: %s -- Balances the number of players on each team. -- This command can ONLY be executed on Teamplay GameTypes like CTF.]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) if not team_play then sendresponse("This command is disabled since it is not a team based game.", executorPlayerId) return end local redsize = getteamsize(0) local bluesize = getteamsize(1) if math.abs(redsize - bluesize) > 1 then local randPlayerId = SelectRandomPlayer(bluesize > redsize and 1 or 0) if randPlayerId then changeteam(randPlayerId, true) say("Balancing Teams") sendresponse("The teams have been balanced", executorPlayerId) else sendresponse("There was no one found on the other team.") end else sendresponse("Teams are already balanced.", executorPlayerId) end end } ) Commands.Create( "banpenalty", { help = [[-- Ban Penalty -- Syntax: %s {1st Bantime} {2nd Bantime} {3rd Bantime} etc.. -- Determines how much time a player can be banned when the time argument '0' is used in a ban command.]] }, { arguments = {"Time String", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, times) if not times then for i = 1,#ban_penalty do cmdreply[cmdreply()] = "Ban Penalty #" .. i .. ": " .. ban_penalty[i] end sendresponse(cmdreply, executorPlayerId) else local i = 1 local length = #ban_penalty for time in string.gmatch(times, "%d+[cywdhms]") do time = wordtotime(time) ban_penalty[i] = time i = i + 1 end while length >= i do ban_penalty[i] = nil i = i + 1 end sendresponse("The Ban Penalties have been changed to: " .. times, executorPlayerId) end end } ) Commands.Create( "ban", { aliases = {"b", "hashban", "playerban", "banplayer"}, usesBanCounts = true, help = [[-- Ban -- Syntax: %s [Player, Hash, or IP Address] {Time} {Reason} -- Bans the Player/Hash/IP Address from the server with a reason written to the BanReasons log file]] }, { arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3}, func = function(executorPlayerId, players, time, reason) local exname = executorPlayerId and getname(executorPlayerId) or "the Server" local playerId, name, hash for i = 1,#players do playerId = players[i] name = getname(playerId) if not checkAdminBlockerAccess(executorPlayerId, playerId) then sendresponse("You cannot use this command on " .. name, executorPlayerId) privatesay(playerId, exname .. " attempted to Ban you!") goto continue end hash = gethash(playerId) if hash == sharedhashes[hash] then cmdreply[cmdreply()] = name .. " has a shared hash, and therefore cannot be hashbanned. Try an IP Ban instead." goto continue end tempBanPlayer(resolveplayer(playerId)) if time ~= 1 then addBan(name, hash, nil, time, "hash", reason) WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was banned by " .. exname .. " Reason: " .. reason .. " Type: Hash Ban") say(name .. " has been banned by " .. exname .. " Reason: " .. reason) cmdreply[cmdreply()] = name .. " has been banned from the server" end ::continue:: end sendresponse(cmdreply, executorPlayerId) end }, { arguments = {"Hash", "Time And Reason", minArgs = 1, maxArgs = 3}, func = function(executorPlayerId, hash, time, reason) local exname = executorPlayerId and getname(executorPlayerId) or "the Server" for i = 1,#sharedhashes do if hash == sharedhashes[i] then sendresponse("That is a shared hash, and therefore cannot be hashbanned. Try an IP Ban instead.", executorPlayerId) return end end -- Check if a person in this server has this hash. for playerId = 0,15 do if getplayer(playerId) and gethash(playerId) == hash then tempBanPlayer(resolveplayer(playerId)) end end addBan("manual_ban" .. #ban_table, hash, nil, time, "hash", reason) WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", "Hash '" .. hash .. "' was banned by " .. exname .. " Reason: " .. reason .. " Type: Hash Ban") sendresponse("That hash has been banned from the server successfully", executorPlayerId) end }, { arguments = {"IP Address", "Time And Reason", minArgs = 1, maxArgs = 3}, func = function(executorPlayerId, ip_address, time, reason) local exname = executorPlayerId and getname(executorPlayerId) or "the Server" -- Check if a person in this server has this IP Address. for playerId = 0,15 do if getplayer(playerId) and netMatch(ip_address, getip(playerId)) then tempBanPlayer(resolveplayer(playerId)) end end addBan("manual_ban" .. #ban_table, nil, ip_address, time, "ip", reason) WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", "IP Address '" .. ip_address .. "' was banned by " .. exname .. " Reason: " .. reason .. " Type: IP Ban") sendresponse("That IP Address has been banned from the server successfully", executorPlayerId) end } ) Commands.Create( "bos", { help = [[Ban on Sight -- Syntax: %s [Bosplayer Index] {Bantype 'Hash' or 'IP'} -- Add the specified player to the Ban On Sight (BOS) list. -- The next time this person joins the server, they will be banned. -- This command explicitly requires a number for an index. -- This index must be the player index of a player who has left the server. -- Use 'sv_bosplayers' to get a list of players to add to the BOS list.]] }, { arguments = {"Positive Number", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, playerId) local leave_entry = leave_table[playerId] if not leave_entry then sendresponse("Invalid BoS ID! Use sv_bosplayers to get a list of bosable players.", executorPlayerId) return end local bos_entry for i = 1,#bos_table do bos_entry = bos_table[i] if bos_entry.hash == leave_entry.hash or netMatch(bos_entry.ip, leave_entry.ip) then sendresponse(leave_entry.name .. " is already on the BoS", executorPlayerId) return end end cmdreply[cmdreply()] = "Adding " .. leave_entry.name .. " to BoS." cmdreply[cmdreply()] = "Entry: " .. leave_entry.name .. " - " .. leave_entry.hash .. " - " .. leave_entry.ip sendresponse(cmdreply, executorPlayerId) bos_table[#bos_table+1] = leave_entry -- check if they are already in the server for playerId = 0,15 do if getplayer(playerId) then if not sharedhashes[leave_entry.hash] and leave_entry.hash == gethash(playerId) or netMatch(leave_entry.ip, getip(playerId)) then tempBanPlayer(playerId) privateSayAdmins(bos_entry.name .. " banned from BoS.\nEntry: " .. bos_entry.name .. "- " .. bos_entry.hash) hprintf(bos_entry.name .. " banned from BoS.\nEntry: " .. bos_entry.name .. "- " .. bos_entry.ip) WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", bos_entry.name .. " was Banned on Sight") addBan(bos_entry.name, nil, ip, -1, "ip", "Ban on Sight") end end end end } ) Commands.Create( "kickbansfile", { help = [[-- Kicks and Bans Log File Name -- Syntax: %s {Filename} -- Allows the executor to view and change the name of the 'BanReasons.log' file.]], }, { arguments = {"String", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, filename) if not filename then sendresponse("The current KickBans file name is " .. defaults.kickbans_file .. ".log", executorPlayerId) elseif match(filename, "%w+") then defaults.kickbans_file = filename sendresponse("The KickBans file has been changed to " .. defaults.kickbans_file .. ".log", executorPlayerId) else sendresponse("File names must contain alphanumerical characters only!", executorPlayerId) end end } ) Commands.Create( "commandsfile", { help = [[-- Commands Log File Name -- Syntax: %s {Filename} -- Allows the executor to view and change the name of the 'commands.log' file.]], }, { arguments = {"String", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, filename) if not filename then sendresponse("The current KickBans file name is " .. defaults.commands_file .. ".log", executorPlayerId) elseif match(filename, "%w+") then defaults.commands_file = filename sendresponse("The KickBans file has been changed to " .. defaults.commands_file .. ".log", executorPlayerId) else sendresponse("File names must contain alphanumerical characters only!", executorPlayerId) end end } ) Commands.Create( "adminfile", { help = [[-- Admins Text File Name -- Syntax: %s {Filename} -- Allows the executor to view and change the name of the 'admins.txt' file.]], }, { arguments = {"String", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, filename) if not filename then sendresponse("The current Admins file name is " .. defaults.admin_file .. ".txt", executorPlayerId) elseif match(filename, "%w+") then defaults.admin_file = filename sendresponse("The Admins file has been changed to " .. defaults.admin_file .. ".txt", executorPlayerId) else sendresponse("File names must contain alphanumerical characters only!", executorPlayerId) end end } ) Commands.Create( "sharedhashfile", { help = [[-- Shared Hashes Text File Name -- Syntax: %s {Filename} -- Allows the executor to view and change the name of the 'sharedhashes.txt' file. -- The Shared Hashes file contain hashes that cannot be banned, because they are used by lots of different players.]], }, { arguments = {"String", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, filename) if not filename then sendresponse("The current Shared Hashes file name is " .. defaults.sharedhash_file .. ".txt", executorPlayerId) elseif match(filename, "%w+") then defaults.sharedhash_file = filename sendresponse("The Shared Hashes file has been changed to " .. defaults.sharedhash_file .. ".txt", executorPlayerId) else sendresponse("File names must contain alphanumerical characters only!", executorPlayerId) end end } ) Commands.Create( "banlistfile", { help = [[-- Kicks and Bans Log File Name -- Syntax: %s {Filename} -- Allows the executor to view and change the name of the 'banned.txt' file.]], }, { arguments = {"String", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, filename) if not filename then sendresponse("The current Banlist File Name is " .. defaults.banlist_file .. ".txt", executorPlayerId) elseif match(filename, "%w+") then defaults.banlist_file = filename sendresponse("The Banlist file has been changed to " .. defaults.banlist_file .. ".txt", executorPlayerId) else sendresponse("File names must contain alphanumerical characters only!", executorPlayerId) end end } ) Commands.Create( "hashbanlist", { help = [[-- Hash Ban List -- Syntax: %s -- Displays all players currently hash banned from the server.]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) Commands.banlist[1].func(executorPlayerId, "hash") end } ) Commands.Create( "ipbanlist", { help = [[-- IP Ban List -- Syntax: %s -- Displays all players currently IP banned from the server.]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) Commands.banlist[1].func(executorPlayerId, "ip") end } ) Commands.Create( "namebanlist", { help = [[-- Name Ban List -- Syntax: %s -- Displays all players currently name banned from the server.]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) Commands.banlist[1].func(executorPlayerId, "name") end } ) Commands.Create( "textbanlist", { help = [[-- Text Ban List -- Syntax: %s -- Displays all players currently chat banned from the server.]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) Commands.banlist[1].func(executorPlayerId, "text") end } ) local function getBanlist(banlists, bantype) if banlists ~= "local" then --reloadRemoteBanlist() end local output = {}--TM.New() local cur_time = os.time() local ban_entry, time for id = 1,#ban_table do ban_entry = ban_table[id] if banlists == "both" or ban_entry.remote and banlists == "remote" or not ban_entry.remote and banlists == "local" then time = ban_entry.time if bantype == "all" or (time == -1 or ((time - cur_time) > 0)) and (not bantype or bantype == ban_entry.type) then output[#output+1] = format("[%u | %s | %s | %s | %s | %s]", id, ban_entry.name, ban_entry.count or "N/A", ban_entry.type, time ~= -1 and formatTime(timeleft) or "Never", ban_entry.reason or "None") end end end return output end Commands.Create( "banlist", { aliases = {"listbans", "bans", "showbans", "viewbans"}, help = [[-- Ban List -- Syntax: %s {ip | hash | chat | name | all} -- Displays all players banned from the server. -- Specifying a second argument will filter the list by the specified bantype. -- Specifying "all" will show everyone who has ever been banned on this server.]] }, { arguments = {"String", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, bantype) bantype = bantype and lower(bantype) if bantype and bantype ~= "name" and bantype ~= "chat" and bantype ~= "hash" and bantype ~= "ip" and bantype ~= "all" then sendresponse("Invalid Bantype. Valid bantypes are IP, Hash, Name, Chat, and All", executorPlayerId) return end cmdreply.header = "[ID | Name | Bans | Type | Expires | Reason]" cmdreply.delim = "|" cmdreply.align = true local args = defaults.remote_bansystem local output = getBanlist(not args and "local" or args.mode == 1 and "remote" or "both", bantype) for i = 1,#output do cmdreply[cmdreply()] = output[i] end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "unban", { aliases = {"ipunban", "hashunban", "textunban", "nameunban"}, help = [[-- Unban -- Syntax: %s [ID] -- Unbans the specified ban entry and allows the person to rejoin the server. -- Note: This command will NOT remove people COMPLETELY off the banlist, but will allow the banned player to rejoin. -- Use removeban to completely remove someone off the banlist.]] }, { arguments = {"Positive Number", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, ID) local entry = ban_table[ID] local cur_time = os.time() local args = defaults.remote_bansystem if not entry or (args and args.mode == 2 and not entry.remote) or (entry.time ~= -1 and entry.time <= cur_time) then sendresponse("Invalid ID", executorPlayerId) return end local index = (entry.ip or "") .. ":" .. (entry.hash or "") .. ":" .. entry.name if entry.type == "chat" then -- unmute them if they are currently in the game. for playerId = 0,15 do if getplayer(playerId) and netMatch(entry.ip, getip(playerId)) then PlayerClass[playerId].muted = false end end end local bantype = entry.type entry.time = cur_time -- set the ban expire time to the present. local name = executorPlayerId and PlayerClass[executorPlayerId].admin_entry and PlayerClass[executorPlayerId].admin_entry.name or getname(executorPlayerId) if entry.reason then if find(entry.reason, "| Unbanned by '") then entry.reason = gsub(entry.reason, " | Unbanned by '[^\']'", " | Unbanned by '" .. name .. "'") else entry.reason = entry.reason .. " | Unbanned by '" .. name .. "'" end else entry.reason = "None Given | Unbanned by '" .. name .. "'" end if args and args.mode >= 2 then http.request(args.http_source, "&bans=" .. toBanTextEntry(entry) .. "&unban=true") end updateBanFiles(bantype) -- update banlist file. sendresponse(bantype .. " ban '" .. index .. "' has been unbanned from the banlist!", executorPlayerId) end } ) Commands.Create( "removeban", { aliases = {"banremove", "deleteban", "bandelete", "wipeban", "banwipe"}, help = [[-- Remove Ban -- Syntax: %s [ID] -- Similar to unban but will completely remove the ban entry from the banlist -- Note: this will NOT remove bans on a central remote banlist, but instead will unban them!]] }, { arguments = {"Positive Number", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, ID) local entry = ban_table[ID] local cur_time = os.time() local args = defaults.remote_bansystem if not entry or (args and args.mode == 2 and not entry.remote) or (entry.time ~= -1 and entry.time <= cur_time) then sendresponse("Invalid ID", executorPlayerId) return end local index = (entry.ip or "") .. ":" .. (entry.hash or "") .. ":" .. entry.name if entry.type == "chat" then -- unmute them if they are currently in the game. for playerId = 0,15 do if getplayer(playerId) and netMatch(entry.ip, getip(playerId)) then PlayerClass[playerId].muted = false end end end -- remove the ban entry from the banlist completely remove(ban_table, ID) if args and args.mode >= 2 then http.request(args.http_source, "&bans=" .. toBanTextEntry(entry) .. "&unban=true") end updateBanFiles(bantype) -- update banlist file. sendresponse(bantype .. " ban '" .. index .. "' has been unbanned from the banlist!", executorPlayerId) end } ) Commands.Create( "boslist", { help = [[-- Ban on Sight List -- Syntax: %s -- Displays the Ban On Sight list -- These people will be automatically added to the banlist when they join the server. -- Use unbos to remove from this list.]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) if not bos_table[1] then sendresponse("The Ban on Sight list is empty!", executorPlayerId) return end cmdreply.header = "[ID | Name | Hash | IP]" cmdreply.delim = "|" cmdreply.align = true local bos_entry for id = 1,#bos_table do bos_entry = bos_table[id] cmdreply[cmdreply()] = format("[%u | %s | %s | %s]", id, bos_entry.name, bos_entry.hash, bos_entry.ip) end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "bosplayers", { aliases = {"bosableplayers"}, help = [[-- Bosable Players List -- Syntax: %s -- Shows the available players that can be banned on sight. -- This list is constructed from people who leave the server.]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) if not next(leave_table) then sendresponse("There are no players that can be added as a BOS right now", executorPlayerId) return end cmdreply.header = "[ID | Name]" cmdreply.delim = "|" cmdreply.align = true local leave_entry for i = 1,16 do leave_entry = leave_table[i] if leave_entry then cmdreply[cmdreply()] = "[" .. i .. " | " .. leave_entry.name .. " | " .. leave_entry.ip .. "]" end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "changelevel", { aliases = {"adminlevel", "levelchange", "changelevel", "level", "modifylevel", "changeadminlevel", "modifyadminlevel", "setadminlevel"}, help = [[-- Change Level Command -- Syntax: %s [Nickname] {Level} -- Change the specified admins' level]] }, { arguments = {"String", "Access Level", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, nickname, level) 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 if level then thisAdmin.level = level sendresponse(nickname .. " is now a level " .. level .. (thisAdmin.type == "ip" and " IP Admin" or " Hash Admin"), executorPlayerId) updateAdminFiles() else sendresponse(nickname .. " is currently a level " .. thisAdmin.level .. (thisAdmin.type == "ip" and " IP Admin" or " Hash Admin"), executorPlayerId) end return end end sendresponse("Invalid Nickname", executorPlayerId) end } ) Commands.Create( "changeteam", { aliases = {"ts", "teamchange", "swapteam", "teamswap"}, help = [[-- Change team Command -- Syntax: %s [Player] -- Change the specified players team]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) if team_play then local playerId for i = 1,#players do playerId = players[i] changeteam(playerId, true) sendresponse(getname(playerId) .. " has been forced to change teams", executorPlayerId) end else sendresponse("Can only be applied to team games.", executorPlayerId) end end } ) Commands.Create( "disconnect", { aliases = {"losenetworkconnection", "loseconnection", "dc"}, help = [[-- Disconnect Player -- Syntax: %s [Player] -- Will forcibly cause the player to lose connection to the server, -- This will not affect the server]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local machine_base = readdword(addresses.network_pointer) -- Confirmed. local machine_table = machine_base + 0xAA0 -- Confirmed. Player machine table local playerId, m_player, player_machine_index, machine_struct, machine_network for i = 1,#players do playerId = players[i] m_player = getplayer(playerId) player_machine_index = readbyte(m_player + 0x64) machine_struct = readdword(machine_table + player_machine_index*4) machine_network = readdword(readdword(machine_struct)) writebyte(machine_network, 0) halo_svcmd("sv_kick " .. resolveplayer(playerId)) -- just because it takes ages for the server to figure out they quit cmdreply[cmdreply()] = getname(playerId) .. " has lost connection successfully." end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "count", { aliases = {"uniques", "uniqueplayers"}, help = [[-- Count -- Syntax: %s -- It will display the number of unique users.]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) if not defaults.uniques_enabled then sendresponse("'sv_uniques_enabled' is currently disabled.", executorPlayerId) return end sendresponse("There are " .. unique_table.total .. " unique users that have been to this server", executorPlayerId) end } ) Commands.Create( "commands", { aliases = {"cmds", "commandlist", "list", "listcommands", "showcommands", "allcommands", "getcommands", "viewcommands"}, help = [[-- Commands --Syntax %s -- Lists the commands you are allowed to executed]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) if not executorPlayerId then sendresponse("All Commands: " .. concat(Commands, ", "), executorPlayerId) return end local admin_entry = PlayerClass[executorPlayerId].admin_entry if admin_entry and admin_entry ~= true then sendresponse(concat(access_table[admin_entry.level or 0], " | "), executorPlayerId) end end } ) Commands.Create( "crash", { scrimBlock = true, help = [[-- Crash Player's Game -- Syntax: %s [Player] -- This command will crash the players game, -- This will not affect the server -- Use this command sparingly. It has been known to crash servers (ironic right?) on abuse]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) if gameend then sendresponse("You cannot crash a player while the game is ended. Wait until next game.", executorPlayerId) return end local exname = getname(executorPlayerId) local playerId, objectId, name for i = 1,#players do playerId = players[i] name = getname(playerId) if not checkAdminBlockerAccess(executorPlayerId, playerId) then sendresponse("You cannot use this command on " .. name, executorPlayerId) privatesay(playerId, exname .. " attempted to Crash you!") goto continue end local mapId = gettag("vehi", "vehicles\\warthog\\mp_warthog") if mapId then objectId = createobject(mapId, 0, 1, false, 0, 1, 2) if not objectId then break end end entervehicle(playerId, objectId, 5) destroyobject(objectId) cmdreply[cmdreply()] = name .. " had their game crashed by an admin" ::continue:: end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "damage", { aliases = {"dmg", "setdmg", "setdmgmulti", "setdamage"}, scrimBlock = true, help = [[-- Damage Multiplier -- Syntax: %s [Player] [Damage Multiplier] -- Increases the amount of damage the player does.]] }, { arguments = {"Player", "Number", minArgs = 2, maxArgs = 2}, func = function(executorPlayerId, players, value) local playerId for i = 1,#players do playerId = players[i] if value then PlayerClass[playerId].dmgmultiplier = value cmdreply[cmdreply()] = getname(playerId) .. " now has a damage multiplier of " .. value else cmdreply[cmdreply()] = getname(playerId) .. " has a damage multiplier of " .. PlayerClass[playerId].dmgmultiplier end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "delrcon", { aliases = {"rcondel"}, help = [[-- Delete Rcon Password -- Syntax: %s {Password} -- Deletes the rcon password.]] }, { arguments = {"String", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, password) if not rcon_passwords[password] then sendresponse(password .. " is not a rcon password", executorPlayerId) return end rcon_passwords[password] = nil sendresponse(password .. " is no longer a rcon password", executorPlayerId) end } ) Commands.Create( "eject", { aliases = {"playereject", "ejectplayer"}, scrimBlock = true, help = [[-- Eject -- Syntax: %s [Player] -- Force the specified players to exit their vehicle]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, m_playerObj for i = 1,#players do playerId = players[i] m_playerObj = getplayerobject(playerId) if m_playerObj and isinvehicle(playerId) then exitvehicle(playerId) cmdreply[cmdreply()] = "Ejecting " .. getname(playerId) .. " from their vehicle" else cmdreply[cmdreply()] = getname(playerId) .. " is not in a vehicle" end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "gethash", { aliases = {"hash", "gethash"}, help = [[-- Get Player Hash -- Syntax: %s [Player] -- Gets the specified player's hash]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId for i = 1,#players do playerId = players[i] cmdreply[cmdreply()] = getname(playerId) .. ": " .. gethash(playerId) end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "getip", { help = [[-- Get IP -- Syntax: %s [Player] -- Get the specified playersIP address]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId for i = 1,#players do playerId = players[i] cmdreply[cmdreply()] = getname(playerId) .. ": " .. getip(playerId) end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "getloc", { aliases = {"getplayerlocation", "getplayerloc", "getplayercoords", "getcoords", "coords", "playerloc", "playercoords"}, help = [[-- Get Location -- Syntax: %s [Player] -- Get the specified players' world coordinates in the server]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId for i = 1,#players do playerId = players[i] local m_playerObj, playerObjId = getplayerobject(playerId) if m_playerObj then local x,y,z = getobjectcoords(playerObjId, m_playerObj) x,y,z = round(x, 2),round(y, 2),round(z, 2) cmdreply[cmdreply()] = getname(playerId) .. "'s coords are: X: " .. x .. " Y: " .. y .. " Z: " .. z else cmdreply[cmdreply()] = getname(playerId) .. " is dead" end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "setgod", { aliases = {"g", "god", "godmode", "godset", "cheatgod", "cheatsetgod", "cheatgodmode", "cheatinvincible", "invincible"}, scrimBlock = true, help = [[-- Set God -- Syntax: %s [Player] -- Gives you lots of health]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) if defaults.deathless then sendresponse("Deathless is enabled. You cannot give out godmode", executorPlayerId) return end local playerId, player, m_playerObj for i = 1,#players do playerId = players[i] m_playerObj = getplayerobject(playerId) if m_playerObj then player = PlayerClass[playerId] if not player.godmode then cmdreply[cmdreply()] = getname(playerId) .. " has been given godmode" player.godmode = true else cmdreply[cmdreply()] = getname(playerId) .. " is already in godmode" end else cmdreply[cmdreply()] = getname(playerId) .. " is dead" end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "cheathax", { aliases = {"hax", "haxolu", "haxor", "1337"}, scrimBlock = true, help = [[-- Cheat Hax -- Syntax: %s [Player] -- I will never tell]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, m_player for i = 1,#players do playerId = players[i] m_player = getplayer(playerId) setscore(playerId, 9999) writeshort(m_player + 0x9C, 9999) writeshort(m_player + 0xA4, 9999) writeshort(m_player + 0xAC, 9999) writeshort(m_player + 0xAE, 9999) writeshort(m_player + 0xB0, 9999) cmdreply[cmdreply()] = getname(playerId) .. " has been haxed" end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "heal", { aliases = {"healplayer", "playerheal", "cheatheal", "restorehealth", "cheatrestorehealth", "cheatheal"}, scrimBlock = true, help = [[-- Heal -- Syntax: %s [Player] -- Heal the specified players]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, m_playerObj, playerObjId, mapId, obj_health, m_vehicleObj, x, y, z, healthpack for i = 1,#players do playerId = players[i] m_playerObj, playerObjId = getplayerobject(playerId) if m_playerObj then obj_health = readfloat(m_playerObj + 0xE0) if obj_health < 1 then m_vehicleObj = getplayervehicle(playerId) if not m_vehicleObj then x,y,z = getobjectcoords(playerObjId) mapId = gettag("eqip", "powerups\\health pack") if mapId then healthpack = getobject(createobject(mapId, 0, 0, false, x, y, z+0.5)) else cmdreply[cmdreply()] = "Health Pack could not be spawned!" end if healthpack then writefloat(healthpack + 0x70, -2) end else writefloat(m_playerObj + 0xE0, 1) end cmdreply[cmdreply()] = getname(playerId) .. " has been healed" else cmdreply[cmdreply()] = getname(playerId) .. " is already at full health" end else cmdreply[cmdreply()] = getname(playerId) .. " is dead" end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "hide", { aliases = {"hideplayer", "playerhide", "cheathide"}, scrimBlock = true, help = [[-- Hide -- Syntax: %s [Player] -- You are invisible. Not Camo.]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, player for i = 1,#players do playerId = players[i] player = PlayerClass[playerId] if not player.hidden then cmdreply[cmdreply()] = getname(playerId) .. " is now hidden" player.hidden = true else cmdreply[cmdreply()] = getname(playerId) .. " is already hidden" end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "info", { aliases = {"i", "playerinfo", "infoplayer", "getplayerinfo", "getinfo"}, help = [[-- Info Syntax: %s [Player] -- Returns a lot of info of the specified player]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local gametype_maximum_health = readfloat(addresses.gametype_base + 0x54) local playerId local invis_info,crouch,health_info,objective_mode,flashlight_mode,flashlight_level local x,y,z local primary_weap_heat, primary_weap_age, primary_weap_ammo, primary_weap_clip, primary_weap_info local secondary_weap_heat, secondary_weap_age, secondary_weap_ammo, secondary_weap_clip, secondary_weap_info for i = 1,#players do playerId = players[i] local m_player = getplayer(playerId) local ip = getip(playerId) local player = PlayerClass[playerId] local team = getteam(playerId) local teamsize = getteamsize(team) team = team_play and (team == 0 and "Red" or team == 1 or "Blue" or "Hidden") or "FFA " .. team local respawntime = round(readdword(m_player + 0x2C) * 0.033, 2) local invis_time = round(readword(m_player + 0x68) * 0.033, 2) local speed = readfloat(m_player + 0x6C) local objective_mode = readbyte(m_player + 0x74) local objective_mode2 = readbyte(m_player + 0x7A) local killstreak = readword(m_player + 0x96) local kills = readshort(m_player + 0x9C) local assists = readshort(m_player + 0xA4) local suicides = readshort(m_player + 0xB0) local betrays = readshort(m_player + 0xAC) + suicides local deaths = readshort(m_player + 0xAE) local ping = readword(m_player + 0xDC) local m_playerObj, playerObjId = getplayerobject(playerId) local primary_weap_info = "Primary: Empty" local secondary_weap_info = "Secondary: Empty" local weap_slot, nade_info if m_playerObj then local m_vehicleObj = getplayervehicle(playerId) x,y,z = getobjectcoords(playerObjId) x,y,z = round(x, 2),round(y, 2),round(z, 2) local health = round(readfloat(m_playerObj + 0xE0) * 100) local shields = round(readfloat(m_playerObj + 0xE4) * 100) local max_health = round(health * readfloat(m_playerObj + 0xD8) / 100) local max_shields = round(shields * readfloat(m_playerObj + 0xDC) / 100) flashlight_mode = readbit(m_playerObj + 0x204, 19) and "On" or "Off" crouch = readbyte(m_playerObj + 0x2A0) weap_slot = readbyte(m_playerObj + 0x2F2) local nade_type = readbyte(m_playerObj + 0x31C) local primary_nades = readbyte(m_playerObj + 0x31E) local secondary_nades = readbyte(m_playerObj + 0x31F) flashlight_level = round(readfloat(m_playerObj + 0x344) * 100) local invis_scale = round(readfloat(m_playerObj + 0x37C) * 100, 2) invis_scale = invis_scale == 0 and "No" or invis_scale .. "%" invis_info = invis_scale ~= "No" and "Invis: " .. invis_scale .. " (" .. invis_time .. " secs)" or "Invis: " .. invis_scale local m_primaryWeapObj, m_secondaryWeapObj if m_vehicleObj then m_primaryWeapObj = getobject(readdword(m_vehicleObj + 0x2F8)) elseif weap_slot == 1 then m_primaryWeapObj = getobject(readdword(m_playerObj + 0x2FC)) m_secondaryWeapObj = getobject(readdword(m_playerObj + 0x2F8)) else m_primaryWeapObj = getobject(readdword(m_playerObj + 0x2F8)) m_secondaryWeapObj = getobject(readdword(m_playerObj + 0x2FC)) end if m_primaryWeapObj then local primary_weap_heat = round(readfloat(m_primaryWeapObj + 0x23C) * 100) local primary_weap_age = round((1 - readfloat(m_primaryWeapObj + 0x240)) * 100) local primary_weap_ammo = readword(m_primaryWeapObj + 0x2B6) local primary_weap_clip = readword(m_primaryWeapObj + 0x2B8) primary_weap_info = primary_weap_age ~= 100 and "Primary Battery: " .. primary_weap_heat .. "% / " .. primary_weap_age .. "%" or primary_weap_ammo == 0 and primary_weap_clip == 0 and "Primary: Infinite" or "Primary Ammo: " .. primary_weap_clip .. " / " .. primary_weap_ammo end if m_secondaryWeapObj then local secondary_weap_heat = round(readfloat(m_secondaryWeapObj + 0x23C) * 100) local secondary_weap_age = round((1 - readfloat(m_secondaryWeapObj + 0x240)) * 100) local secondary_weap_ammo = readword(m_secondaryWeapObj + 0x2B6) local secondary_weap_clip = readword(m_secondaryWeapObj + 0x2B8) secondary_weap_info = secondary_weap_age ~= 100 and "Secondary Battery: " .. secondary_weap_heat .. "% / " .. secondary_weap_age .. "%" or secondary_weap_ammo == 0 and secondary_weap_clip == 0 and "Secondary: Infinite" or "Secondary Ammo: " .. secondary_weap_clip .. " / " .. secondary_weap_ammo end if crouch == 0 then crouch = "Warthog: Driver" elseif crouch == 1 then crouch = "Warthog: Gunner" elseif crouch == 2 then crouch = "Warthog: Passenger" elseif crouch == 3 then crouch = "Stance: Crouching" elseif crouch == 4 then crouch = "Stance: Standing" elseif crouch == 5 then crouch = "Ghost: Driver" elseif crouch == 6 then crouch = "Banshee: Pilot" elseif crouch == 13 then crouch = "Scorpion: Driver" elseif crouch == 17 then crouch = "Shade: Gunner" elseif crouch == 20 or crouch == 21 or crouch == 22 or crouch == 23 then crouch = "Scorpion: Passenger" end nade_info = "Frag Grenades: " .. primary_nades .. " | " .. "Plasma Grenades: " .. secondary_nades nade_info = nade_type == 1 and "Plasma Grenades: " .. secondary_nades .. " | " .. "Frag Grenades: " .. primary_nades or nade_info if crouch == "Stance: Crouching" or crouch == "Stance: Standing" then if readbyte(m_playerObj + 0x4CC) == 1 then crouch = "Stance: Airborne" end end if player.suspended then health_info = "Respawn: Player is Suspended" else health_info = format("Health: %s%% (%s) | Shields: %s%% (%s)", health, max_health, shields, max_shields) end else crouch = "Stance: Dead" health_info = respawntime == 1 and "Respawn: " .. respawntime .. " sec" or "Respawn: " .. respawntime .. " secs" end if objective_mode == 0x22 and objective_mode2 == 0x71 then objective_mode = "Hill" elseif objective_mode == 0x23 and objective_mode2 == 0x71 then objective_mode = "Juggernaut" elseif objective_mode == 0x23 and objective_mode2 == 0x72 then objective_mode = "It" elseif objective_mode == 0x29 and objective_mode2 == 0x70 then objective_mode = "Ball" elseif weap_slot == 2 then objective_mode = "Flag" else objective_mode = "None" end cmdreply.delim = "|" cmdreply[cmdreply()] = "----------" cmdreply[cmdreply()] = format("Name: %s ( %u ) | Team: %s (%s) | Speed: %s | Location: (%s, %s, %s)", getname(playerId), resolveplayer(playerId), team, teamsize, round(speed, 2), x, y, z) cmdreply[cmdreply()] = format("Hash: %s | IP: %s", gethash(playerId), ip) cmdreply[cmdreply()] = format("Admin: %s | Ping: %s | %s", player.admin_entry and "YES" or "NO", ping, crouch) cmdreply[cmdreply()] = format("Kills: %s (%s) | Assists: %s | Betrays %s | Suicides %s | Deaths %s", kills, killstreak, assists, betrays, suicides, deaths) cmdreply[cmdreply()] = format("%s | %s | Light: %s (%s%%)", health_info, invis_info, flashlight_mode, flashlight_level) cmdreply[cmdreply()] = format("%s | %s | Objective: %s", primary_weap_info, secondary_weap_info, objective_mode) cmdreply[cmdreply()] = nade_info cmdreply[cmdreply()] = format("Hidden: %s | God: %s | AFK: %s", player.hidden, player.godmode, player.afk) cmdreply[cmdreply()] = "----------" end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "ipban", { aliases = {"banip", "ipbanplayer"}, help = [[-- IP Ban -- Syntax: %s [Player or IP] {Time} {Reason} -- Will ban a player/ip from the server.]], usesBanCounts = true, }, { arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3}, func = function(executorPlayerId, players, time, reason) local exname = getname(executorPlayerId) local playerId, name for i = 1,#players do playerId = players[i] name = getname(playerId) if not checkAdminBlockerAccess(executorPlayerId, playerId) then sendresponse("You cannot use this command on " .. name, executorPlayerId) privatesay(playerId, exname .. " attempted to IPBan you!") goto continue end tempBanPlayer(resolveplayer(playerId)) addBan(name, nil, getip(playerId) .. "/24", time, "ip", reason) WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was banned by " .. exname .. " Reason: " .. reason .. " Type: IP Ban") say(name .. " was IP banned! Reason: " .. reason) cmdreply[cmdreply()] = name .. " has been IP banned" sendresponse(cmdreply, executorPlayerId) ::continue:: end end }, { arguments = {"IP Address", "Time And Reason", minArgs = 1, maxArgs = 3}, func = function(executorPlayerId, ip_address, time, reason) local exname = getname(executorPlayerId) addBan("manual_ban", nil, ip_address, time, "ip", reason) WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", "The IP: " .. ip_address .. " was banned by " .. exname .. " Reason: " .. reason .. " Type: IP Ban") sendresponse(ip_address .. " has been IP banned successfully.", executorPlayerId) end } ) Commands.Create( "invis", { aliases = {"camo", "camouflage", "setcamo", "cheatsetcamo", "cheatcamo", "cheatgivecamo", "givecamo"}, help = [[-- Invis -- Syntax: %s [Player] {Time} -- Will camo the specified player.]] }, { arguments = {"Player", "Time", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, players, time) local playerId, m_playerObj, playerObjId, player for i = 1,#players do playerId = players[i] m_playerObj, playerObjId = getplayerobject(playerId) if not m_playerObj then cmdreply[cmdreply()] = getname(playerId) .. " is dead" goto continue end player = PlayerClass[playerId] if player.invisible then cmdreply[cmdreply()] = getname(playerId) .. " is already invisible" goto continue end player.invisible = time cmdreply[cmdreply()] = getname(playerId) .. " is now invisible" ::continue:: end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "kick", { aliases = {"k", "kickplayer", "playerkick"}, help = [[-- Kick -- Syntax: %s [Player] {Reason} -- Kicks the player out of the server with a reason written to the KicksAndBans.log]] }, { arguments = {"Player", "Remaining Arguments", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, players, reason) reason = reason or "None Given" local exname = getname(executorPlayerId) local playerId, name for i = 1,#players do playerId = players[i] name = getname(playerId) if not checkAdminBlockerAccess(executorPlayerId, playerId) then sendresponse("You cannot use this command on " .. name, executorPlayerId) privatesay(playerId, exname .. " attempted to Kick you!") goto continue end WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was kicked by " .. exname .. " Reason: " .. reason) say(name .. " has been kicked! Reason: " .. reason) sendresponse(name .. " has been kicked from the server", executorPlayerId) halo_svcmd("sv_kick " .. resolveplayer(playerId)) ::continue:: end end } ) Commands.Create( "kill", { aliases = {"killplayer", "playerkill", "cheatkill", "cheatkillplayer"}, scrimBlock = true, help = [[-- Kill Player -- Syntax: %s [Player] -- Kills the specified player, and forces them to respawn.]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId for i = 1,#players do playerId = players[i] if not getplayerobject(playerId) then sendresponse(getname(playerId) .. " is already dead!", executorPlayerId) goto continue end kill(playerId) sendresponse(getname(playerId) .. " has been killed", executorPlayerId) ::continue:: end end } ) Commands.Create( "launch", { help = [[-- Launch -- Syntax: %s [Player] -- Launches the person in a random direction.]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, m_vehicleObj, vehicleObjId for i = 1,#players do playerId = players[i] m_vehicleObj, vehicleObjId = getplayervehicle(playerId) if not m_vehicleObj then cmdreply[cmdreply()] = getname(playerId) .. " is dead/not in a vehicle" goto continue end local x_or_y = rand(1, 3) if x_or_y == 1 then local x_rand_vel = rand(6, 11) writefloat(m_vehicleObj + 0x94, x_rand_vel) writefloat(m_vehicleObj + 0x90, 0) writefloat(m_vehicleObj + 0x8C, 0) elseif x_or_y == 2 then local y_rand_vel = rand(6, 11) writefloat(m_vehicleObj + 0x8C, y_rand_vel) writefloat(m_vehicleObj + 0x90, 0) writefloat(m_vehicleObj + 0x94, 0) else local z_rand_vel = rand(6, 11) writefloat(m_vehicleObj + 0x90, z_rand_vel) writefloat(m_vehicleObj + 0x94, 0) writefloat(m_vehicleObj + 0x8C, 0) end writefloat(m_vehicleObj + 0x70, 0.1) cmdreply[cmdreply()] = getname(playerId) .. " has been launched!" -- update object physics writefloat(m_vehicleObj + 0x70, 0.4) writebit(m_vehicleObj + 0x10, 0, 0) -- Unset noCollisions bit32. writebit(m_vehicleObj + 0x10, 5, 0) -- Unset ignorePhysics. ::continue:: end sendresponse(cmdreply, executorPlayerId) end } ) function lo3Timer(id, count) if gameend then return false end if count >= 3 then if not defaults.scrim_mode then say "WARNING! Scrim mode is NOT on!" end say "Start your match" halo_svcmd "sv_map_reset" lo3_timer = nil return false else halo_svcmd "sv_map_reset" return true end end Commands.Create( "lo3", { aliases = {"scrim", "startscrim"}, help = [[-- Live on Three -- Syntax: %s -- This command will reset the map 3 times]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) if lo3_timer then sendresponse("Live on three is already in progress! Please wait!", executorPlayerId) else sendresponse("Live on three.", executorPlayerId) lo3_timer = registertimer(500, "lo3Timer") end sendresponse("Live on three.", executorPlayerId) end } ) Commands.Create( "login", { aliases = {"l"}, help = [[-- Login -- Syntax: %s [Username] [Password] -- If there are no admins in the admin_table then you will be able to login with this command -- so you are able to use Chat commands even without being a hash or IP admin, it is only temporary.]] }, { arguments = {"String", "String", minArgs = 2, maxArgs = 2}, func = function(executorPlayerId, username, password) if not executorPlayerId then sendresponse("the Server is always logged in.", executorPlayerId) return end if PlayerClass[executorPlayerId].tempadmin then sendresponse("You are already logged in", executorPlayerId) return end if PlayerClass[executorPlayerId].admin_entry then sendresponse("You are already an admin!", executorPlayerId) return end if admin_logins[username] == password then PlayerClass[executorPlayerId].tempadmin = true sendresponse("You have successfully logged in, you are now able to use chat commands.", executorPlayerId) else sendresponse("Bad username/password combo.", executorPlayerId) end end } ) Commands.Create( "mnext", { aliases = {"mapnext"}, is_alias = true, help = [[-- Map Next -- Syntax: %s -- Shortcut for sv_map_next]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) halo_svcmd"sv_map_next" sendresponse("The next map will start shortly", executorPlayerId) end } ) Commands.Create( "reset", { aliases = {"mapreset", "resetmap"}, is_alias = true, help = [[-- Map Reset -- Syntax: %s -- Shortcut for sv_map_reset]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) halo_svcmd"sv_map_reset" sendresponse("The map has been reset", executorPlayerId) end } ) Commands.Create( "move", { aliases = {"j", "mv"}, scrimBlock = true, help = [[-- Move Player -- Syntax: %s [player] [x] [y] [z] -- Move the player by the set number of coords.]] }, { arguments = {"Player", "Number", "Number", "Number", minArgs = 4, maxArgs = 4}, func = function(executorPlayerId, players, X, Y, Z) local playerId, m_playerObj, playerObjId, x, y, z for i = 1,#players do playerId = players[i] m_playerObj, playerObjId = getplayerobject(playerId) if m_playerObj then x,y,z = getobjectcoords(playerObjId) movobjectcoords(playerObjId, x+X, y+Y, z+Z) local m_vehicleObj = getplayervehicle(playerId) if m_vehicleObj then -- these four lines are only in here for shoo. writebit(m_vehicleObj + 0x10, 5, 1) end cmdreply[cmdreply()] = getname(playerId) .. " has been moved" else cmdreply[cmdreply()] = getname(playerId) .. " is dead" end end sendresponse(cmdreply, executorPlayerId) end } ) --TODO: sv_announce_bans Commands.Create( "nameban", { aliases = {"banname"}, help = [[-- Name Ban -- Syntax: %s [Player] -- Bans a use of a name in the server]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local exname = getname(executorPlayerId) local playerId, name, ban_entry, found, b for i = 1,#players do playerId = players[i] name = getname(playerId) if not checkAdminBlockerAccess(executorPlayerId, playerId) then sendresponse("You cannot use this command on " .. name, executorPlayerId) privatesay(playerId, exname .. " attempted to NameBan you!") goto continue end if not randomNames[name] then b = {}--TM.New() b.name, b.type = name, "name" local args = defaults.remote_bansystem if args and args.mode == 2 then b.remote = true end ban_table[#ban_table+1] = b updateBanFiles() cmdreply[cmdreply()] = halo_svcmd("sv_kick " .. resolveplayer(playerId), true) say(name .. " has been name banned from the server") ::found:: else cmdreply[cmdreply()] = "You cannot ban this name because this name has been assigned automatically." end ::continue:: end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "overshield", { aliases = {"os", "giveos", "osgive", "giveovershield", "overshieldgive", "cheatgiveos", "cheatosgive", "cheatovershield", "cheatplayerovershield", "cheatgiveovershield", "cheatovershieldgive"}, scrimBlock = true, help = [[-- OverShield -- Syntax: %s [Player] -- Give specified players an overshield (os)]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, m_playerObj, playerObjId, mapId, m_vehicleObj, vehicleObjId, x, y, z, overshield, obj_shields for i = 1,#players do playerId = players[i] m_playerObj, playerObjId = getplayerobject(playerId) if not m_playerObj then cmdreply[cmdreply()] = getname(playerId) .. " is dead" goto continue end obj_shields = readfloat(m_playerObj + 0xE4) if obj_shields > 1 then cmdreply[cmdreply()] = getname(playerId) .. " already has an overshield" goto continue end m_vehicleObj, vehicleObjId = getplayervehicle(playerId) if m_vehicleObj then writefloat(m_playerObj + 0xE4, 3) else x,y,z = getobjectcoords(playerObjId) mapId = gettag("eqip", "powerups\\overshield") if mapId then overshield = getobject(createobject(mapId, 0, 0, false, x, y, z+0.5)) else cmdreply[cmdreply()] = "Overshield could not be spawned!" end if overshield then writefloat(overshield + 0x70, -2) end end cmdreply[cmdreply()] = getname(playerId) .. " has been given an overshield" ::continue:: end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "players", { aliases = {"pl", "playerlist", "showplayers", "listplayers"}, help = [[-- Player List -- Syntax: %s -- Displays a list of players. -- Displays all Player Indicies and Names]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) cmdreply.header = "[ID | Name]" cmdreply.delim = "|" cmdreply.align = true local playerId for rconId = 1,16 do playerId = rresolveplayer(rconId) if getplayer(playerId) then cmdreply[cmdreply()] = "[" .. rconId .. " (" .. playerId .. ") | " .. getname(playerId) .. "]" end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "playersmore", { aliases = {"plmore", "moreplayers"}, help = [[-- Extended Player List -- Syntax: %s -- Shows Player ID, Player Name, Player Team, Status(Admin/Regular), IP, and Hash]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) cmdreply.header = "[ID | Name | Team | Type | IP | Hash]" cmdreply.delim = "|" cmdreply.align = true local playerId, team for i = 1,16 do playerId = rresolveplayer(i) if not getplayer(playerId) then goto continue end team = getteam(playerId) team = team_play and (team == 0 and "Red" or team == 1 and "Blue" or "Hidden") or "FFA " .. team cmdreply[cmdreply()] = format("[%s | %s | %s | %s | %s | %s]", i, getname(playerId), team, PlayerClass[playerId].admin_entry and "Admin" or "Regular", getip(playerId), gethash(playerId)) ::continue:: end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "privatesay", { aliases = {"pvtsay", "psay", "sayprivately"}, help = [[-- Private Say --Syntax %s {player} {message} --Sends a private message to the specifed player]] }, { arguments = {"Player", "Remaining Arguments", minArgs = 2, maxArgs = 2}, func = function(executorPlayerId, players, message) for i = 1,#players do sendconsoletext(players[i], message) end sendresponse("Private messages sent.", executorPlayerId) end } ) Commands.Create( "rconlist", { aliases = {"listrcons", "rcons"}, help = [[-- Rcon Password List -- Syntax: %s -- Lists all available rcon passwords except the main rcon password]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) cmdreply.header = "[Rcon | Level]" cmdreply.align = true cmdreply.delim = "|" local rcon_entry for rcon,level in next,rcon_passwords do cmdreply[cmdreply()] = "[" .. rcon .. " | " .. level .. "]" end sendresponse(cmdreply, executorPlayerId) end } ) local function tobinary(number) number = tonumber(number) or error("bad argument #1 to 'tobinary' (number expected, got '" .. type(number) .. "')") local t = {}--TM.New() local rest while number > 0 do rest = number % 2 t[#t+1] = rest number = (number - rest) * 0.5 end return concat(t) end Commands.Create( "read", { help = [[-- Read Address/Struct -- Syntax: %s [Type] [Struct or Address] [Offset] [Value] [Player or Bit], [Player] -- Read the Guide for info on this command]] }, { arguments = {"Struct", "Number", "Bit", "Player", minArgs = 3, maxArgs = 3}, func = function(executorPlayerId, struct, offset, bit, players) local playerId, m_playerObj, playerObjId, value, float for i = 1,#players do playerId = players[i] m_playerObj = getplayerobject(playerId) if struct == "player" then struct = getplayer(playerId) elseif m_playerObj then if struct == "object" then struct = m_playerObj elseif struct == "weapon" then struct = getplayerweapon(playerId) if not struct then sendresponse(getname(playerId) .. " is not holding a Weapon", executorPlayerId) return end elseif struct == "vehicle" then struct = getplayervehicle(playerId) if not struct then sendresponse(getname(playerId) .. " is not in a Vehicle", executorPlayerId) return end end else sendresponse("Player Object must exist to use Struct: " .. struct) end value = readbit(struct + offset, struct) sendresponse("Reading " .. format("0x%08X", struct) .. " at Offset " .. format("0x%X", offset) .. " was a Success", executorPlayerId) sendresponse("Binary Val: " .. value, executorPlayerId) end end }, { arguments = {"Datatype", "Struct", "Number", "Player", minArgs = 3, maxArgs = 3}, func = function(executorPlayerId, datatype, struct, offset, players) local playerId, m_playerObj, playerObjId, float, value for i = 1,#players do playerId = players[i] m_playerObj, playerObjId = getplayerobject(playerId) if struct == "player" then struct = getplayer(playerId) elseif m_playerObj then if struct == "object" then struct = m_playerObj elseif struct == "weapon" then struct = getplayerweapon(playerId) if not struct then sendresponse(getname(playerId) .. " is not holding a Weapon", executorPlayerId) end elseif struct == "vehicle" then struct = getplayervehicle(playerId) if not struct then sendresponse(getname(playerId) .. " is not in a Vehicle", executorPlayerId) end end else sendresponse("Player Object must exist to use Struct: " .. struct) end if datatype == "bit8" then value = tobinary(readbyte(struct + offset)) elseif datatype == "bit16" then value = tobinary(readword(struct + offset)) elseif datatype == "bit32" then value = tobinary(readdword(struct + offset)) elseif datatype == "char" then value = readchar(struct + offset) elseif datatype == "byte" then value = readbyte(struct + offset) elseif datatype == "short" then value = readshort(struct + offset) elseif datatype == "word" then value = readword(struct + offset) elseif datatype == "int" then value = readint(struct + offset) elseif datatype == "dword" then value = readdword(struct + offset) elseif datatype == "float" then float = true value = readfloat(struct + offset) elseif datatype == "string" then value = readstring(struct + offset) elseif datatype == "widestring" then value = readwidestring(struct + offset) end sendresponse("Reading Address " .. format("0x%08X", struct) .. " was a Success", executorPlayerId) if not match(datatype, "^bit%d+$") then if float then sendresponse("Float: " .. value, executorPlayerId) elseif type(value) == "number" then sendresponse("Decimal: " .. value .. (value >= 0 and (" Hex: " .. format("0x%X", value)) or ""), executorPlayerId) else sendresponse("Value: " .. value, executorPlayerId) end else sendresponse("Binary Val: " .. value, executorPlayerId) end end end }, { arguments = {"Datatype", "Number", "Number", minArgs = 3, maxArgs = 3}, func = function(executorPlayerId, datatype, address, offset) local float, value if datatype == "bit8" then value = tobinary(readbyte(address + offset)) elseif datatype == "bit16" then value = tobinary(readword(address + offset)) elseif datatype == "bit32" then value = tobinary(readdword(address + offset)) elseif datatype == "char" then value = readchar(address + offset) elseif datatype == "byte" then value = readbyte(address + offset) elseif datatype == "short" then value = readshort(address + offset) elseif datatype == "word" then value = readword(address + offset) elseif datatype == "int" then value = readint(address + offset) elseif datatype == "dword" then value = readdword(address + offset) elseif datatype == "float" then float = true value = readfloat(address + offset) elseif datatype == "string" then value = readstring(address + offset) elseif datatype == "widestring" then value = readwidestring(address + offset) end sendresponse("Reading Address " .. format("0x%08X", offset) .. " was a Success", executorPlayerId) if float then sendresponse("Float: " .. value, executorPlayerId) elseif value >= 0 then sendresponse("Decimal: " .. value .. " Hex: " .. format("0x%X", value), executorPlayerId) else sendresponse("Value: " .. value, executorPlayerId) end end }, { arguments = {"Number", "Number", "Bit", minArgs = 3, maxArgs = 3}, func = function(executorPlayerId, address, offset, bit) sendresponse("Reading Address " .. format("0x%08X", address) .. " was a Success", executorPlayerId) sendresponse("Binary Val: " .. readbit(address + offset, bit) and 1 or 0, executorPlayerId) end } ) Commands.Create( "write", { help = [[-- Write -- Syntax: %s [Type] [Struct] [Offset] [Value] [Player] -- Read the Guide for info on this command]] }, { arguments = {"Datatype", "Struct", "Whole Number", "Number", "Player", minArgs = 3, maxArgs = 5}, func = function(executorPlayerId, datatype, struct, offset, value, playerId) --[[local address if count >= 5 and count <= 6 then if lower(sub(offset, 1, 2)) == "0x" then offset = tonumber(sub(offset, 3), 16) else offset = tonumber(offset) or tonumber(offset, 16) end local players = getvalidplayers(playerId, executorPlayerId) if players then local playerId for i = 1,#players do playerId = players[i] local m_playerObj, playerObjId = getplayerobject(playerId) if struct == "player" then address = getplayer(playerId) elseif struct ~= "object" and struct ~= "weapon" and struct ~= "vehicle" then sendresponse("Invalid Struct. Valid structs are: playerId, object, weapon, and vehicle.", executorPlayerId) elseif m_playerObj then if struct == "object" then address = m_playerObj elseif struct == "weapon" then address = getplayerweapon(playerId) if not address then sendresponse(getname(playerId) .. " is not holding a weapon", executorPlayerId) end elseif struct == "vehicle" then address = getplayervehicle(playerId) if not address then sendresponse(getname(playerId) .. " is not in a vehicle", executorPlayerId) end elseif not struct then sendresponse("Invalid Struct. Valid structs are: playerId, object, weapon, and vehicle", executorPlayerId) end elseif struct ~= "object" and struct ~= "weapon" and struct ~= "vehicle" then sendresponse("Invalid Struct. Valid structs are: playerId, object, weapon, and vehicle.", executorPlayerId) else sendresponse("playerId object must exist to use struct: " .. struct) end if offset and address then if lower(sub(tostring(value), 2)) == "0x" then value = tonumber(sub(tostring(value), 3), 16) else value = tonumber(value) or tonumber(value, 16) end if value then if datatype == "char" then writechar(address + offset, value) elseif datatype == "byte" then writebyte(address + offset, value) elseif datatype == "short" then writeshort(address + offset, value) elseif datatype == "word" then writeword(address + offset, value) elseif datatype == "int" then writeint(address + offset, value) elseif datatype == "dword" then writedword(address + offset, value) elseif datatype == "float" then writefloat(address + offset, value) elseif datatype == "string" then writestring(address + offset, value) elseif datatype == "widestring" then writewidestring(address + offset, value) else sendresponse("Invalid datatype. Valid datatypes are 'char', 'byte', 'short', 'word', 'int', 'dword', 'float', 'string', and 'widestring'", executorPlayerId) end sendresponse("Writing " .. value .. " to address " .. format("0x%08X", offset) .. " was a success", executorPlayerId) else sendresponse("Value must be a number", executorPlayerId) end elseif not offset then sendresponse("Offset must be a number", executorPlayerId) end end elseif not playerId then if lower(sub(struct, 1, 2)) == "0x" then address = tonumber(sub(struct, 3), 16) else address = tonumber(struct) or tonumber(struct, 16) end if address then if offset then if lower(sub(value, 1, 2)) == "0x" then value = tonumber(sub(value, 3), 16) else value = tonumber(value) or tonumber(value, 16) end if value then if datatype == "char" then writechar(address + offset, value) elseif datatype == "byte" then writebyte(address + offset, value) elseif datatype == "short" then writeshort(address + offset, value) elseif datatype == "word" then writeword(address + offset, value) elseif datatype == "int" then writeint(address + offset, value) elseif datatype == "dword" then writedword(address + offset, value) elseif datatype == "float" then writefloat(address + offset, value) elseif datatype == "string" then writestring(address + offset, value) elseif datatype == "widestring" then writewidestring(address + offset, value) else sendresponse("Invalid datatype. Valid datatypes are 'char', 'byte', 'short', 'word', 'int', 'dword', 'float', 'string', and 'widestring'", executorPlayerId) return end sendresponse("Writing " .. value .. " to address " .. format("0x%08X", offset) .. " was a success", executorPlayerId) else sendresponse("Value must be a number.", executorPlayerId) end else sendresponse("Offset must be a number", executorPlayerId) end else sendresponse("Struct must be a number", executorPlayerId) end else sendresponse("Invalid Player", executorPlayerId) end end]] end } ) Commands.Create( "resetplayer", { aliases = {"playerreset", "playereset"}, help = [[-- Reset Player -- Syntax: %s [Player] -- Removes all troll settings from specified player]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId for i = 1,#players do playerId = players[i] ResetPlayer(playerId) cmdreply[cmdreply()] = getname(playerId) .. " has been reset." end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "resetweapons", { aliases = {"resetweaps", "weaponsreset", "weapsreset"}, scrimBlock = true, help = [[-- Reset Weapons -- Syntax: %s [Player] -- Reset the weapons of the specified players]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, player, m_playerObj for i = 1,#players do playerId = players[i] PlayerClass[playerId].disarmed = false resetweapons(playerId) cmdreply[cmdreply()] = getname(playerId) .. " had their weapons reset" end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "resp", { aliases = {"respplayer", "playerresp"}, scrimBlock = true, help = [[-- Respawn Time for Player -- Syntax: %s [Player] {Time} -- Change the player's respawn time]] }, { arguments = {"Player", "Time", minArgs = 2, maxArgs = 2}, func = function(executorPlayerId, players, time) local playerId, m_playerObj for i = 1,#players do playerId = players[i] m_playerObj = getplayerobject(playerId) if not m_playerObj then writedword(getplayer(playerId) + 0x2C, time) cmdreply[cmdreply()] = "Setting " .. getname(playerId) .. "'s respawn time to " .. timetoword(time) else cmdreply[cmdreply()] = getname(playerId) .. " is alive. Setting their respawn time will do nothing." end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "rtvrequired", { aliases = {"rtvneeded", "totalrtv", "rtvtotal", "rtvpercent", "rtvpercentage", "rockthevoteneeded", "rockthevotepercent", "rockthevotetotal", "totalrockthevote", "midgamevoteneeded"}, help = [[-- RTV Needed -- Syntax: %s [Percent] -- Change the number of votes needed for RTV to change the map.]] }, { arguments = {"Percent", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, percent) if percent then sendresponse("Votes required for RTV has been set to " .. percent .. "%", executorPlayerId) defaults.rtv_required = percent else sendresponse(defaults.rtv_required .. "% votes required for RTV", executorPlayerId) end end } ) Commands.Create( "rtvtimeout", { aliases = {"rockthevotetimeout"}, help = [[-- RTV Timeout -- Syntax: %s {Time} -- The amount of time between each RTV attempt.]] }, { arguments = {"Time", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, time) if time == -1 then sendresponse("RTV Timeout is currently " .. timetoword(defaults.rtv_timeout), executorPlayerId) else sendresponse("RTV Timeout has been set to " .. timetoword(time), executorPlayerId) defaults.rtv_timeout = time end end } ) Commands.Create( "setammo", { aliases = {"ammo", "ammoset"}, scrimBlock = true, help = [[-- Set Ammo -- Syntax: %s [Player] [Type] [Ammo] -- Set the ammo of the players specified -- type means type of ammo, use 1 for unloaded ammo and 2 for loaded ammo]] }, { arguments = {"Player", "String", "Whole Number", minArgs = 3, maxArgs = 3}, func = function(executorPlayerId, players, ammotype, ammo) local playerId, m_playerObj, playerObjId, m_weaponObj, weaponObjId for i = 1,#players do playerId = players[i] m_playerObj, playerObjId = getplayerobject(playerId) if not m_playerObj then cmdreply[cmdreply()] = getname(playerId) .. " is dead and cannot have ammo" goto continue end m_weaponObj, weaponObjId = getplayerweapon(playerId) if not m_weaponObj then cmdreply[cmdreply()] = getname(playerId) .. " is not holding any weapons" goto continue end if ammotype == "unloaded" or ammotype == "1" then writeword(m_weaponObj + 0x2B6, ammo) cmdreply[cmdreply()] = getname(playerId) .. " had their unloaded ammo changed to " .. ammo elseif ammotype == "loaded" or ammotype == "2" then writeword(m_weaponObj + 0x2B8, ammo) updateammo(weaponObjId) cmdreply[cmdreply()] = getname(playerId) .. " had their loaded ammo changed to " .. ammo else cmdreply[cmdreply()] = "Invalid ammo type: 1 for unloaded, 2 for loaded ammo" end ::continue:: end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "color", { aliases = {"setcolor", "colorset", "playercolor", "cheatsetcolor", "cheatplayercolor"}, scrimBlock = true, help = [[-- Set Color -- Syntax: %s [Player] [Color] -- Change the color of the selected player. Works on FFA Only]] }, { arguments = {"Player", "String", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, players, color) -- check if argument is correct color if color then color = tonumber(color) or player_colors[color] if type(color) ~= "number" then sendresponse("Invalid Color", executorPlayerId) return end end local color_name = player_colors[color] local playerId, m_playerObj, playerObjId, player, x, y, z for i = 1,#players do playerId = players[i] if not color then cmdreply[cmdreply()] = getname(playerId) .. " is currently " .. (player_colors[readbyte(getplayer(playerId) + 0x60)] or "Invalid Color") goto continue end setcolor(playerId, color) cmdreply[cmdreply()] = getname(playerId) .. " had their color changed to '" .. color_name .. "'" ::continue:: end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "assists", { aliases = {"setassists", "assistset"}, scrimBlock = true, help = [[-- Set Assists -- Syntax: %s [Player] {Assists} -- Set the assists for the specified players]] }, { arguments = {"Player", "Whole Number", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, players, assists) local playerId if not assists then for i = 1,#players do playerId = players[i] cmdreply[cmdreply()] = getname(playerId) .. " Assists: " .. tostring(readshort(getplayer(playerId) + 0xA4, assists)) end else for i = 1,#players do playerId = players[i] writeshort(getplayer(playerId) + 0xA4, assists) cmdreply[cmdreply()] = getname(playerId) .. " had their assists set to " .. assists end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "deaths", { aliases = {"setdeaths", "deathset"}, scrimBlock = true, help = [[-- Set Deaths -- Syntax: %s [Player] {Deaths} -- Set the deaths for the specified players]] }, { arguments = {"Player", "Whole Number", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, players, deaths) local playerId if not deaths then for i = 1,#players do playerId = players[i] cmdreply[cmdreply()] = getname(playerId) .. " Deaths: " .. tostring(readshort(getplayer(playerId) + 0xAE, deaths)) end else for i = 1,#players do playerId = players[i] writeshort(getplayer(playerId) + 0xAE, deaths) cmdreply[cmdreply()] = getname(playerId) .. " had their deaths set to " .. deaths end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "kills", { aliases = {"setkills", "killset"}, scrimBlock = true, help = [[-- Set Kills -- Syntax: %s [Player] {Kills} -- Set the kills for the specified players]] }, { arguments = {"Player", "Whole Number", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, players, kills) local playerId if not kills then for i = 1,#players do playerId = players[i] cmdreply[cmdreply()] = getname(playerId) .. " Kills: " .. tostring(readshort(getplayer(playerId) + 0x9C, kills)) end else for i = 1,#players do playerId = players[i] writeshort(getplayer(playerId) + 0x9C, kills) cmdreply[cmdreply()] = getname(playerId) .. " had their kills set to " .. kills end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "score", { aliases = {"setscore", "scoreset"}, scrimBlock = true, help = [[-- Set Score -- Syntax: %s [Player] {Score} -- Set the score for the specified players]] }, { arguments = {"Player", "Whole Number", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, players, score) local playerId if not score then for i = 1,#players do playerId = players[i] cmdreply[cmdreply()] = getname(playerId) .. ": " .. getscore(playerId) end else local playerId for i = 1,#players do playerId = players[i] setscore(playerId, score) cmdreply[cmdreply()] = getname(playerId) .. " had their score set to " .. score end sendresponse(cmdreply, executorPlayerId) end end } ) Commands.Create( "teamscore", { aliases = {"setteamscore", "seteamscore", "teamscoreset"}, scrimBlock = true, help = [[-- Set Team Score -- Syntax: %s [Team] {Score} -- Set the score for the specified team]] }, { arguments = {"Whole Number", "Whole Number", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, team, score) if not score then sendresponse("Team " .. team .. ": " .. getteamscore(team), executorPlayerId) else setteamscore(team, score) sendresponse("Team " .. team .. " had their score set to " .. score, executorPlayerId) end end } ) Commands.Create( "scorelimit", { aliases = {"setscorelimit"}, help = [[-- Set Score Limit -- Syntax: %s {Score} -- Set the score for the specified players]] }, { arguments = {"Whole Number", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, score) if not score then sendresponse("Scorelimit: " .. getscorelimit(), executorPlayerId) else sendresponse("Scorelimit set to " .. (setscorelimit(score) or score), executorPlayerId) end end } ) Commands.Create( "frags", { aliases = {"setfrags", "fragset", "setfragnades"}, scrimBlock = true, help = [[-- Set Frags -- Syntax: %s [Player] {Frags} -- Set the frags for the specified players]] }, { arguments = {"Player", "Whole Number", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, players, frags) frags = frags > 7 and 7 or frags local playerId, m_playerObj, playerObjId for i = 1,#players do playerId = players[i] m_playerObj, playerObjId = getplayerobject(playerId) if not m_playerObj then cmdreply[cmdreply()] = getname(playerId) .. " is dead" goto continue end if not frags then cmdreply[cmdreply()] = getname(playerId) .. " Frags: " .. readbyte(m_playerObj + 0x31E) else writebyte(m_playerObj + 0x31E, frags) cmdreply[cmdreply()] = "Setting " .. getname(playerId) .. "'s frag grenades to " .. frags --privatesay(playerId, "Your frag grenades were set to " .. frags) end ::continue:: end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "plasmas", { aliases = {"setplasmas", "stickies", "plasmaset", "setplasmanades"}, scrimBlock = true, help = [[-- Set Plasmas -- Syntax: %s [Player] {Plasmas} -- Set the plasmas for the specified players]] }, { arguments = {"Player", "Whole Number", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, players, plasmas) plasmas = plasmas > 7 and 7 or plasmas local playerId, m_playerObj, playerObjId for i = 1,#players do playerId = players[i] m_playerObj, playerObjId = getplayerobject(playerId) if not m_playerObj then cmdreply[cmdreply()] = getname(playerId) .. " is dead" goto continue end if not plasmas then cmdreply[cmdreply()] = getname(playerId) .. " Plasmas: " .. readbyte(m_playerObj + 0x31E) else writebyte(m_playerObj + 0x31E, plasmas) cmdreply[cmdreply()] = "Setting " .. getname(playerId) .. "'s plasma grenades to " .. plasmas --privatesay(playerId, "Your plasma grenades were set to " .. plasmas) end ::continue:: end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "prefix", { aliases = {"setprefix", "serverprefix"}, help = [[-- Set Server Prefix -- Syntax: %s [Prefix] -- Will set the server prefix on sv_say messages to whatever you want (e.g. **SERVER** **MYCLAN** **PHASOR**)]] }, { arguments = {"Remaining Arguments", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, prefix) if prefix == "default" then server_prefix = nil sendresponse("Prefix is now set to default **SERVER**", executorPlayerId) elseif prefix then server_prefix = prefix sendresponse(server_prefix .. " is the new prefix.", executorPlayerId) else sendresponse(server_prefix .. " is the current prefix.", executorPlayerId) end end } ) Commands.Create( "say", { help = [[-- Server Say -- Syntax: %s [Message] -- Will send a message as the Server to anyone currently in the game.]] }, { arguments = {"String", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, message) say(message) end } ) Commands.Create( "mode", { aliases = {"setmode", "modeset"}, scrimBlock = true, help = [[-- mode -- Syntax: %s [Player] [Mode] {Object} -- destroy -- portalgun -- entergun -- spawngun -- normal]] }, { arguments = {"Player", "String", "String", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, players, bulletmode) local playerId for i = 1,#players do playerId = players[i] if bulletmode == "destroy" then PlayerClass[playerId].bulletmode = "destroy" cmdreply[cmdreply()] = getname(playerId) .. " is now in destroy mode" elseif bulletmode == "portalgun" then PlayerClass[playerId].bulletmode = "portalgun" cmdreply[cmdreply()] = getname(playerId) .. " is now in portalgun mode" elseif bulletmode == "entergun" then PlayerClass[playerId].bulletmode = "entergun" cmdreply[cmdreply()] = getname(playerId) .. " is now in entergun mode" elseif bulletmode == "normal" or bulletmode == "none" or bulletmode == "regular" then local player = PlayerClass[playerId] player.objspawnid = false player.bulletmode = false cmdreply[cmdreply()] = getname(playerId) .. " is now in normal mode" elseif bulletmode then cmdreply[cmdreply()] = "Invalid Bullet Mode!" else cmdreply[cmdreply()] = getname(playerId) .. " Bulletmode: " .. PlayerClass[playerId.bulletmode] end end sendresponse(cmdreply, executorPlayerId) end }, { arguments = {"Player", "String", "Object", minArgs = 3, maxArgs = 3}, func = function(executorPlayerId, players, bulletmode, object) if bulletmode == "spawngun" then local playerId, player for i = 1,#players do playerId = players[i] player = PlayerClass[playerId] player.bulletmode = "spawngun" player.objspawnid = object.mapId cmdreply[cmdreply()] = getname(playerId) .. " is now spawning " .. object.name .. "" end else sendresponse("Invalid Bullet Mode!", executorPlayerId) end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "password", { aliases = {"setpass", "pass", "setpassword", "passwordset"}, help = [[-- Set Server Password -- Syntax: %s {Password} -- Self-explanatory.]] }, { arguments = {"Password", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, password) if not password then sendresponse("The password is currently: " .. readstring(addresses.network_server_globals + 0x8, 8), executorPlayerId) elseif password == "" then writestring(addresses.network_server_globals + 0x8, 8, "") sendresponse("Password has been taken off", executorPlayerId) elseif password then writestring(addresses.network_server_globals + 0x8, 8, password) sendresponse("The password is now " .. password, executorPlayerId) end end } ) Commands.Create( "reloadadmins", { aliases = {"reloadadminlist", "adminlistreload", "adminsreload"}, help = [[-- Reload Admin List -- Syntax: %s -- Loads all admins from the admin file.]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) loadAllAdminFiles() -- We can now archive the other admin files without worrying about losing the data. os.rename(profilepath .. "ipadmins.txt", profilepath .. "archived_ipadmins.txt") os.rename(profilepath .. "admin.txt", profilepath .. "archived_admin.txt") sendresponse("All admins have been reloaded from the file.", executorPlayerId) end } ) --[====[Commands.Create( "loadbanlist", { aliases = {"banlistload", "loadbans", "bansload", "mergebans", "bansmerge", "mergebanlist", "banlistmerge"}, help = [[-- Reload Banlist -- Syntax: %s -- Loads all bans from the ban file.]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) -- Save the ban table temporarily local temp_bantable = {}--TM.New() for id = 1,#ban_table do temp_bantable[id] = ban_table[id] end loadBanFile(profilepath .. "ipbans.txt", "ip") -- load sapp ip bans loadBanFile(profilepath .. "ipbanlist.txt", "ip") -- load ipbanlist file for backwards compatibility loadBanFile(profilepath .. "iprangebanlist.txt", "ip") -- load iprangebanlist file for backwards compatibility loadBanFile(profilepath .. "textbanlist.txt", "chat") -- load textbanlist file for backwards compatibility loadBanFile(profilepath .. "namebans.txt", "name") -- load textbanlist file for backwards compatibility loadBanFile(profilepath .. defaults.banlist_file .. ".txt") -- we're not going to remove the files, let's just rename them so we don't upset anyone. local timestamp = os.date "%Y_%m_%d_%H_%M_%S" os.rename(profilepath .. "ipbans.txt", profilepath .. "old_ipbans_" .. timestamp .. ".txt") os.rename(profilepath .. "ipbanlist.txt", profilepath .. "old_ipbanlist_" .. timestamp .. ".txt") os.rename(profilepath .. "iprangebanlist.txt", profilepath .. "old_iprangebanlist_" .. timestamp .. ".txt") os.rename(profilepath .. "textbanlist.txt", profilepath .. "old_textbanlist_" .. timestamp .. ".txt") os.rename(profilepath .. "namebans.txt", profilepath .. "old_namebans_" .. timestamp .. ".txt") -- Check if a banned player is in the server. local cur_time = os.time() local hash, ip, ban_entry for playerId = 0,15 do if not getplayer(playerId) then goto continue end hash, ip = gethash(playerId), getip(playerId) for id = 1,#ban_table do ban_entry = ban_table[id] if ban_entry.time > cur_time then if ban_table.type == "hash" and hash == ban_table.hash or ban_table.type == "ip" and netMatch(ban_table.ip, ip) then tempBanPlayer(resolveplayer(playerId)) break elseif ban_entry.type == "chat" and (ban_entry.hash == hashOnlyOnScriptReload or netMatch(ban_entry.ip, ip)) 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 during a reload.") break end end end ::continue:: end updateBanFiles() sendresponse("The Banlist has been reloaded.", executorPlayerId) end } )]====] Commands.Create( "reloadbanlist", { aliases = {"banlistreload", "reloadbans", "bansreload", "refreshipbans"}, help = [[-- Reload Banlist -- Syntax: %s -- Loads all bans from the ban file.]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) -- Clear the ban table. for id = 1,#ban_table do ban_table[id] = nil end local args = defaults.remote_bansystem if args then reloadRemoteBanlist() end if not args or args and args.mode ~= 2 then loadBanFile(profilepath .. "ipbans.txt", "ip") -- load sapp ip bans loadBanFile(profilepath .. "ipbanlist.txt", "ip") -- load ipbanlist file for backwards compatibility loadBanFile(profilepath .. "iprangebanlist.txt", "ip") -- load iprangebanlist file for backwards compatibility loadBanFile(profilepath .. "textbanlist.txt", "chat") -- load textbanlist file for backwards compatibility loadBanFile(profilepath .. "namebans.txt", "name") -- load textbanlist file for backwards compatibility loadBanFile(profilepath .. defaults.banlist_file .. ".txt") -- we're not going to remove the files, let's just rename them so we don't upset anyone. local timestamp = os.date"%Y_%m_%d_%H_%M_%S" os.rename(profilepath .. "ipbans.txt", profilepath .. "old_ipbans_" .. timestamp .. ".txt") os.rename(profilepath .. "ipbanlist.txt", profilepath .. "old_ipbanlist_" .. timestamp .. ".txt") os.rename(profilepath .. "iprangebanlist.txt", profilepath .. "old_iprangebanlist_" .. timestamp .. ".txt") os.rename(profilepath .. "textbanlist.txt", profilepath .. "old_textbanlist_" .. timestamp .. ".txt") os.rename(profilepath .. "namebans.txt", profilepath .. "old_namebans_" .. timestamp .. ".txt") end -- The banned player could be currently playing on the server. Apply punishments to players that are found on the banlist. for playerId = 0,15 do if getplayer(playerId) then punishIfOnBanlist(playerId) end end updateBanFiles() sendresponse("The Banlist has been reloaded.", executorPlayerId) end } ) Commands.Create( "respawntime", { aliases = {"setresp", "setrespawntime"}, help = [[-- Server Respawn Time -- Syntax: %s {Time} -- Sets the default respawn time for all players.]] }, { arguments = {"Time", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, time) if time == -1 then sendresponse("Respawn time is currently: " .. (defaults.respawn_time ~= -1 and timetoword(defaults.respawn_time) or "Default")) else defaults.respawn_time = time sendresponse("Respawn time set to " .. (time ~= -1 and timetoword(time) or "Default"), executorPlayerId) end end } ) Commands.Create( "setspeed", { aliases = {"spd", "s", "speed", "speedset"}, scrimBlock = true, help = [[-- Set Speed -- Syntax: %s [Player] {Speed} -- Allow you to view/change the selected players' speed]] }, { arguments = {"Player", "Number", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, players, speed) local playerId if not speed then for i = 1,#players do playerId = players[i] speed = readfloat(getplayer(playerId) + 0x6C) sendresponse(getname(playerId) .. "'s speed is currently " .. speed, executorPlayerId) end else for i = 1,#players do playerId = players[i] setspeed(playerId, speed) sendresponse(getname(playerId) .. " had their speed changed to " .. speed, executorPlayerId) end end end } ) local function saveTeleportsToFile() local file = assert(io.open(profilepath .. "data\\locations.txt", "w")) local writetbl = {} for map,mapLocations in next,locations do for locname,thisLocation in next,mapLocations do writetbl[#writetbl+1] = map .. "," .. locname .. "," .. thisLocation[1] .. "," .. thisLocation[2] .. "," .. thisLocation[3] end end file:write(concat(writetbl, "\n")) file:close() end Commands.Create( "setteleport", { aliases = {"settp", "teleportadd", "addteleport", "tadd", "st", "tpadd", "addtp", "addlocation", "locationadd"}, help = [[--Set Teleport Location -- Syntax: %s [Location] [Player or X] {Y} {Z} -- Adds a teleport location wherever the specified player is standing. -- Or you can manually specify XYZ Coordinates for a location]] }, { arguments = {"String", "Number", "Number", "Number", "String", minArgs = 4, maxArgs = 5}, func = function(executorPlayerId, locname, x, y, z, map) locations[map or Map][locname] = {x, y, z} sendresponse("'" .. locname .. "' has been added as a teleport location!", executorPlayerId) end }, { arguments = {"String", "Single Player", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, locname, playerId) local m_playerObj, playerObjId = getplayerobject(playerId) if not m_playerObj then sendresponse("Cannot add teleport because the player is dead.", executorPlayerId) return end if locations[Map][locname] then sendresponse("Location '" .. locname .. "' already exists on this map!\nUse sv_teleport_del to remove it from the list first.", executorPlayerId) return end local x,y,z = getobjectcoords(playerObjId) locations[Map][locname] = {x, y, z} sendresponse("'" .. locname .. "' has been added as a teleport location!", executorPlayerId) saveTeleportsToFile() end } ) Commands.Create( "teleportlist", { aliases = {"tlist", "listteleports", "locations", "teleports", "locs"}, help = [[--List Teleport Locations -- Syntax: %s {Map} -- Lists all the teleport locations available for teleporting.]] }, { arguments = {"String", minArgs = 0, maxArgs = 0}, func = function(executorPlayerId, map) map = map or Map or "all" sendresponse("Teleport Locations " .. (map ~= "all" and (" for map " .. map) or ""), executorPlayerId) cmdreply.header = "Map Location" cmdreply.align = true cmdreply.delim = " " for thisMap,mapLocations in next,locations do for locname,_ in next,mapLocations do if map == thisMap or map == "all" then cmdreply[cmdreply()] = thisMap .. " " .. locname end end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "allvehicles", { aliases = {"allvehis", "spawnvehicles", "spawnallvehicles", "spawnvehis", "spawnallvehi", "spawnallvehis"}, help = [[ -- Spawn All Vehicles -- Syntax: %s {Player} -- Spawns all vehicles available to a map at a specific player's location.]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local tag_class, tag_id, tag_name_address, tag_name, tag_address, playerId, playerObjId, m_playerObj, x, y, z for j = 1,#players do playerId = players[j] for i = 1,#tag_table.vehi do tag_id = tag_table.vehi[i] --for tag_id,tag_entry in pairs(tag_table) do playerObjId = getplayerobjectid(playerId) m_playerObj = getobject(playerObjId) x,y,z = getobjectcoords(playerObjId) x = x + readfloat(m_playerObj + 0x230) * 2 y = y + readfloat(m_playerObj + 0x234) * 2 createobject(tonumber(tag_id), 0, 65534, false, x, y + i*2, z+2) sendresponse("Vehicle '" .. tostring(tag_id) .. "' spawned at " .. getname(playerId) .. "'s location!", playerId) end end sendresponse(#tag_table.vehi .. " of each vehicle was spawned.", executorPlayerId) end } ) Commands.Create( "allweapons", { aliases = {"allweaps", "spawnweapons", "spawnallweapons", "spawnweaps", "spawnallweap", "spawnallweaps"}, help = [[ -- Spawn All Weapons -- Syntax: %s {Player} -- Spawns all weapons available to a map at a specific player's location.]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local tag_class, tag_id, tag_name_address, tag_name, tag_address, playerId, playerObjId, m_playerObj, x, y, z, iter, objectId, m_object for i = 1,#players do playerId = players[i] iter = 0 for tag_id,tag_entry in pairs(tag_table) do if type(tag_entry) == "table" and tag_entry.tag_class == "weap" then playerObjId = getplayerobjectid(playerId) m_playerObj = getobject(playerObjId) x,y,z = getobjectcoords(playerObjId) x = x + readfloat(m_playerObj + 0x230) * 2 y = y + readfloat(m_playerObj + 0x234) * 2 objectId = getobject(createobject(tonumber(tag_id), 0, 65534, true, x, y + iter, z+2)) m_object = getobject(objectId) if m_object then end sendresponse("Weapon '" .. tostring(tag_id) .. "' spawned at " .. getname(playerId) .. "'s location!", playerId) iter = iter + 0.5 end end end end } ) Commands.Create( "allequipment", { aliases = {"alleqip", "spawnequipment", "spawnallequipment", "spawneqips", "spawnalleqip", "spawnalleqips"}, help = [[ -- Spawn All Equipment -- Syntax: %s {Player} -- Spawns all weapons available to a map at a specific player's location.]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local tag_class, tag_id, tag_name_address, tag_name, tag_address, playerId, playerObjId, m_playerObj, x, y, z, iter for i = 1,#players do playerId = players[i] iter = 0 for tag_id,tag_entry in pairs(tag_table) do if type(tag_entry) == "table" and tag_entry.tag_class == "eqip" then playerObjId = getplayerobjectid(playerId) m_playerObj = getobject(playerObjId) x,y,z = getobjectcoords(playerObjId) x = x + readfloat(m_playerObj + 0x230) * 2 y = y + readfloat(m_playerObj + 0x234) * 2 createobject(tonumber(tag_id), 0, 65534, true, x, y + iter, z+2 + iter*2) sendresponse("Equipment '" .. tostring(tag_id) .. "' spawned at " .. getname(playerId) .. "'s location!", playerId) iter = iter + 0.25 end end end end } ) -- ADD JETPACK COMMAND FROM BRANDIS SCRIPT HERE! Commands.Create( "ghost", { aliases = {"ghostplayer"}, help = [[ -- Ghost Player -- Syntax: %s [Player] -- Puts a player into Ghost Mode, they will not have a collision model -- bullets will pass right through them ]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, m_playerObj for i = 1,#players do playerId = players[i] m_playerObj = getplayerobject(playerId) if m_playerObj then writebit(m_playerObj + 0x10, 0, 1) sendresponse(getname(playerId) .. " is now a ghost!", executorPlayerId) --privatesay(playerId, "You are now a ghost.") else sendresponse("You cannot ghost " .. getname(playerId) .. " because " .. getname(playerId) .. " is dead!", executorPlayerId) end end end } ) Commands.Create( "unghost", { aliases = {"ghostplayer"}, help = [[ -- Unghost Player -- Syntax: %s [Player] -- Removes a player from Ghost Mode]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, m_playerObj for i = 1,#players do playerId = players[i] m_playerObj = getplayerobject(playerId) if m_playerObj then writebit(m_playerObj + 0x10, 0, 0) sendresponse(getname(playerId) .. " is no longer a ghost!", executorPlayerId) else sendresponse("You cannot unghost " .. getname(playerId) .. " because " .. getname(playerId) .. " is dead!", executorPlayerId) end end end } ) local function updateObjectPhysics(objId, m_object) m_object = m_object or getobject(objId) if m_object then writebit(m_object + 0x10, 0, 0) -- Unset noCollisions bit. writebit(m_object + 0x10, 5, 0) -- Unset ignorePhysics. end end local function setVehicleUpright(objId, m_object) m_object = m_object or getobject(objId) if m_object then writefloat(m_object + 0x8A, 2.3 * (10 ^ -41)) writefloat(m_object + 0x8C, 2.3 * (10 ^ -41)) writefloat(m_object + 0x90, 2.3 * (10 ^ -41)) writefloat(m_object + 0x94, 2.3 * (10 ^ -41)) updateObjectPhysics(objId, m_object) end end Commands.Create( "upright", { aliases = {"rotate", "flip", "f", "setupright"}, help = [[ -- Upright Vehicle -- Syntax: %s [Player] -- Places a player's vehicle in the upright position.]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, playerVehiObjId, m_vehicleObj for i = 1,#players do playerId = players[i] playerVehiObjId = getplayervehicleid(playerId) m_vehicleObj = getobject(playerVehiObjId) if m_vehicleObj then setVehicleUpright(playerVehiObjId, m_vehicleObj) sendresponse(getname(playerId) .. " has been rotated upright!", executorPlayerId) else sendresponse(getname(playerId) .. " is not in a vehicle!", executorPlayerId) end end end }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, strBool) local newBool, response = ReturnScriptBooleanCheck("Antiflip", defaults.antiflip, strBool) if newBool ~= nil then defaults.antiflip = newBool end sendresponse(response, executorPlayerId) end } ) Commands.Create( "spawn", { aliases = {"spawnobj", "create", "createobject", "spawnobject", "objspawn"}, help = [[-- Spawn -- Syntax: %s [Object] [Player] {Amount} {Respawn Time} {Recycle Boolean} -- Spawns specified object near the specified player]] }, { arguments = {"Object", "Player", "Positive Number", "Whole Number", "Boolean", minArgs = 1, maxArgs = 5}, func = function(executorPlayerId, object, players, amount, resp_time, bRecycle, spawn_type) amount = amount or 1 bRecycle = not not bRecycle if spawn_type == "enter" and object.type ~= "vehi" then sendresponse("Invalid Vehicle!", executorPlayerId) return end if spawn_type == "give" and object.type ~= "weap" then sendresponse("Invalid Weapon!", executorPlayerId) return end if not object.mapId or object.mapId < 400 then sendresponse("Object " .. object.name .. " could not be spawned at this time.", executorPlayerId) return end local playerId, m_playerObj, playerObjId, objectId, x, y, z for i = 1,#players do playerId = players[i] m_playerObj, playerObjId = getplayerobject(playerId) if not m_playerObj then cmdreply[cmdreply()] = getname(playerId) .. " is dead" goto continue end -- Spawn the object right where they are looking (should work for vehicles too) x,y,z = getobjectcoords(playerObjId) x = x + readfloat(m_playerObj + 0x230) * 2 y = y + readfloat(m_playerObj + 0x234) * 2 -- Create the object for i = 0,amount-1 do --hprintf(tostring(object.mapId)) objectId = createobject(object.mapId, 0, resp_time, bRecycle, x, y + i, z+2 + i*2) end -- check if object was spawned correctly if not objectId then cmdreply[cmdreply()] = "Error spawning object: " .. object.name goto continue end if spawn_type == "give" then assignweapon(playerId, objectId) cmdreply[cmdreply()] = object.name .. " given to " .. getname(playerId) elseif spawn_type == "enter" then local drones = PlayerClass[playerId].drones drones[#drones+1] = objectId entervehicle(playerId, objectId, 0) cmdreply[cmdreply()] = getname(playerId) .. " was forced to enter a " .. object.name else cmdreply[cmdreply()] = object.name .. " spawned at " .. getname(playerId) .. "'s location." end ::continue:: end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "enter", { aliases = {"entervehicle", "vehicleeneter", "vehienter", "entervehi"}, scrimBlock = true, help = [[-- Enter Vehicle -- Syntax: %s [Player1 or Vehicle] [Player2] -- Force specified player into specified vehicle -- Or will put player1 into player2's vehicle, provided halo will let them. -- You cannot enter a vehicle of an enemy (unless sv_multiteam_vehicles is enabled in Free-For-All GameTypes)]] }, { arguments = {"Object", "Player", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, object, players) Commands.spawn[1].func(executorPlayerId, object, players, nil, nil, nil, "enter") end }, { arguments = {"Player", "Single Player", "Whole Number", minArgs = 3, maxArgs = 3}, func = function(executorPlayerId, players, playerId2, seat) local m_vehicleObj, vehicleObjId = getplayervehicle(playerId2) if not m_vehicleObj then sendresponse(getname(playerId2) .. " is not in a vehicle!", executorPlayerId) return end local playerId for i = 1,#players do playerId = players[i] entervehicle(playerId, vehicleObjId, seat) sendresponse("Entering " .. getname(playerId) .. " into " .. getname(playerId2) .. "'s vehicle!", executorPlayerId) end end } ) Commands.Create( "give", { aliases = {"giveweapon", "weapongive", "cheatgiveweapon"}, scrimBlock = true, help = [[-- Give -- Syntax: %s [Object] [Player] -- Gives specified player the specified weapon]] }, { arguments = {"Object", "Player", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, object, players) Commands.spawn[1].func(executorPlayerId, object, players, nil, nil, nil, "give") end } ) Commands.Create( "spammax", { aliases = {"smax", "maxspam"}, help = [[-- SpamMax -- Syntax: %s {Value or Boolean} -- Determines how many messages a player can send before a player is muted. -- Wizard recommends leaving this at the default, but you're welcome to change it -- Setting this to false or 0 will disable Spam Protection.]] }, { arguments = {"Boolean", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, boolean) if boolean == false and defaults.spam_max ~= false then defaults.spam_max = 0 sendresponse("Spam protection is now disabled", executorPlayerId) elseif not boolean and defaults.spam_max == false then sendresponse("Spam protection is already disabled", executorPlayerId) elseif boolean then defaults.spam_max = 7 sendresponse("Spam protection is now on!", executorPlayerId) end end }, { arguments = {"Number", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, time) if time == -1 then sendresponse("The Spam max is currently '" .. defaults.spam_max .. "'", executorPlayerId) else defaults.spam_max = time sendresponse("The Spam max is now " .. time, executorPlayerId) end end } ) Commands.Create( "spamtimeout", { aliases = {"timeoutspam"}, help = [[-- SpamTimeout -- Syntax: %s {Time} -- Changes the time you are muted for spamming]], }, { arguments = {"Time", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, time) if time == -1 then sendresponse("Spam timeout is currently " .. timetoword(defaults.spam_timeout), executorPlayerId) else defaults.spam_timeout = time sendresponse("The Spam timeout is now " .. timetoword(time), executorPlayerId) end end } ) Commands.Create( "specs", { aliases = {"serverspecs", "machineinfo"}, help = [[-- Specs -- Syntax: %s -- Display the server specifications (like processor, RAM, model, etc)]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) sendresponse("The server specs are: " .. readstring(addresses.computer_specs_address), executorPlayerId) end } ) Commands.Create( "mapcyclebegin", { aliases = {"mcbegin", "startcycle", "cyclestart", "mc"}, is_alias = true, help = [[-- Start MapCycle -- Syntax: %s -- Shortcut for sv_mapcycle_begin]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) sendresponse(halo_svcmd("sv_mapcycle_begin", true), executorPlayerId) end } ) Commands.Create( "ffa", { aliases = {"setffa"}, help = [[-- Set FFA -- Syntax: %s -- Hard-forces the current slayer game to act like a FFA gametype. -- unknown how it works on other gametypes.]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayer) local m_player, client_network_struct, client_color local ce = 0x0 if Game == "CE" then ce = 0x40 end for playerId = 0,15 do m_player = getplayer(playerId) if m_player then writebyte(m_player + 0x20, playerId) client_network_struct = addresses.network_struct + 0x1AA+ce + playerId * 0x20 client_color = readword(client_network_struct + 0x18) --say(getname(playerId) .. " is trying to turn " .. tostring(player_colors[client_color]) .. " aka " .. tostring(client_color) .. " name: " .. tostring(readwidestring(client_network_struct, 12))) setcolor(playerId, client_color) cmdreply[cmdreply()] = "Setting player " .. tostring(getname(playerId)) .. " to team " .. playerId .. " with color " .. player_colors[client_color] end end team_play = false sendresponse(cmdreply, executorPlayerId) sendresponse("FFA applied successfully", executorPlayerId) end } ) Commands.Create( "teams", { aliases = {"setteams"}, help = [[-- Set Teams -- Syntax: %s -- Hard-forces the current slayer game to act like a Team gametype. -- unknown how it works on other gametypes.]] }, { arguments = {"Whole Number", minArgs = 0, maxArgs = 1}, func = function(executorPlayer, amount) amount = amount or 2 local m_player, team for playerId = 0,15 do m_player = getplayer(playerId) if m_player then writebyte(m_player + 0x20, playerId%amount) setcolor(playerId, playerId%amount+2) team = getteam(playerId) team_scores[team] = team_scores[team] + getscore(playerId) cmdreply[cmdreply()] = "Setting player " .. tostring(getname(playerId)) .. " to team " .. (playerId%amount) end end sendresponse(cmdreply, executorPlayerId) sendresponse("Teams applied successfully", executorPlayerId) team_play = true end } ) --[[Commands.Create( "map", { aliases = {"m", "setmap", "choosemap"}, is_alias = true, help = -- Set Map -- Syntax: %s [Map] [Gametype] {script1} {script2} {script3 etc..} -- Ends the current game, and starts a new game on selected map and gametype. }, { arguments = {"Remaining Arguments", minArgs = 1, maxArgs = 10}, func = function(executorPlayerId, mapargs) halo_svcmd("sv_mapcycle_timeout 1") halo_svcmd("sv_mapvote 0") sendresponse("sv_map " .. mapargs, executorPlayerId) sendresponse(halo_svcmd("sv_map " .. mapargs, true), executorPlayerId) end } )]] Commands.Create( "statusmore", { aliases = {"serverinfo", "sinfo"}, help = [[-- Status -- Syntax: %s -- Shows a list of all the init.txt commands and their status.]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) for key,value in next,defaults do sendresponse(key .. ": " .. tostring(value), executorPlayerId) end end } ) Commands.Create( "superban", { aliases = {"ultraban", "megaban"}, help = [[-- Superban -- Syntax: %s [Player] {Time} {Reason} -- Bans a person via their Name, IP, and Hash -- Most likely overkill in most situations -- This command does the same as doing the following, -- where player is the player being banned, and time is a time if specified -- sv_ipban player time sv_nameban player sv_ban player time]], usesBanCounts = true, }, { arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3}, func = function(executorPlayerId, players, time, reason) local exname = getname(executorPlayerId) local playerId, name, b for i = 1,#players do playerId = players[i] name = getname(playerId) if not checkAdminBlockerAccess(executorPlayerId, playerId) then sendresponse("You cannot use this command on " .. name, executorPlayerId) privatesay(playerId, exname .. " attempted to SuperBan you!") goto continue end reason = reason == "None Given" and "SuperBan" or reason WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was Super-Banned by " .. exname .. " Reason: " .. reason) say(name .. " was Super Banned from the server! Reason: " .. reason) -- Create name ban. local b = {}--TM.New() b.name,b.type,b.reason = name,"name",reason ban_table[#ban_table+1] = b -- Add IP Ban addBan(name, nil, getip(playerId) .. "/24", time, "ip", reason) -- Execute Hash Ban svcmd("sv_ban " .. resolveplayer(playerId) .. " " .. timetoword(time)) ::continue:: end end } ) Commands.Create( "suspend", { aliases = {"suspendplayer", "playersuspend", "suspendpl", "sleep", "cheatsuspendplayer"}, scrimBlock = true, help = [[-- Suspend Player -- Syntax: %s [Player] {Time} -- Kills a player and prevents them from respawning.]] }, { arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3}, func = function(executorPlayerId, players, time, reason) reason = reason or "None Given" local playerId, player for i = 1,#players do playerId = players[i] player = PlayerClass[playerId] if player.suspended then cmdreply[cmdreply()] = getname(playerId) .. " has already been suspended." goto continue end local m_player = getplayer(playerId) kill(playerId) writedword(m_player + 0x2C, (time ~= -1 and time or 2880) * 30) player.suspended = time ~= -1 and time or true say(getname(playerId) .. " was suspended by an admin " .. (time ~= -1 and ("for " .. timetoword(time)) or "") .. " Reason: " .. reason) ::continue:: end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "unsuspend", { aliases = {"unsuspendplayer", "unsuspendpl", "playerunsuspend"}, help = [[-- Unsuspend Player -- Syntax: %s [Player] -- Unsuspends the specified player.]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId for i = 1,#players do playerId = players[i] if not PlayerClass[playerId].suspended then sendresponse(getname(playerId) .. " has never been suspended.", executorPlayerId) goto continue end writedword(getplayer(playerId) + 0x2C, 0) sendresponse(getname(playerId) .. " has been unsuspended", executorPlayerId) ::continue:: end end } ) Commands.Create( "takeweapons", { aliases = {"removeweapons", "takeweaponspl", "takeweps", "takeweaps", "weaponsremove", "weapsremove", "weapstake"}, scrimBlock = true, help = [[-- Take Weapons -- Syntax: %s [Player] -- Take all the weapons away from the specified player.]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, m_playerObj, playerObjId for i = 1,#players do playerId = players[i] PlayerClass[playerId].disarmed = true m_playerObj, playerObjId = getplayerobject(playerId) if m_playerObj then for slot = 0,3 do local m_weapon, weaponObjId = getplayerweapon(playerId, slot) if m_weapon then destroyobject(weaponObjId) end end end cmdreply[cmdreply()] = getname(playerId) .. " now cannot pickup weapons" end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "teleportdel", { aliases = {"tdel", "delteleport", "dellocation", "locationdel", "tpdel", "rmtel", "teldel", "deltel"}, help = [[--Delete Teleport Location -- Syntax: %s [Location] -- Deletes the specified teleport location -- Use 'sv_teleport_list' to get a list of teleport locations.]] }, { arguments = {"String", "String", minArgs = 1, maxArgs = 2}, func = function(executorPlayerId, locname, map) if map and not locations[map] then sendresponse("Invalid Map!", command, executorPlayerId) return end if map and locations[map][locname] then locations[map][locname] = nil sendresponse("Location '" .. locname .. "' on map '" .. map .. "' has been removed from the teleport locations list!", executorPlayerId) elseif Map and locations[Map][locname] then locations[Map][locname] = nil sendresponse("Location '" .. locname .. "' on map '" .. map .. "' has been removed from the teleport locations list!", executorPlayerId) else sendresponse("'" .. locname .. "' is not a teleport location\nUse sv_teleport_list for current teleport locations.", executorPlayerId) return end saveTeleportsToFile() end } ) Commands.Create( "teleport", { aliases = {"tp", "t", "teletolocation", "tele", "teletoloc"}, help = [[--Teleport Player -- Syntax: %s [Player] [Player2 or Location or X] {Y} {Z} -- Teleports the specified players' to a location. -- Use 'sv_teleport_list' to get a list of teleport locations. -- You can also use this command to teleport to a set of XYZ coordinates]] }, { arguments = {"Player", "Single Player", minArgs = 2, maxArgs = 2}, func = function(executorPlayerId, players, playerId2) local m_player2Obj, player2ObjId = getplayerobject(playerId2) if not m_player2Obj then sendresponse("The player you are trying to teleport to is dead!", executorPlayerId) return end local teletoname = getname(playerId2) local x,y,z = getobjectcoords(player2ObjId) local playerId, m_playerObj, playerObjId, m_vehicleObj, vehicleObjId for i = 1,#players do playerId = players[i] m_playerObj, playerObjId = getplayerobject(playerId) if not m_playerObj then cmdreply[cmdreply()] = "The players you are trying to teleport are dead" goto continue end m_vehicleObj, vehicleObjId = getplayervehicle(playerId) movobjectcoords(m_vehicleObj and vehicleObjId or playerObjId, x, y, z+1) cmdreply[cmdreply()] = getname(playerId) .. " was teleported to " .. teletoname ::continue:: end sendresponse(cmdreply, executorPlayerId) end }, { arguments = {"Player", "String", minArgs = 2, maxArgs = 2}, func = function(executorPlayerId, players, location) local thisLocation = locations[Map][location] if not thisLocation then sendresponse("Location '" .. location .. "' doesn't exist on this map!", executorPlayerId) return end -- A player can never exist unless the game is started on a map. local x,y,z = thisLocation[1], thisLocation[2], thisLocation[3] local playerId, m_playerObj, playerObjId, m_vehicleObj, vehicleObjId for i = 1,#players do playerId = players[i] m_playerObj, playerObjId = getplayerobject(playerId) if not m_playerObj then cmdreply[cmdreply()] = getname(playerId) .. " is dead and cannot be teleported." goto continue end m_vehicleObj, vehicleObjId = getplayervehicle(playerId) movobjectcoords(m_vehicleObj and vehicleObjId or playerObjId, x, y, z+1) cmdreply[cmdreply()] = getname(playerId) .. " was teleported to " .. location ::continue:: end sendresponse(cmdreply, executorPlayerId) end }, { arguments = {"Player", "Number", "Number", "Number", minArgs = 4, maxArgs = 4}, func = function(executorPlayerId, players, x, y, z) local playerId, m_playerObj, playerObjId, m_vehicleObj, vehicleObjId for i = 1,#players do playerId = players[i] m_playerObj, playerObjId = getplayerobject(playerId) if not m_playerObj then cmdreply[cmdreply()] = "The players you are trying to teleport are dead" goto continue end m_vehicleObj, vehicleObjId = getplayervehicle(playerId) movobjectcoords(m_vehicleObj and vehicleObjId or playerObjId, x, y, z+1) cmdreply[cmdreply()] = getname(playerId) .. " was teleported to " .. teletoname ::continue:: end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "textban", { aliases = {"mute", "muteplayer", "textbanplayer", "tban", "chatban", "playermute"}, help = [[-- Text Ban -- Syntax: %s [Player] {Time}]], }, { arguments = {"Player", "Time And Reason", minArgs = 1, maxArgs = 3}, func = function(executorPlayerId, players, time, reason) local exname = getname(executorPlayerId) local playerId, name, player for i = 1,#players do playerId = players[i] player = PlayerClass[playerId] if PlayerClass[playerId].admin_entry then cmdreply[cmdreply()] = "Admins cannot be banned from the chat!" elseif player.muted then cmdreply[cmdreply()] = getname(playerId) .. " is already textbanned!" else name = getname(playerId) player.muted = true addBan(name, gethash(playerId), getip(playerId) .. "/24", time, "chat", reason) WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", name .. " was text banned by " .. exname .. " Reason: " .. reason) say(name .. " was text banned from the server by an admin! Reason: " .. reason) cmdreply[cmdreply()] = name .. " has been banned from the chat " .. ((time == -1 and "indefinitely") or ("for " .. timetoword(time))) end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "timecur", { aliases = {"curtime"}, scrimBlock = true, help = [[-- Current Time -- Syntax: %s {Time}]] }, { arguments = {"Time", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, time) if time == -1 then local time_passed = readdword(readdword(addresses.gameinfo_header) + 0xC) - (time_passed_value or 0) local timelimit = timelimit_set_value or readdword(addresses.gametype_base + 0x78) local time_left = (timelimit - time_passed) / 30 sendresponse("Current Timelimit is " .. timetoword(timelimit) .. ". Time remaining: " .. timetoword(time_left), executorPlayerId) else timelimit_set_value = time time_passed_value = readdword(readdword(addresses.gameinfo_header) + 0xC) writedword(addresses.gametype_base + 0x78, time_passed_value + 30*time) -- Can't set time_passed to 0 because it causes weird stuff to happen. sendresponse("Timelimit set to " .. timetoword(time), executorPlayerId) end end } ) Commands.Create( "unbos", { aliases = {"removebos", "bosremove", "unbanbos", "bosunban"}, help = [[-- Remove from Ban on Sight List -- Syntax: %s [ID] -- Remove selected index off of the ban on sight list]] }, { arguments = {"Positive Number", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, ID) local entry = bos_table[ID] if not entry then sendresponse("Invalid Entry", executorPlayerId) else sendresponse("Removing " .. entry.name .. " - " .. entry.hash .. " from BoS.", executorPlayerId) remove(bos_table, ID) end end } ) Commands.Create( "ungod", { aliases = {"unsetgod", "removegod", "godunset", "godremove", "cheatunsetgod", "cheatremovegod", "cheatremovegodmode"}, help = [[-- Ungod -- Syntax: %s [Player] -- Ungods the specified player.]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, player for i = 1,#players do playerId = players[i] local m_playerObj, playerObjId = getplayerobject(playerId) if m_playerObj then player = PlayerClass[playerId] if player.godmode then player.godmode = false sendresponse(getname(playerId) .. " is no longer in godmode", executorPlayerId) else sendresponse(getname(playerId) .. " is not in godmode", executorPlayerId) end else sendresponse(getname(playerId) .. " is dead", executorPlayerId) end end end } ) Commands.Create( "cheatunhax", { aliases = {"unhax"}, help = [[-- Cheat Unhax -- Syntax: %s [Player] -- Unhaxs the specified player.]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, m_player for i = 1,#players do playerId = players[i] m_player = getplayer(playerId) setscore(playerId, 0) writeshort(m_player + 0x9C, 0) writeshort(m_player + 0xA4, 0) writeshort(m_player + 0xAC, 0) writeshort(m_player + 0xAE, 0) writeshort(m_player + 0xB0, 0) sendresponse(getname(playerId) .. " has been unhaxed", executorPlayerId) end end } ) Commands.Create( "unhide", { aliases = {"removehide", "cheatunhide", "cheatunhideplayer"}, help = [[-- Unhide -- Syntax: %s [Player] -- Unhides the specified player.]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, player for i = 1,#players do playerId = players[i] player = PlayerClass[playerId] if player.hidden then cmdreply[cmdreply()] = getname(playerId) .. " is no longer hidden." player.hidden = false else cmdreply[cmdreply()] = getname(playerId) .. " was never hidden." end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "uninvis", { aliases = {"uncamo", "removeinvis", "removecamo", "cheatuncamoplayer", "cheatuninvis", "cheatremovecamo", "cheatuncamo", "cheatuncamoplayer"}, help = [[-- Uninvis -- Syntax: %s [Player] -- Removes camouflage from the specified player.]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, player for i = 1,#players do playerId = players[i] player = PlayerClass[playerId] if not player.invisible then cmdreply[cmdreply()] = getname(playerId) .. " is not invisible" else player.invisible = false cmdreply[cmdreply()] = getname(playerId) .. " is no longer invisible" end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "unmute", { aliases = {"removemute"}, help = [[-- Unmute -- Syntax: %s [Player] -- Unmutes the specified player. -- Will also unban their chat ban from the banlist]] }, { arguments = {"Player", minArgs = 1, maxArgs = 1}, func = function(executorPlayerId, players) local playerId, player, ban_entry for i = 1,#players do playerId = players[i] player = PlayerClass[playerId] if player.muted then player.muted = false -- remove them from the textbanlist ban_entry = findBanlistEntry(nil, gethash(playerId), getip(playerId), "chat") if ban_entry then sendresponse(getname(playerId) .. " has been unmuted", executorPlayerId) ban_entry.time = os.time() updateBanFiles() return end if player.spamcounter < 0 then sendresponse(getname(playerId) .. " has been forgiven for spamming.", executorPlayerId) player.spamcounter = 0 else sendresponse(getname(playerId) .. " is not found in any ban entries somehow???", executorPlayerId) end else sendresponse(getname(playerId) .. " has not been muted.", executorPlayerId) end end end } ) Commands.Create( "viewadmins", { aliases = {"curadmins", "adminscur"}, help = [[-- Viewadmins -- Syntax: %s -- Shows Current Admins in the Server]] }, { arguments = {minArgs = 0, maxArgs = 0}, func = function(executorPlayerId) sendresponse("The current admins in the server are listed below:", executorPlayerId) cmdreply.header = "[Level | Nickname | Name | Admin Type]" cmdreply.align = true cmdreply.delim = "|" local admin_entry for playerId = 0,15 do if getplayer(playerId) then admin_entry = PlayerClass[playerId].admin_entry if admin_entry then cmdreply[cmdreply()] = format("%s | %s | %s | %s", admin_entry.level, admin_entry.name, getname(playerId), (admin_entry.type == "ip" and "IP Admin" or "Hash Admin")) end end end sendresponse(cmdreply, executorPlayerId) end } ) Commands.Create( "votekickaction", { aliases = {"vkaction"}, help = [[-- Vote Kick Action -- Syntax: %s [Kick/Ban] -- Allows you to either ban or kick the player that has been voted out.]] }, { arguments = {"String", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, action) if not action then sendresponse("The current action for people who are votekicked is '" .. defaults.votekick_action .. "'", executorPlayerId) sendresponse("Valid actions are 'kick' and 'ban'", executorPlayerId) elseif action == "kick" or action == "ban" then sendresponse("The current VoteKick action has been changed to '" .. action .. "'", executorPlayerId) defaults.votekick_action = action else sendresponse("That is not a valid action", executorPlayerId) end end } ) Commands.Create( "votekicktimeout", { help = [[-- VoteKick Timeout -- Syntax: %s [Time] -- The amount of time between each votekick.]] }, { arguments = {"Time", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, time) if time == -1 then sendresponse("VoteKick Timeout is currently " .. timetoword(defaults.votekick_timeout), executorPlayerId) else sendresponse("VoteKick Timeout has been set to " .. timetoword(time), executorPlayerId) defaults.votekick_timeout = time end end } ) Commands.Create( "votekickrequired", { aliases = {"votekickneeded"}, help = [[-- Vote Kick Needed -- Syntax: %s [Percent] -- Allow you to change the number of votes needed for VoteKick to kick the player.]] }, { arguments = {"Percent", minArgs = 0, maxArgs = 1}, func = function(executorPlayerId, percent) if not percent then sendresponse(defaults.votekick_required .. "% votes required for VoteKick", executorPlayerId) else sendresponse("Votes required for VoteKick has been set to " .. percent .. "%", executorPlayerId) defaults.votekick_required = percent end end } ) function GetRequiredVersion() return 200 end function OnScriptLoad(process, game, persistent) -- Sort the commands so they're alphabetical when someone does /list or sv_commands table.sort(Commands, function(word1, word2) local myChar1, myChar2 local word1Len = #word1 local word2Len = #word2 local longestLen = word1Len >= word2Len and word1Len or word2Len local chartobyte = string.byte for i = 1,longestLen do myChar1 = i <= word1Len and chartobyte(sub(word1, i, i)) or 0 myChar2 = i <= word2Len and chartobyte(sub(word2, i, i)) or 0 if myChar1 < myChar2 then return true elseif myChar1 ~= myChar2 then return false end end return false end ) processid = process Persistent = persistent profilepath = getprofilepath() Game = game GetGameAddresses(game) if _SERVERAPP ~= "Sapp" then writeword(addresses.servername_patch, 0x9090) writeword(addresses.devmode_patch1, 0x9090) writeword(addresses.devmode_patch2, 0x9090) --writebyte(addresses.color_patch, 0xEB) end -- This bit of code fixes the stupidness that is sv_public. -- Usually if sv_public is disabled, no one can join the server (or weird things start happening) -- This bit of code will fix that. --[[local public_status = readdword(addresses.public_value_address) == 0x10101 if not public_status then writedword(addresses.public_value_address, 0x101) writestring(addresses.version_address, "01.23.45.6789") -- write a bad version string so it will never show in the lobby. (only if sv_public is false) end]] local file = io.open("changelog_" .. script_version .. ".txt") if file then changelog = true file:close() else WriteChangeLog() end registertimer(0, "turnAdminCheckOff") -- don't worry, this isn't malicious code, this simply removes all of halo's bans so I can override them with my system (it's much better, I promise) -- No bans will be deleted, anything in banned.txt will be formatted exactly the same as it was before. writedword(addresses.banlist_header, 0) -- writing the number of bans to 0 seems to remove all bans, sweet file = io.open(defaults.sharedhash_file .. ".txt") if file then local iter = 0 for line in file:lines() do if match(line, "%g%g%g+") then --reset our sharedhashes table and only load stuff in the sharedhashes file. if iter == 0 then -- only reset the table during the first iteration sharedhashes = {} end iter = iter + 1 sharedhashes[iter] = line end end file:close() if iter == 0 then file = io.open(defaults.sharedhash_file .. ".txt", "a") if file then for hash,index in next,sharedhashes do file:write(hash .. "\n") end end file:close() end else file = io.open(defaults.sharedhash_file .. ".txt", "w") if file then for hash,index in next,sharedhashes do file:write(hash .. "\n") end end file:close() end local args = defaults.remote_bansystem if not args or args.mode ~= 2 then loadBanFile(profilepath .. "ipbans.txt", "ip") -- load sapp ip bans loadBanFile(profilepath .. "ipbanlist.txt", "ip") -- load ipbanlist file for backwards compatibility loadBanFile(profilepath .. "iprangebanlist.txt", "ip") -- load iprangebanlist file for backwards compatibility loadBanFile(profilepath .. "textbanlist.txt", "chat") -- load textbanlist file for backwards compatibility loadBanFile(profilepath .. "namebans.txt", "name") -- load textbanlist file for backwards compatibility loadBanFile(profilepath .. defaults.banlist_file .. ".txt") updateBanFiles() -- we're not going to remove the files, let's just rename them so we don't upset anyone. local timestamp = os.date "%Y_%m_%d_%H_%M_%S" os.rename(profilepath .. "ipbans.txt", profilepath .. "old_ipbans_" .. timestamp .. ".txt") os.rename(profilepath .. "ipbanlist.txt", profilepath .. "old_ipbanlist_" .. timestamp .. ".txt") os.rename(profilepath .. "iprangebanlist.txt", profilepath .. "old_iprangebanlist_" .. timestamp .. ".txt") os.rename(profilepath .. "textbanlist.txt", profilepath .. "old_textbanlist_" .. timestamp .. ".txt") os.rename(profilepath .. "namebans.txt", profilepath .. "old_namebans_" .. timestamp .. ".txt") end loadAllAdminFiles() -- We can now archive the other admin files without worrying about losing the data. os.rename(profilepath .. "ipadmins.txt", profilepath .. "archived_ipadmins.txt") os.rename(profilepath .. "admin.txt", profilepath .. "archived_admin.txt") file = io.open(profilepath .. "access.ini") if file then local commands, lvlMatch, level, accessEntry, thisCommand, fullaccess local iter = 0 local allcommands = concat(Commands, ", ") for line in file:lines() do -- ignore blank lines if match(line, "%g%g%g+") then lvlMatch = tonumber(match(line, "%[([0-9]+)%]")) commands = match(line, "data=(.+)") commands = commands == "-1" and allcommands or commands fullaccess = commands == allcommands if iter % 2 == 0 and lvlMatch then level = lvlMatch elseif iter % 2 ~= 0 and commands then -- String full of commands this access level can execute. access_entry = {commands = commands, allcommands = fullaccess} -- We want to set each access_table[level][command] to equal the actual true name of the command (e.g. Display Admins List). -- Doing this will allow command aliases like sv_rcon_add, /rcon_add, add_rcon etc to work without using AccessMerging anymore (yuck) commands = tokenizestring(commands, ",") for i = 1,#commands do thisCommandName = getvalidformat(commands[i]) thisCommandEntry = Commands[thisCommandName] if not thisCommandEntry then thisCommandName = commands[i] thisCommandEntry = thisCommandName end commandIndex = #access_entry+1 access_entry[thisCommandEntry] = commandIndex access_entry[commandIndex] = thisCommandName end table.sort(access_entry, alphabetize) access_table[level] = access_entry else error(profilepath .. "access.ini is formatted incorrectly! Line: " .. line) end iter = iter + 1 end end file:close() end file = io.open(profilepath .. "data\\bos.data") if file then local name, hash, ip for line in file:lines() do name, hash, ip = match(line, "^(.-),(%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x+),(%g+)$") ip = validate_ipv4(ip) bos_table[#bos_table+1] = {name = name, hash = hash, ip = ip} end file:close() end file = io.open(profilepath .. "data\\locations.txt") if file then local map, locname, x, y, z for line in file:lines() do map,locname,x,y,z = match(line, "^(%g+),(%g+),([%d%.%-]+),([%d%.%-]+),([%d%.%-]+)") x,y,z = tonumber(x), tonumber(y), tonumber(z) if locname and x and y and z then locations[map] = locations[map] or {}--TM.New() locations[map][locname] = {x, y, z} end end file:close() end -- Load the remote banlist. local args = defaults.remote_bansystem if args then reloadRemoteBanlist() end local gameinfo_base = readdword(addresses.gameinfo_header) -- Code for script reload. -- If this script loads as a persistent script (in the persistent folder) this will sometimes be nil/0. if gameinfo_base and gameinfo_base ~= 0 then local gameinfo_time_passed = readdword(gameinfo_base + 0xC) -- Seems to not work when starting at 0. if gameinfo_time_passed >= 30 then gameend = false Map = readstring(addresses.map_name_address2) locations[Map] = locations[Map] or {} team_play = readbyte(addresses.gametype_base + 0x34) == 1 gametype = readbyte(addresses.gametype_base + 0x30) starting_equipment = readbit(addresses.gametype_base + 0x38, 2) and "Generic" or "Custom" LoadTags() for playerId = 0,15 do if not getplayer(playerId) then goto continue end -- Increase our total player counter. cur_players = cur_players + 1 -- Add player in the script's tables. PlayerClass:Initialize(playerId) -- Remove the player from the server if they are on the banlist. punishIfOnBanlist(playerId) ::continue:: end end end -- override slayer's score system by setting the scorelimit to a high number and swapping the map in onplayerkill. if gametype == 2 then team_scores[0] = getteamscore(0) team_scores[1] = getteamscore(1) --writebyte(addresses.slayer_score_patch, 0xEB) -- how tf do i set slayer scorelimit: figured it out writebyte(addresses.gametype_base + 0x58, score) end hprintf "-------------------------------------------------------------------------------" hprintf(" >> Command Script Version: " .. script_version .. " <<") if not changelog then hprintf(" >> [!] Change log Version " .. script_version .. " is being written [!] <<") end hprintf " >> Credit: Creator Wizard, Updater Aelite_Prime <<" hprintf " >> Xfire: th3w1zard3 <<" hprintf " >> Support: http://phasor.proboards.com/ <<" hprintf "-------------------------------------------------------------------------------" file = io.open("temp_" .. processid .. ".tmp") or io.open "defaults.txt" local temp_commands_executed = {} --TM.New() local words -- if gameinfo_base is nil, then this script is being loaded from the persistent folder, so we don't need to do anything (loading from the init now :D) if gameinfo_base and file then for line in file:lines() do if match(line, "[%w_]+%s+[%w%p]+") then -- used to call svcmd but I hate it using halo's servercommand call -- no need when I only want it to execute scripted commands anyway. OnServerCommand(nil, line) end words = tokenizecmdstring(line) temp_commands_executed[#temp_commands_executed+1] = words[1] end file:close() if filename == "temp_" .. processid .. ".tmp" then os.remove(filename) end elseif file then file:close() else file = io.open("defaults.txt", "a") hprintf " >> Defaults.txt not found. File will be created..." for command,value in next,defaults do file:write("sv_" .. command .. " " .. tostring(value) .. "\n") end file:close() end maintimer = registertimer(33, "MainTimer") collectgarbage() end function turnAdminCheckOff(id, count) halo_svcmd "sv_admin_check false" -- stupid phasor :( -- Load Maplist and Gamelist. --[[local gmatch = string.gmatch for map in gmatch(concat(halo_svcmd("sv_maplist", true)), "%w+") do valid_maps[map] = true end for gametype in gmatch(concat(halo_svcmd("sv_gamelist", true)), "%w+") do valid_gametypes[gametype] = true end--]] return false end function OnScriptUnload() if defaults.remotecontrol then for i = 1,#clients do clients[i].socket:close() end server:close() server = nil end local writetbl = {}--TM.New() local file = assert(io.open(profilepath .. "data\\bos.data", "w")) local bos_entry for id = 1,#bos_table do bos_entry = bos_table[id] writetbl[#writetbl+1] = bos_entry.name .. "," .. bos_entry.hash .. "," .. bos_entry.ip end file:write(concat(writetbl, "\n")) file:close() -- Continue to write these onscriptunload because they aren't as important as admins/bans and they're written to a lot more. --[[file = assert(io.open(profilepath .. "uniques.txt", "w")) start = #writetbl+1 for k,unique_entry in next,unique_table do if k ~= "total" then writetbl[#writetbl+1] = k .. "," .. unique_entry.joincount .. "," .. concat(unique_entry.names, ",") end end writetbl[#writetbl+1] = unique_table.total file:write(concat(writetbl, "\n", start)) file:close()--]] -- Write all script game variables to temp file file = assert(io.open("temp_" .. processid .. ".tmp", "w")) start = #writetbl+1 for command,value in next,defaults do if command == "remote_bansystem" and type(value) == "table" then writetbl[#writetbl+1] = command .. " " .. value.host .. " " .. value.phpscript .. " " .. value.banfile .. " " .. value.mode .. " " .. value.port else writetbl[#writetbl+1] = command .. " " .. tostring(value) end end for rcon,level in next,rcon_passwords do writetbl[#writetbl+1] = "sv_rcon_add " .. rcon .. " " .. level end file:write(concat(writetbl, "\n", start)) file:close() if gametype == 2 then --writebyte(addresses.slayer_score_patch, 0x74) -- how tf do i set slayer scorelimit: figured it out writebyte(addresses.gametype_base + 0x58, score) end -- Clean up drones. for playerId = 0,15 do if getplayer(playerId) then cleanupdrones(playerId) end end end local NameRequestName function OnNameRequest(hash, name) -- No commas allowed in the name (it's our delimiter for the banlist and admin file.) local count name, count = gsub(name, ",", "") NameRequestName = tostring(name) if findBanlistEntry(name, nil, nil, "name") then hprintf(name .. " joined with a banned name, using random name.") return false end if count and count >= 1 then return false, name end end -- brief Called when a hash is validated by gamespy -- param hash: The hash that was checked -- param status: Result of the check (1 = valid, 2 = invalid, 3 = valid hash but invalid challenge) -- Status 2 indicates that somebody is trying to spoof a player's hash -- (i.e. pretend to be them). The player is immediately kicked after calling this function. function OnHashValidation(hash, status) hprintf("Hash: " .. tostring(hash) .. " Status: " .. tostring(status)) --[[if status == 2 then WriteLog(profilepath .. "logs\\SecurityIssues.log", hash .. " attempted to spoof, status 2") end--]] end local isMuted function OnBanCheck(hash, ip) hprintf(NameRequestName .. " (Hash: " .. tostring(hash) .. " IP: " .. tostring(ip) .. ") is attempting to join the server") -- Do not let anyone with hacked hashes (they did some serious hacking and memory modding to change it to something like 'myfakehashlolz') into the game ever. if not match(hash, "%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x+") then return false end -- Check if they are on boslist. local bos_entry for i = 1,#bos_table do bos_entry = bos_table[i] if netMatch(bos_entry.ip, ip) then privateSayAdmins(bos_entry.name .. " banned from BoS.\nEntry: " .. bos_entry.name .. "- " .. bos_entry.ip) hprintf(bos_entry.name .. " banned from BoS.\nEntry: " .. bos_entry.name .. "- " .. bos_entry.ip) WriteLog(profilepath .. "logs\\" .. defaults.kickbans_file .. ".log", bos_entry.name .. " was Banned on Sight") addBan(bos_entry.name, nil, ip, -1, "ip", "Ban on Sight") return false end end -- Check if they are on banlist. local ban_entry = findBanlistEntry(nil, hash, ip) if ban_entry then hprintf(NameRequestName .. " (Hash: " .. hash .. " IP: " .. ip .. ") has been rejected because they were found on the " .. ban_entry.type .. " banlist with index '" .. ( ban_entry.name .. ":" .. (ban_entry.hash or "") .. ":" .. (ban_entry.ip or "") ) .. "'") if ban_entry.type == "chat" then isMuted = true else return false end end end function OnPlayerJoin(playerId) local player = PlayerClass:Initialize(playerId) -- write the team colors to the player (required since we are using the color patch) if team_play then --writeword(getplayer(playerId) + 0x60, getteam(playerId)+2) elseif readword(getplayer(playerId) + 0x60) == 10 and sub(gethash(playerId), 1, 5) ~= "56d5f" --[[forjessasblack-or readword(getplayer(playerId) + 0x60) == 1 and sub(gethash(playerId), 1, 5) ~= "c68bd"--]] or readword(getplayer(playerId) + 0x60) == 12 and sub(gethash(playerId), 1, 5) ~= "abd5c" then writeword(getplayer(playerId) + 0x60, 13) end cur_players = cur_players + 1 local name = getname(playerId) local hash = gethash(playerId) local ip = getip(playerId) local iprange = match(ip, "^%d+%.%d+%.%d+") player.muted = player.muted or not not isMuted isMuted = nil if player.suspended then kill(playerId) writeshort(getplayer(playerId) + 0x2C, tonumber(player.suspended) or 3000) end if defaults.uniques_enabled then if unique_table[hash] or unique_table[ip] or unique_table[iprange] then if defaults.wb_message then privatesay(playerId, "Welcome back " .. name .. "") end unique_table[hash] = unique_table[hash] or {}--TM.New() unique_table[hash].joincount = (unique_table[hash].joincount or 0) + 1 unique_table[ip] = unique_table[ip] or {}--TM.New() unique_table[ip].joincount = (unique_table[ip].joincount or 0) + 1 unique_table[iprange] = unique_table[iprange] or {}--TM.New() unique_table[iprange].joincount = (unique_table[iprange].joincount or 0) + 1 else unique_table[hash] = {joincount = 1, names = {name}} unique_table[ip] = {joincount = 1, names = {name}} unique_table[iprange] = {joincount = 1, names = {name}} unique_table.total = unique_table.total + 1 if defaults.firstjoin_message then say("This is " .. name .. "'s first time in the server unique player #: " .. unique_table.total) end end end if defaults.sa_message then if PlayerClass[playerId].admin_entry then hprintf("Server Admin: " .. name) Say("Server Admin: " .. name) end end if defaults.multiteam_vehicles then writebyte(getplayer(playerId) + 0x20, 0) end hprintf(name .. " has joined the game") end function OnPlayerLeave(playerId) cleanupdrones(playerId) cur_players = cur_players - 1 local name = getname(playerId) local player = PlayerClass[playerId] local ip = player.ip player.playerId = -1 if not gameend and player.tempadmin then player.tempadmin = false end if votekickPlayerId == playerId then votekicktimer = nil votekickPlayerId = nil votekick_counter = -defaults.votekick_timeout for playerId = 0,15 do if getplayer(playerId) then PlayerClass[playerId].used_votekick = false end end say "Votekick ending because votekicked player left the server!" end ResetPlayer(playerId) local left_entry = {}--TM.New() left_entry.name = name left_entry.hash = gethash(playerId) left_entry.ip = ip leave_table[resolveplayer(playerId)] = left_entry hprintf(name .. " is leaving the game") PlayerClass[playerId].player_struct = false end function OnTeamChange(playerId, old_team, new_team, relevant) if team_play then --say(tostring(getname(playerId)) .. " swapping from " .. tostring(old_team) .. " to " .. tostring(new_team)) --[[writeword(getplayer(playerId) + 0x60, new_team+2) PlayerClass[playerId].changing_teams = true--]] end end function destroyPlayer(id, count, playerId) local player = PlayerClass[playerId] local playerObjId = getplayerobjectid(playerId) if getobject(playerObjId) then --say("Destroying " .. tostring(getname(playerId))) destroyobject(playerObjId) --say("Done! Player " .. tostring(getname(playerId)) .. " is now " .. readword(getplayer(playerId) + 0x60)) end player.changing_teams = false return false end function OnPlayerSpawn(playerId, playerObjId) local player = PlayerClass[playerId] if player.changing_teams then --say(getname(playerId) .. " is changing teams") registertimer(100, "destroyPlayer", playerId) return end if defaults.noweapons or player.disarmed then local m_weapon, weaponObjId for slot = 0,3 do m_weapon, weaponObjId = getplayerweapon(playerId, slot) if m_weapon then destroyobject(weaponObjId) end end end if defaults.multiteam_vehicles then writebyte(player.player_struct + 0x20, 0) end if player.colorspawn then movobjectcoords(playerObjId, player.x, player.y, player.z) player.colorspawn = false end player.suspended = false player.ghostmode = false --writebit(m_playerObj + 0x10, 0, 1) -- both for ghostmode --writebit(m_playerObj + 0x10, 24, 0) -- default spawn weapons code: if next(spawnWeapons) then if starting_equipment == "Generic" then -- check if we still need to assign leftover weapons to players (tertiary and quartenary weapons) if spawnWeapons[3] then -- assign the leftover weapons to the player registertimer(0, "AssignLeftoverWeapons", playerId) end elseif starting_equipment == "Custom" then -- assign the correct weapons to the player registertimer(0, "AssignWeapons", playerId) end end end local mode = 1 -- screw you phasor function OnNewGame(map) if Persistent then rtv_counter = 0 for _,entry in next,PlayerClass do if type(entry) ~= "function" then entry.rtv_rocked = false end end end Map = map locations[map] = locations[map] or {} gameend = false gametype = readbyte(addresses.gametype_base + 0x30) team_play = readbyte(addresses.gametype_base + 0x34) == 1 scorelimit = getscorelimit() starting_equipment = readbit(addresses.gametype_base + 0x38, 2) and "Generic" or "Custom" -- Turn MTV Off if team_play then defaults.multiteam_vehicles = false end LoadTags() mode = 1 if gametype == 2 then --writebyte(addresses.slayer_score_patch, 0xEB) -- how tf do i set slayer scorelimit: figured it out writebyte(addresses.gametype_base + 0x58, score) end local args = defaults.remote_bansystem if args then reloadRemoteBanlist() end collectgarbage() end function OnGameEnd(mode_that_sometimes_lies) if mode == 1 then gameend = true collectgarbage() if gametype == 2 then team_scores[0] = 0 team_scores[1] = 0 for i = 0,15 do player_scores[i] = 0 end --writebyte(addresses.slayer_score_patch, 0x74) -- how tf do i set slayer scorelimit: figured it out writebyte(addresses.gametype_base + 0x58, score) end team_play_temp = nil end mode = mode + 1 end local function votekick() say("Removing " .. getname(votekickPlayerId) .. " from the server") if defaults.votekick_action == "ban" then svcmd("sv_ban " .. resolveplayer(votekickPlayerId) .. " 5m Votekicked with " .. votekick_counter .. " votes") else svcmd("sv_kick " .. resolveplayer(votekickPlayerId) .. " Votekicked with " .. votekick_counter .. " votes") end votekickPlayerId = nil if votekicktimer then removetimer(votekicktimer) votekicktimer = nil end votekick_counter = -defaults.votekick_timeout end function OnServerChat(playerId, chattype, message) local AllowChat, found, receiverPlayer if chattype == 4 then -- don't do anything if the server is private messaging someone. local msg = gsub(message, "**SERVER**", "\n**SERVER TO " .. getname(playerId) .. "**") hprintf(msg) if server_prefix then return true, gsub(message, "**SERVER**", server_prefix) end return nil elseif not playerId then -- do nothing here if the server is globally talking to everyone. hprintf("\n" .. message) if server_prefix then return true, gsub(message, "**SERVER**", server_prefix) end return nil end local name, hash, ip = getname(playerId), gethash(playerId), getip(playerId) local player = PlayerClass[playerId] if player.muted or player.spamcounter < 0 then return false end local t = tokenizecmdstring(message) local count = #t local cmd = t[1] if cmd == "rtv" or cmd == "skip" then if count ~= 1 then goto endchat end AllowChat = false if not defaults.rtv_enabled then privatesay(playerId, "Rockthevote is disabled.") goto endchat end if rtv_counter < 0 then privatesay(playerId, "You cannot initiate rtv at this time") goto endchat end local total_votes_required = round(cur_players * defaults.rtv_required * 0.01) if player.rtv_rocked then privatesay(playerId, "You have already voted for rtv") goto endchat end rtv_counter = rtv_counter + 1 if rtv_counter == 1 then say(name .. " has initiated rtv") say('Type "rtv" to join the vote') rtvtimer = registertimer(defaults.rtv_timeout * 1000, "rtvTimer") else say(name .. " has voted for rtv") end say(rtv_counter .. " of " .. total_votes_required .. " votes required for rtv") player.rtv_rocked = true if rtv_counter >= total_votes_required then if rtvtimer then removetimer(rtvtimer) rtvtimer = nil end rtv_counter = -defaults.rtv_timeout say("Enough votes for rtv, game is now ending...") halo_svcmd "sv_map_next" end elseif cmd == "votekick" then if count ~= 2 then goto endchat end AllowChat = false if not defaults.votekick_enabled then privatesay(playerId, "Votekick is disabled") goto endchat end if player.used_votekick then privatesay(playerId, "You have already voted for a votekick!") goto endchat end if votekick_counter < 0 then privatesay(playerId, "Votekick will be available in " .. -votekick_counter .. " seconds") goto endchat elseif votekick_counter > 0 then privatesay(playerId, "There is already a votekick in progress.") goto endchat end local players = getvalidplayers(t[2]) if not players then privatesay(playerId, "Invalid Player!") goto endchat end if players[2] then privatesay(playerId, "You can only votekick one player at a time!") goto endchat end receiverPlayer = players[1] if playerId == receiverPlayer then privatesay(playerId, "You cannot votekick yourself noob.") goto endchat end if PlayerClass[receiverPlayer].admin_entry then privatesay(playerId, "Admins cannot be votekicked") goto endchat end local total_votes_required = round(cur_players*(defaults.votekick_required * 0.01)) votekickPlayerId = receiverPlayer player.used_votekick = true votekick_counter = votekick_counter + 1 say(name .. ' has initiated a votekick on ' .. getname(receiverPlayer) .. '\n Type "kick" to join the vote\n 1 of ' .. total_votes_required .. ' votes required to kick') if votekick_counter >= total_votes_required then votekick() end elseif cmd == "kick" then if count ~= 1 then goto endchat end AllowChat = false if not defaults.votekick_enabled then privatesay(playerId, "Votekick is disabled") goto endchat end if player.used_votekick then privatesay(playerId, "You have already voted for a votekick!") goto endchat end if votekick_counter <= 0 then privatesay(playerId, "There is no votekick in progress. Use 'votekick (playerIndex)' to start one!") goto endchat end if playerId == votekickPlayerId then privatesay(playerId, "You cannot vote for yourself to be kicked noob") goto endchat end local total_votes_required = round(cur_players*(defaults.votekick_required*0.01)) player.used_votekick = true votekick_counter = votekick_counter + 1 say(name .. " has voted to kick " .. getname(votekickPlayerId)) say(votekick_counter .. " of " .. total_votes_required .. " votes required to kick") if votekick_counter >= total_votes_required then votekick() end end receiverPlayer = match(cmd, "^@(%g+)$") if defaults.pm_enabled and receiverPlayer then AllowChat = false local players = getvalidplayers(receiverPlayer, playerId) if not players then privatesay(playerId, "There is no player identified as '" .. receiverPlayer .. "'") goto endchat end if #players > 4 then privatesay(playerId, "You cannot privatemessage more than 4 people at once!") goto endchat end local privatemessage = concat(t, " ", 2, #t) local names = {}--TM.New() for i = 1,#players do receiverPlayer = players[i] if playerId == receiverPlayer then goto nextPlayer end names[i] = getname(receiverPlayer) .. " (" .. resolveplayer(receiverPlayer) .. ")" sendconsoletext(receiverPlayer, getname(playerId) .. ": (" .. resolveplayer(playerId) .. ") " .. privatemessage) ::nextPlayer:: end sendconsoletext(playerId, "PM to " .. concat(names, ", ") .. " " .. privatemessage) end if sub(cmd, 1, 1) == "/" then output_environment = 2 found = true AllowChat = _SERVERAPP == "Phasor" or not not say(name .. ": " .. message, false) -- sapp will execute the command a second time if this isn't here. I still like this environment showing up in the chat. elseif sub(cmd, 1, 1) == "\\" then output_environment = 3 found = true AllowChat = false end if found then if defaults.chatcommands then if cmd == "/" or cmd == "\\" then sendresponse("Invalid Command", playerId) elseif cmd == "/e" or cmd == "\\e" then cmd = concat(t, " ", 2) sendresponse("Executed " .. cmd, playerId) sendresponse(svcmdplayer(cmd, playerId, true), playerId) --[[elseif cmd == "/l" or cmd == "/login" then remove(t, 1) -- command is not an argument Commands[cmd](t, cmd, playerId)--]] else sendresponse(svcmdplayer(message, playerId, true), playerId) end else privatesay(playerId, "Chat commands are currently disabled.") end end ::endchat:: if AllowChat ~= false and defaults.spam_max > 0 and (defaults.antispam == "all" or defaults.antispam == "players" and not getaccess(playerId)) then player.spamcounter = player.spamcounter + 1 end -- Print a message to the console of the chat. hprintf("\nOnServerChat(" .. playerId .. ", " .. tostring(chattype) .. ") " .. getname(playerId) .. ": (" .. resolveplayer(playerId) .. ") " .. message) if AllowChat ~= false then if defaults.anticaps then if defaults.chatids then return true, " (" .. resolveplayer(playerId) .. ") " .. lower(message) end return true, lower(message) elseif defaults.chatids then return true, " (" .. resolveplayer(playerId) .. ") " .. message end end return AllowChat end function rtvTimer(id, count) if rtv_counter > 0 then rtv_counter = -defaults.rtv_timeout for playerId = 0,15 do if getplayer(playerId) then PlayerClass[playerId].rtv_rocked = false end end say "The current rtv has expired" end return false end function rconBruteForceTimeout(id, count, player) if player.rcon_fails == 0 then player.rconfail_timer = -1 return false end player.rcon_fails = player.rcon_fails - 1 return true end local command_attempt -- this function is horrendously named, would you believe it's only SUPPOSED to be called when BAD rcon passwords are given? function OnServerCommandAttempt(playerId, command, password) local t = tokenizecmdstring(command) local cmd = getvalidformat(t[1]) -- EVEN IF the server is executing a command, we don't want it executing commands during scrimmode. if defaults.scrim_mode then -- Format our command. if not Commands[cmd].scrim then sendresponse("This command is currently disabled.\nTurn Scrim mode off to reenable this command.", playerId) cmdlog(getname(playerId) .. " attempted to use " .. cmd .. " during scrim mode.") return false end end -- Do nothing if the server is executing a command if not playerId then return nil end -- If the player has gotten the password wrong too many times, register our brute force timer local player = PlayerClass[playerId] if player.rcon_fails >= 10 then if player.rconfail_timer ~= -1 then player.rcon_fails = player.rcon_fails + 1 else player.rconfail_timer = registertimer(1000, "rconBruteForceTimeout", player) end return false end if password then output_environment = 1 end -- We now have several cases here. -- If there are no admins, anyone can use the generic rcon -- If there are admins, then only admins can use the generic rcon -- If there is no generic rcon (sv_rcon_password set to "any"), admins can use any rcon password they want. -- If there is no password given, it is a chatcommand and we need to check their access. -- Everyone can use global rcons (in the rcon_passwords table). local permission = false local access -- Check out global passwords (sv_rcon_add) local level = password and rcon_passwords[password] if level then permission = checkaccess(cmd, level) else access = getaccess(playerId) local generic_rcon = readstring(addresses.network_server_globals + 0x128) -- If there are no admins on the server, and the rcon was correct, allow the command if not next(admin_table) and generic_rcon == password then permission = true -- If the player has admin access, then allow the command IF a password was not provided (chat command), sv_rcon_password is set to 'any' (allow all rcon passwords), or check if the rcon matches the rcon password. elseif access and (not password or generic_rcon == "any" or generic_rcon == password) then permission = checkaccess(cmd, access) end end if permission == false then local admin_entry = PlayerClass[playerId].admin_entry local admin_name = admin_entry and admin_entry.name or "N/A" if level then cmdlog(" >>Security Alert: " .. getname(playerId) .. " (Nickname: " .. admin_name .. " Hash:" .. gethash(playerId) .. " IP: " .. getip(playerId) .. ") tried to execute: '" .. command .. "'") sendresponse("This Rcon does not have access to that command. This will be reported.", playerId) elseif password and output_environment <= 1 then if not access then cmdlog(getname(playerId) .. " (Nickname: " .. admin_name .. " Hash:" .. gethash(playerId) .. " IP: " .. getip(playerId) .. ") tried to use '" .. password .. "' as an rcon password") sendresponse("You are not an admin. This will be reported", playerId) goto ReturnPermission elseif password ~= generic_rcon then cmdlog(getname(playerId) .. " (Nickname: " .. admin_name .. " Hash:" .. gethash(playerId) .. " IP: " .. getip(playerId) .. ") tried to use '" .. password .. "' as an rcon password") sendresponse("That is not an rcon password", playerId) else cmdlog(getname(playerId) .. " (Nickname: " .. admin_name .. " Hash:" .. gethash(playerId) .. " IP: " .. getip(playerId) .. ") tried to execute: '" .. command .. "'") sendresponse("You cannot execute this command.", playerId) end else cmdlog(getname(playerId) .. " (Nickname: " .. admin_name .. " Hash:" .. gethash(playerId) .. " IP: " .. getip(playerId) .. ") tried to execute: '" .. command .. "'") sendresponse("You cannot execute this command.", playerId) goto ReturnPermission end player.rcon_fails = player.rcon_fails + 1 else command_attempt = true player.rcon_fails = 0 end ::ReturnPermission:: return permission end function OnServerCommand(playerId, command) -- prevents rare issues that happen when init files execute blank commands if not match(command, "%w+") then return nil end -- this is to prevent infinite loops from when I want to execute a halo command -- without creating infinite loops (continually calling my sv_unban which will then continually call this etc) if dont_call_onservercommand then return nil end -- this means that a valid password was given so oncommandattempt was never actually called. -- It also means the command came using the console, and not the chat if not command_attempt then if OnServerCommandAttempt(playerId, command, readstring(addresses.network_server_globals + 0x128)) == false then return false elseif playerId then output_environment = 1 end command_attempt = nil else command_attempt = nil end local response, thisCommand local t = tokenizecmdstring(command) local count = #t -- Format our command. local cmd = getvalidformat(t[1]) if cmd == "help" or cmd == "gethelp" then response = false t[2] = concat(t, "", 2) thisCommand = Commands[getvalidformat(t[2])] if thisCommand and thisCommand.info.help then sendresponse(gsub(thisCommand.info.help, "%%s", t[2]), playerId) else sendresponse("No help topics for command '" .. tostring(t[2]) .. "'", playerId) end else -- this is a bit hacky, but I've made hackier stuff before, plus this will always work :D -- Code for commands with spaces in it. local tempCmd = cmd local i = 2 while i <= count do tempCmd = tempCmd .. gsub(t[i], "_", "") thisCommand = Commands[tempCmd] if thisCommand then t[1] = tempCmd for j = 2,i do remove(t, 2) end break end i = i + 1 end thisCommand = Commands[getvalidformat(t[1])] -- First possibility: a command gets truncated in a valid format, and this function recognizes it as a script command if thisCommand then response = false local origCommand = t[1] remove(t, 1) -- the command isn't an argument. thisCommand:Execute(t, origCommand, playerId) -- this means it is NOT one of my scripted commands. else local message local newcmd = command if not match(newcmd, "script_reload") and not match(newcmd, "script_unload " .. sub(debug.getinfo(1, "S").source, 2, -5)) then if sub(newcmd, 1, 1) == "/" or sub(newcmd, 1, 1) == "\\" then -- print("1st CHECK") newcmd = sub(newcmd, 2) message = halo_svcmd(newcmd, true) end -- Second Possibility: the command might need an sv_, or might need the sv_ removed. if type(message) ~= "table" or type(message[1]) ~= "string" or find(concat(message), "Requested function \"") then --print("2nd check") -- Add the sv_ if sub(newcmd, 1, 3) ~= "sv_" then --print("3rd CHECK") message = halo_svcmd("sv_" .. newcmd, true) -- Remove the sv_ else message = halo_svcmd(sub(newcmd, 4), true) end end if type(message) ~= "table" or type(message[1]) ~= "string" or find(concat(message), "Requested function \"") then --sendresponse('Command "' .. t[1] .. '" not found.', playerId) -- Send back the message from the non-scripted command. else sendresponse(message, playerId) end end end end if playerId and response == false then cmdlog(format("%s (Nickname: %s Hash: %s IP: %s) has executed: %s", getname(playerId), (PlayerClass[playerId].admin_entry and PlayerClass[playerId].admin_entry.name or "N/A"), gethash(playerId), getip(playerId), command)) end return response end local function sendKillingSpreeMessages(killerPlayerId, victimPlayerId) local m_kplayer = getplayer(killerPlayerId) local kname = getname(killerPlayerId) local multikill = readword(m_kplayer + 0x98) if multikill == 2 then sendconsoletext(killerPlayerId, "Double Kill") elseif multikill == 3 then sendconsoletext(killerPlayerId, "Triple Kill") elseif multikill == 4 then sendconsoletext(killerPlayerId, "OverKill") elseif multikill == 5 then sendconsoletext(killerPlayerId, "Killtacular") elseif multikill == 6 then sendconsoletext(killerPlayerId, "Killtrocity") elseif multikill == 7 then sendconsoletext(killerPlayerId, "Killimanjaro") elseif multikill == 8 then sendconsoletext(killerPlayerId, "Killtastrophe") elseif multikill == 9 then sendconsoletext(killerPlayerId, "Killpocalypse") elseif multikill >= 10 then sendconsoletext(killerPlayerId, "Killionaire") end local spree = readword(m_kplayer + 0x96) if spree >= 40 and spree%2 == 0 then Say("OMFGWTFBBQWAFFLES " .. kname .. " is Unfrigginbelievable with " .. spree .. " kills!", 1, playerId) sendconsoletext(killerPlayerId, "OMFGWTFBBQWAFFLES Unfrigginbelievable") elseif spree >= 35 and spree < 40 then Say(kname .. " is Inconceivable with " .. spree .. " kills!", 1, playerId) sendconsoletext(killerPlayerId, "Inconceivable") elseif spree >= 30 then Say(kname .. " is Invincible with " .. spree .. " kills!", 1, playerId) sendconsoletext(killerPlayerId, "Invincible") elseif spree >= 25 then Say(kname .. " is Untouchable with " .. spree .. " kills!", 1, playerId) sendconsoletext(killerPlayerId, "Untouchable") elseif spree >= 20 then Say(kname .. " is on a Rampage with " .. spree .. " kills!", 1, playerId) sendconsoletext(killerPlayerId, "Rampage") elseif spree >= 15 then Say(kname .. " is on a Running Riot with " .. spree .. " kills!", 1, playerId) sendconsoletext(killerPlayerId, "Running Riot") elseif spree >= 10 then Say(kname .. " is on a Killing Frenzy with " .. spree .. " kills!", 1, playerId) sendconsoletext(killerPlayerId, "Killing Frenzy") elseif spree >= 5 then Say(kname .. " is on a Killing Spree with " .. spree .. " kills!", 1, playerId) sendconsoletext(killerPlayerId, "Killing Spree") end local m_vplayer = getplayer(victimPlayerId) local victim_spree = readword(m_vplayer + 0x96) if victim_spree >= 5 then Say(kname .. " just ended " .. getname(victimPlayerId) .. "'s killing spree of " .. victim_spree .. "!") end end function OnPlayerKill(killerPlayerId, victimPlayerId, mode) if mode == 6 then hprintf(getname(victimPlayerId) .. " has committed suicide!") elseif mode == 0 or mode >= 4 then hprintf(getname(victimPlayerId) .. " was killed by " .. getname(killerPlayerId)) elseif mode == 1 then hprintf(getname(victimPlayerId) .. " fell off a high place") elseif mode == 2 then hprintf(getname(victimPlayerId) .. " was killed by the Guardians") elseif mode == 3 then hprintf(getname(victimPlayerId) .. " was rolled over by a vehicle") end cleanupdrones(victimPlayerId) local victim = PlayerClass[victimPlayerId] local killer = PlayerClass[killerPlayerId] victim.godmode = false if defaults.respawn_time then writedword(getplayer(victimPlayerId) + 0x2C, defaults.respawn_time * 30) end if mode == 4 then -- Score monitoring. if gametype == 2 then local score = player_scores[killerPlayerId] player_scores[killerPlayerId] = score + 1 if team_play then team_scores[getteam(killerPlayerId)] = team_scores[getteam(killerPlayerId)] + 1 score = team_scores[getteam(killerPlayerId)] end --say("Score: " .. tostring(score) .. "Team Score: " .. tostring(team_scores[getteam(killerPlayerId)]) .. " Scorelimit: " .. tostring(scorelimit)) if score >= scorelimit then -- check if the scorelimit has been reached. halo_svcmd("sv_map_next") end end if defaults.killing_spree then sendKillingSpreeMessages(killerPlayerId, victimPlayerId) end end if defaults.tbag_detection then killer.tbagname = getname(victimPlayerId) killer.tbagcount = 0 victim.tbagcount = 0 victim.x, victim.y, victim.z = getobjectcoords(getplayerobjectid(victimPlayerId)) end end function playerWeaponCheckTimer(id, count) for playerId = 0,15 do if not getplayer(playerId) then goto continue end local m_playerObj, playerObjId = getplayerobject(playerId) if not m_playerObj then goto continue end local pweaptable = PlayerClass[playerId].weapons local m_weaponObj, weaponObjId for slot = 0,3 do weaponObjId = readdword(m_playerObj + 0x2F8+(slot-1)*4) m_weaponObj = getobject(weaponObjId) if m_weaponObj and weaponObjId ~= pweaptable[slot] then writeshort(m_weaponObj + 0x2B6, 0x7CFF) writeshort(m_weaponObj + 0x2B8, 0x7CFF) updateammo(weaponObjId) pweaptable[slot] = weaponObjId end end ::continue:: end return true end function OnClientUpdate(playerId) if not defaults.tbag_detection then return end local player = PlayerClass[playerId] if player.tbagname == "" then return end local playerObjId = getplayerobjectid(playerId) local m_playerObj = getobject(playerObjId) if not m_playerObj then return end local crouching = readbyte(m_playerObj + 0x2A0) == 3 if not player.crouch and crouching then player.tbagcount = (player.tbagcount or 0) + 1 if player.tbagcount == 4 then player.tbagcount = 0 say(getname(playerId) .. " is T-Bagging " .. player.tbagname) player.tbagname = "" end player.crouch = true elseif player.crouch and not crouching then player.crouch = false end end function OnObjectInteraction(playerId, objectId, mapId) if defaults.noweapons or PlayerClass[playerId].disarmed then if getObjType(objectId) == 2 then return false end end return nil -- gotta return a value end local object_types = { [0] = "Biped", "Vehicle", "Weapon", "Equipment", "Garbage", "Projectile", "Scenery", "Machine", "Control", "Light Fixture", "Placeholder", "Sound Scenery" } function OnDamageApplication(receiverObjId, causerObjId, tagId, hit, backtap) if not getobject(causerObjId) then return end local playerId = objectidtoplayer(causerObjId) if not playerId then return end local player = PlayerClass[playerId] if player.bulletmode == "destroy" then destroyobject(receiverObjId) elseif player.bulletmode == "entergun" then local m_receiverObj = getobject(receiverObjId) if not m_receiverObj then return end local objtype = readword(m_receiverObj + 0xB4) if objtype == 1 then -- check if object is a vehicle entervehicle(playerId, receiverObjId, 0) end elseif player.bulletmode == "debuggun" then local m_receiverObj = getobject(receiverObjId) if not m_receiverObj then return end end end function OnDamageLookup(receiverObjId, causerObjId, mapId, tagdata) local receivingPlayerId = objectidtoplayer(receiverObjId) if not defaults.falldamage and (mapId == gettag("jpt!", "globals\\falling") or mapId == gettag("jpt!", "globals\\distance")) then odl_multiplier(0.01) elseif defaults.deathless or (receivingPlayerId and PlayerClass[receivingPlayerId].godmode) then odl_multiplier(0.00000000000000000000000000000000000000001) local dmg_side_effect = readword(tagdata + 0x1C4) if dmg_side_effect == 2 or dmg_side_effect == 3 then writeword(tagdata + 0x1C4, 0) registertimer(0, "DamageAddressReset", {tagdata, 0x1C4, dmg_side_effect}) -- new phasor doesn't automatically reset tagdata anymore. end elseif getobject(causerObjId) and receivingPlayerId then --say("2APPLYING DAMAGE TO: " .. tostring(getname(receivingPlayerId))) -- make sure firefister doesn't take fire damage local dmg_damage_category = readword(tagdata + 0x1C6) if dmg_damage_category == 7 then --say("2FLAME DAMAGE BEING APPLIED TO: " .. tostring(getname(receivingPlayerId))) if PlayerClass[receivingPlayerId].firefist then --say("2SETTING 0 DAMAGE") odl_multiplier(0) end end local causingPlayerId = objectidtoplayer(causerObjId) local m_causingPlayer, m_receivingPlayer = getplayer(causingPlayerId), getplayer(receivingPlayerId) if not m_receivingPlayer or not m_causingPlayer or causingPlayerId == receivingPlayerId then return end local player = PlayerClass[causingPlayerId] if player.dmgmultiplier ~= 1 then odl_multiplier(player.dmgmultiplier) end if defaults.multiteam_vehicles then writebyte(m_receivingPlayer + 0x20, getteam(receivingPlayerId)+1) registertimer(0, "multiteamtimer", receivingPlayerId) end if PlayerClass[receivingPlayerId].firefist then -- check for melee damage ApplyFlame(receivingPlayerId, causerObjId) PlayerClass[receivingPlayerId].firecauser = causerPlayerId end elseif receivingPlayerId then --say("1APPLYING DAMAGE TO: " .. tostring(getname(receivingPlayerId))) -- make sure firefister doesn't take fire damage local dmg_damage_category = readword(tagdata + 0x1C6) if dmg_damage_category == 7 then --say("1FLAME DAMAGE BEING APPLIED TO: " .. tostring(getname(receivingPlayerId))) if PlayerClass[receivingPlayerId].firefist then --say("1SETTING 0 DAMAGE") odl_multiplier(0) end end end end function multiteamtimer(id, count, playerId) local m_player = getplayer(playerId) if m_player and defaults.multiteam_vehicles then writebyte(m_player + 0x20, 0) end return false end function DamageAddressReset(id, count, userdata) local address = userdata[1] local offset = userdata[2] local orig_value = userdata[3] writeword(address + offset, orig_value) return false end local TempObjectTable = {} function OnObjectCreationAttempt(mapId, parentObjId, playerId) TempObjectTable[1] = mapId TempObjectTable[2] = playerId return nil end function portalgunTimer(id, count, userdata) local playerObjId = userdata[1] local m_bulletObj = userdata[2] if count < 100 then if getobject(playerObjId) then if readfloat(m_bulletObj + 0x68) == 0 then local x = readfloat(m_bulletObj, 0x5C) local y = readfloat(m_bulletObj, 0x60) local z = readfloat(m_bulletObj, 0x64) movobjectcoords(playerObjId, x, y, z) else return true end end end return false end function spawngunTimer(id, count, userdata) local playerId = userdata[1] local m_bulletObj = userdata[2] if getplayerobject(playerId) then local x = readfloat(m_bulletObj, 0x5C) local y = readfloat(m_bulletObj, 0x60) local z = readfloat(m_bulletObj, 0x64) local objspawnid = PlayerClass[playerId].objspawnid if objspawnid then createobject(objspawnid, 0, 60, false, x, y, z+0.6) end end return false end function OnObjectCreation(objectId) if defaults.infinite_ammo then local m_object = getobject(objectId) if m_object then local obj_type = readword(m_object, 0xB4) if obj_type == 2 then -- check if it is a weapon writeshort(m_object + 0x2B6, 0x7CFF) writeshort(m_object + 0x2B8, 0x7CFF) return -- we can safely return here end end end local mapId = TempObjectTable[1] local playerId = TempObjectTable[2] if getplayer(playerId) then if mapId ~= gettag("proj", "weapons\\flamethrower\\flame") and mapId ~= gettag("proj", "weapons\\needler\\mp_needle") and mapId ~= gettag("proj", "weapons\\frag grenade\\frag grenade") and mapId ~= gettag("proj", "weapons\\plasma grenade\\plasma grenade") then local player = PlayerClass[playerId] if player.bulletmode == "portalgun" then registertimer(100, "portalgunTimer", {getplayerobjectid(playerId), getobject(objectId)}) elseif player.bulletmode == "spawngun" then registertimer(100, "spawngunTimer", {playerId, getobject(objectId)}) end end end end function OnWeaponAssignment(playerId, objId, slot, weapTagId) if not next(spawnWeapons) then return nil end if playerId then local m_player = getplayer(playerId) if m_player then if slot == 0 and spawnWeapons[1] then return spawnWeapons[1] elseif slot == 1 and spawnWeapons[2] then return spawnWeapons[2] end end end return nil end -- basically this timer assigns the tertiary and quarternary weapons to players for the default_spawn_weapons command. -- this is needed since onweaponassignment isn't called for tertiary and quartenary weapons -- This timer is used for Generic gametypes function AssignLeftoverWeapons(id, count, playerId) local m_object = getplayerobject(playerId) if m_object then if spawnWeapons[3] then local m_weaponId = createobject(spawnWeapons[3], 0, 60, false, 5, 2, 2) if m_weaponId and m_weaponId ~= 0xFFFFFFFF then local m_weapon = getobject(m_weaponId) if m_weapon then -- set the ammo writeword(m_weapon + 0x2B6, ammocount) writeword(m_weapon + 0x2B8, clipcount) writefloat(m_weapon + 0x240, math.abs(batterycount - 1)) -- force it to sync updateammo(m_weaponId) end end if spawnWeapons[4] then -- create the quarternary weapon local m_weaponId = createobject(spawnWeapons[4], 0, 60, false, 1, 1, 1) -- make sure createobject didn't screw up if m_weaponId ~= 0xFFFFFFFF then -- assign the weapon to the player assignweapon(playerId, m_weaponId) -- make sure we can safely set the ammo local m_weapon = getobject(m_weaponId) if m_weapon then -- set the ammo writeword(m_weapon + 0x2B6, ammocount) writeword(m_weapon + 0x2B8, clipcount) writefloat(m_weapon + 0x240, math.abs(batterycount - 1)) -- force it to sync updateammo(m_weaponId) end end end end end return false end -- This timer is used for Custom gametypes function AssignWeapons(id, count, userdata) local playerId = userdata[1] local clipcount = userdata[2] local ammocount = userdata[3] local batterycount = userdata[4] if not playerId or not getplayer(playerId) then return false end local m_object = getplayerobject(playerId) if m_object then -- count is increased everytime the timer is called if count == 1 then -- gets rid of any weapons a zombie is holding destroyweapons(playerId) end local i = count if spawnWeapons[i] then local m_weaponId = createobject(spawnWeapons[i], 0, 60, false, 1, 1, 1) or 0xFFFFFFFF local m_weapon = getobject(m_weaponId) if m_weapon then -- Assign the weapon to the player. assignweapon(playerId, m_weaponId) -- set the ammo writeword(m_weapon + 0x2B6, ammocount) writeword(m_weapon + 0x2B8, clipcount) writefloat(m_weapon + 0x240, 1) -- force it to sync updateammo(m_weaponId) end end if count < 4 then return true else return false end end return false end function MainTimer(id, count) -- For hiding. local m_player for playerId = 0,15 do if getplayer(playerId) and PlayerClass[playerId] and PlayerClass[playerId].hidden then m_player = getplayer(playerId) if m_player then writefloat(m_player + 0x100, -100) end end end -- will run every second if count % 30 == 0 then -- local variables used local player -- For invisible timer, suspended timer, and message spamming. for playerId = 0,15 do if getplayer(playerId) then player = PlayerClass[playerId] if player.invisible == -1 then applycamo(playerId, 1.2) elseif player.invisible then applycamo(playerId, 1.2) player.invisible = player.invisible - 1 if player.invisible <= 0 then player.invisible = false end end if type(player.suspended) == "number" then player.suspended = player.suspended - 1 if player.suspended == 0 then player.suspended = false say(player.name .. " is no longer suspended") end end -- Player is currently muted for spamming, add 1 second from their timeout counter until they are at 0 (or above). if player.spamcounter < 0 then player.spamcounter = player.spamcounter + 1 if player.spamcounter > 0 then say(getname(playerId) .. " has been unmuted") player.spamcounter = 0 end -- Player has spammed too many messages, mute them for spamming elseif player.spamcounter > defaults.spam_max then say(getname(playerId) .. " has been muted for " .. timetoword(defaults.spam_timeout) .. " seconds for spamming") player.spamcounter = -defaults.spam_timeout -- Player has sent a message within the last second, will take 4 seconds to remove from spam counter. elseif player.spamcounter > 0 then player.spamcounter = player.spamcounter - 0.25 end end end -- RTV Counter if rtv_counter < 0 then rtv_counter = rtv_counter + 1 if rtv_counter == 0 then say "RTV can be started again." end end -- VoteKick Counter if votekick_counter < 0 then votekick_counter = votekick_counter + 1 if votekick_counter == 0 then say "VoteKick can be started again!" end end end return true end -- This script is now compatible with BOTH Sapp and Phasor! if loadstring then -- don't need the module if this script is loaded via phasor. _G = require"PhasorSappCompatibility" else _SERVERAPP = "Phasor" end