/***************************************************** * Poke-Place [[Reborn]]'s PO scripts. * Last update: Sat Jan 1 23:30:05 PST 2011 * (Except I'll probably forget to update the date...) * Written under the WTFPL: http://sam.zoy.org/wtfpl/COPYING *****************************************************/ this.GLOBAL; function init(){ makeGlobal(); include("Server"); include("Help"); include("Mute"); include("Events"); include("Channels"); include("TextModify"); include("Tournament"); include("Blacklist"); include("NightClub"); include("Automod"); include("Monotype"); include("Randoms"); include("Map"); } Array.prototype.indexOf = function(item, insensitive){ for (var i=0;i 2){ return false; } else if (/[\u2028\u2029\u200E\u200F\u202A\u202B\u202C\u202D\u202E]/.test(data)){ return true; } return (!auth && data.length > 2000); } this.postflood = function(src, channel, message){ if (util.isAuth(src, channel) || GLOBAL[channel].automod[0].flood == 0){ return; } var ip = sys.ip(src); GLOBAL[channel].automod[ip].flood += Math.ceil(message.length/300); var time = parseInt(sys.time()); var tlimit = 70/GLOBAL[channel].automod[0].flood; if (GLOBAL[channel].automod[ip].lastmessage != 0 && time > (GLOBAL[channel].automod[ip].lastmessage + tlimit)){ var dec = Math.floor((time-GLOBAL[channel].automod[ip].lastmessage)/tlimit); if ((GLOBAL[channel].automod[ip].flood -= dec) <= 0){ GLOBAL[channel].automod[ip].flood = 1; } } GLOBAL[channel].automod[ip].lastmessage = time; var limit = GLOBAL[channel].automod[0].flood; if (sys.dbRegistered(sys.name(src))){ limit += 2; } limit += ((2*Math.floor((sys.time() - GLOBAL[channel].automod[ip].join)/1800)) % 10); if (GLOBAL[channel].automod[ip].flood > limit){ sys.stopEvent(); this.kickify(src, channel); } } this.kickify = function(src, channel){ var ip = sys.ip(src); GLOBAL[channel].automod[ip].flood = 0; GLOBAL[channel].automod[ip].lastmessage = 0; GLOBAL[channel].automod[ip].kicks++; if (GLOBAL[channel].automod[ip].kicks > 4){ if (channel == 0){ sys.ban(sys.name(src)); GLOBAL[channel].automod[ip].kicks = 0; sys.sendHtmlAll("" + (util.username(src) || util.escapeHtml(sys.name(src))) + " has been banned for overactivity.", channel) } else { if (helper("autoban", src, channel)){ GLOBAL[channel].automod[ip].kicks = 0; } } } else { sys.sendHtmlAll("±Flood Notice: " + (util.username(src) || util.escapeHtml(sys.name(src))) + " has been kicked for overactivity.", channel); } if (channel == 0){ sys.callQuickly("sys.kick(" + src + ")", 100); } else { sys.callQuickly("sys.kick(" + src + ", " + channel + ")", 100); } } this.resetautomod = function(src, channel, data, kicked){ var message = util.parseMessage(0, data, false, true); if (!message){ util.failParameters(src, channel); return; } if (message.users.length == 0){ util.failUsers(src, channel); return; } for (var i=0;ioff, light, medium, and heavy. Stricter levels will kick users after a shorter amount of messages, as well as increases the time in which the users' flood value is recalculated."]; this.resetautomod.help = ["user", "Clears automod data for user.", "User's flood value and kick count will be reset."]; } /* }}} */ /* {{{ Blacklist Module: Provides methods to disable commands */ function Blacklist(){ this.init = function(){ register(1, "blacklist", this, "bl"); register(1, "whitelist", this, "wl"); helperregister("isBlacklisted", this); } this.isBlacklisted = function(channel, command){ if (GLOBAL[channel].blacklist == undefined){ return false; } return GLOBAL[channel].blacklist.indexOf(command) != -1; } this.showBlacklist = function(src, channel){ var html = ""; var margin = 1; if (GLOBAL[channel].blacklist == undefined){ html += "Nothing blacklisted."; margin++; } else { GLOBAL[channel].blacklist.sort(); for (var i=0;i"; margin++; } } html = util.tableHeader("Blacklist", (GLOBAL[channel].color || "darkred"), 1, margin, false) + html + "
"; sys.sendHtmlMessage(src, html, channel); } this.blacklist = function(src, channel, data){ var command, something = [], err = false; if (data == ""){ this.showBlacklist(src, channel); return; } data = data.split(" "); for (var i=0;i 3 ? 3 : auth == -1 ? 2 : auth; for (var j=0;j 3 ? 3 : auth == -1 ? 2 : auth; for (var j=0;j±Topic: " + GLOBAL[channel].topic; } return null; } this.kickify = function(src, channel, data, kickmessage){ var message; if (!data){ util.failParameters(src, channel); return; } if ((message = util.parseMessage(0, data, false, false)) == null){ sys.sendMessage(src, "Silly person trying to kick nonkickable things...", channel); return; } var myauth = util.isAuth(src, channel); if (myauth == -1){ myauth = 2; } for (var i=0;i 0){ sys.removeVal("kicks.reg", sys.name(src)); } else { if ("kick" in GLOBAL[channel]){ delete GLOBAL[channel].kick; } } sys.sendMessage(src, "Your kick message has been cleared.", channel); } this.topic = function(src, channel, data){ var old = "", topic; if (!data){ var t = this.showTopic(channel); if (!t){ sys.sendMessage(src, "Looks like no topic has been set...", channel); } else { sys.sendHtmlMessage(src, t, channel); } return; } else if (util.isAuth(src, channel)){ if (GLOBAL[channel].topic != undefined){ old = GLOBAL[channel].topic; } GLOBAL[channel].topic = helper("markdown", src, channel, data) || data; GLOBAL[channel].topic = GLOBAL[channel].topic.replace(/%s/g, old); sys.sendHtmlAll(this.showTopic(channel), channel); } else { util.failCommand(src, channel); } } this.cleartopic = function(src, channel, data){ if (GLOBAL[channel].topic != undefined){ delete GLOBAL[channel].topic; util.tellOthers(1, channel, sys.name(src) + " has cleared the topic."); } else { sys.sendMessage(src, "Looks like there is no topic to be cleared...", channel); } } this.setkick = function(src, channel, data){ var message, color if (data){ data = data.split(" "); color = data.shift(); if (!(/#[A-Fa-f0-9]{1,6}|\w+/.test(color))){ color = "black"; } data = data.join(" "); if (!data){ util.failParameters(src, channel); return; } else if (!(/%s/.test(data))){ sys.sendMessage(src, "You must include %s somewhere in your kick message...", channel); return; } message = "" + sys.name(src) + (/^'/.test(data) ? "" : " ") + util.escapeHtml(data) + ""; if (sys.auth(src) > 0){ sys.saveVal("kicks.reg", sys.name(src), message); } else { GLOBAL[channel].kick = message; } } else { if (sys.auth(src) > 0){ message = sys.getVal("kicks.reg", sys.name(src)); } else { message = GLOBAL[channel].kick; } } sys.sendHtmlMessage(src, "Current kick message: " + message, channel); } this.kick = function(src, channel, data){ var message = (sys.auth(src) > 0 ? sys.getVal("kicks.reg", sys.name(src)) : GLOBAL[channel].kick); if (!message){ message = "" + sys.name(src) + " has kicked %s to death. He might not be Reborn."; } this.kickify(src, channel, data, message); } this.silentkick = function(src, channel, data){ this.kickify(src, channel, data); } this.ban = function(src, channel, data){ var trgt, ip, message = util.parseMessage(0, data, true, false); if (!data){ util.failParameters(src, channel); return; } if (!message){ if (src != 0){ sys.sendMessage(src, "Wha? Banning a channel? Crazy person..", channel); } return; } for (var i=0;i 0)){ if (src != 0){ sys.sendMessage(src, "No banning the authy-flavored or chanOpy-flavored persons, good sir/ma'am.", channel); } continue; } if (message.users.length == 0){ if (src != 0){ util.failUsers(src, channel); } return; } if (channel == 0){ if (sys.banList().indexOf(trgt, true) != -1 && src != 0){ sys.sendMessage(src, trgt + " is already banned...", channel); return; } sys.sendHtmlAll("" + (sys.name(src) == "" ? trgt + " has been banned" : sys.name(src) + " has banned " + trgt) + ".", channel); sys.ban(trgt); if (!message.offline){ sys.kick(message.users[i]); } } else { if (GLOBAL[channel].ban == undefined){ GLOBAL[channel].ban = []; } if (this.isChannelBanned(message.users[i], channel)){ if (src != 0){ sys.sendMessage(src, trgt + " is already banned...", channel); } continue; } GLOBAL[channel].ban.push(ip); sys.sendHtmlAll("" + (sys.name(src) == "" ? trgt + " has been banned" : sys.name(src) + " has banned " + trgt) + ".", channel); if (!message.offline){ sys.kick(message.users[i], channel); } } } } this.unban = function(src, channel, data){ var trgt, ip, index, message = util.parseMessage(0, data, true, false); if (!data){ util.failParameters(src, channel); return; } if (!message){ sys.sendMessage(src, "Wha? Unbanning a channel? Crazy person..", channel); return; } if (message.users.length == 0){ util.failUsers(src, channel); return; } for (var i=0;i 1){ util.failParamters(src, channel); return; } if (!(/#[A-Fa-f0-9]{1,6}|\w+/.test(data[0]))){ data[0] = "black"; } GLOBAL[channel].color = data[0]; if (!(nomessage === true)){ util.tellOthers(2, channel, sys.name(src) + " has changed the colortheme to " + data[0]); } } this.authy = function(src, channel, data){ if (channel == 0){ sys.sendMessage(src, "Sorry, /authy cannot be used in the main channel.", channel); return; } var msg; if (GLOBAL[channel].authy == undefined){ GLOBAL[channel].authy = true; data = util.parseMessage(0, data, false, false); var players = sys.playersOfChannel(channel); for (var i=0;i±Authy Notice: " + msg, channel); } this.invite = function(src, channel, data){ var message = util.parseMessage(0, data, false, false); if (!message){ util.failParameters(src, channel); return; } var somebody = []; for (var i=0;i" + words[i] + ""; margin++; } if (html == ""){ html += "No contents..."; margin++; } html = util.tableHeader("Death List", (GLOBAL[channel].color || "darkblue"), 2, margin, false) + html + "
"; sys.sendHtmlMessage(src, html, channel); } this.edit = function(src, channel, data, file){ if (!data){ this.show(src, channel, file); return; } var words = sys.getFileContent(file).split("\n"); words.pop(); n = parseInt(data); if (!isNaN(n)){ if (n < 1 || n > words.length){ sys.sendMessage(src, "Sorry, " + n + " is not a valid index.", channel); return; } var removed = words.splice(n-1, 1); words = words.join("\n"); sys.writeToFile(file, words + "\n"); util.tellOthers(2, channel, sys.name(src) + " has removed the death: " + util.escapeHtml(removed[0])); } else if (/%s/.test(data)){ data = data.replace(/\\n/g, "\\n"); sys.appendToFile(file, data + "\n"); util.tellOthers(2, channel, sys.name(src) + " has added the death: " + util.escapeHtml(data)); } else { sys.sendMessage(src, "Parameter must be an index to remove or a death message containing %s.", channel); } } this.pokedeathmod = function(src, channel, data){ this.edit(src, channel, data, this.POKEDEATH); } this.deathmod = function(src, channel, data){ this.edit(src, channel, data, this.DEATH); } this.send = function(src, channel, data){ var muteval; if ((muteval = helper("isMuted", src, channel)) > 1){ util.failMuted(src, channel); return; } if (muteval == 1){ sys.sendHtmlMessage(src, data, channel); } else { sys.sendHtmlAll(data, channel); callhooks("afterChatMessage", src, data, channel); } return true; } this.death = function(src, channel, data, file){ var words; if (!data){ words = sys.name(src) + " was killed by Nyu for being too lazy to write his/her death and therefore attempting to crash the server."; } else { words = sys.name(src) + (/^'/.test(data) ? "" : " ") + data; } var newwords = helper("markdown", src, channel, words) || util.escapeHtml(words); var message = "~~~ " + newwords + " ~~~"; if (this.send(src, channel, message)){ sys.callQuickly("sys.kick(" + src + ")", 100); } } this.me = function(src, channel, data){ if (!data){ util.failParameters(src, channel); return; } newdata = helper("markdown", src, channel, data) || util.escapeHtml(data); var message = "*** " + sys.name(src) + (/^'/.test(data) ? "" : " ") + newdata + " ***"; this.send(src, channel, message); } this.die = function(src, channel, data){ this.death(src, channel, data, this.DEATH); } this.pokedie = function(src, channel, data){ this.death(src, channel, data, this.POKEDEATH); } this.me.help = ["action", "Performs action."]; this.die.help = ["action", "Kills yourself.", "If no action given, a random preset will be chosen."]; this.pokedie.help = ["", "Death by pokemon."]; } /* }}} */ /* {{{ Help Module: Provides a help command for explaining various commands */ function Help(){ this.init = function(){ register(0, "help", this, "commands", "h"); register(0, "alias", this, "aliases"); } this.colors = ['#24434B', '#FA7F4B', '#FC325B', '#24434B']; this.alias = function(src, channel, data){ var auth = util.isAuth(src, channel); if (auth == -1){ auth = 2; } else if (auth > 3){ auth = 3; } var margin = 1, html = ""; var commands = [] for (var i in GLOBAL.aliases){ for (var j=0;j<=auth;j++){ if (GLOBAL.aliases[i] in GLOBAL.calls[j]){ if (commands[j] == undefined){ commands[j] = {}; } if (commands[j][GLOBAL.aliases[i]] == undefined){ commands[j][GLOBAL.aliases[i]] = []; } commands[j][GLOBAL.aliases[i]].push(i); break; } } } for (var i=0;i<=auth;i++){ for (var j in commands[i]){ margin++; html += "" + j + ":" + commands[i][j].join(", ") + ""; } } html = util.tableHeader("Aliases", (GLOBAL[channel].color || "green"), 3, margin, false) + html + "
"; sys.sendHtmlMessage(src, html, channel); } this.help = function(src, channel, data){ var helpstr, args, auth = util.isAuth(src, channel); if (auth == -1){ auth = 2; } else if (auth > 3){ auth = 3; } if (data){ data = translate(data.replace(/^[\/!]/, "")) for (var i=auth;i>=0;i--){ if ((data in GLOBAL.calls[i] && ((helpstr = GLOBAL.calls[i][data][data].help) != undefined))){ if (GLOBAL.calls[i][data][data].authonly && sys.auth(src) < 2){ util.failPermission(src, channel); return; } args = helpstr[0].replace(/^(.+?)$/, "[$1]").replace(/\s+/g, "] ["); sys.sendHtmlMessage(src, "±Help: /" + data + " " + args + " - " + helpstr[1] + (helpstr.length == 3 ? " " + helpstr[2] : ""), channel); break; } } if (!helpstr){ if (data in GLOBAL.helps){ sys.sendHtmlMessage(src, GLOBAL.helps[data](GLOBAL[channel].color || "purple"), channel); } else { util.failParameters(src, channel); } } } else { var margin = 1, html = ""; for (var i=0;i<=auth;i++){ for (var c in GLOBAL.calls[i]){ helpstr = GLOBAL.calls[i][c][c].help; if (helpstr){ if (GLOBAL.calls[i][c][c].authonly && sys.auth(src) < 2){ continue; } args = helpstr[0].replace(/^(.+?)$/, "[$1]").replace(/\s+/g, "] ["); html += "" + c + " " + args + " - " + helpstr[1] + ""; margin++; } } } var other = "" for (var i in GLOBAL.helps){ other += "" + i + ", "; margin++; } other = other.replace(/,([^,]+), $/, " and $1."); html += "Other help topics: " + other + ""; html = util.tableHeader("Help: All commands must be prefixed with either / or !", (GLOBAL[channel].color || this.colors[2]), 1, margin, true) + html + "
"; sys.sendHtmlMessage(src, html, channel); } } this.alias.help = ["", "Displays aliases for commands."]; this.help.help = ["command", "Display help on given command.", "Yay recursion!"] GLOBAL.helps["users"] = function(color){ return util.tableHeader("Users", color, 2, 24, true) + "For any command which expects a user as an argument (/kick, /join, etc.), " + "the argument can be given in any of the following ways. " + "You cannot combine the different methods." + "Username" + "The most basic form of specifying a user." + "Simply provide the username as an argument. " + "You can only specify 1 user with this method." + "/kick AnnoyingUserWill kick AnnoyingUser" + "/kick Really Annoying UserWill kick Really Annoying User." + "User ID" + "Specify the user ID by prefixing a +. " + "See /userlist for a list of IDs." + "/mute +1 +2 +3Will mute users with the IDs of 1, 2, and 3." + "/mute +0Performs a channel-mute." + "Offline Users" + "Specify offline users by prefixing a =." + "/ban =BanAvoider =RandomGuyWill ban BanAvoider and RandomGuy, if offline." + "Regex" + "Specify a regex pattern by prefixing a ~. " + "For complete regex documentation, see here. " + "Regex is case-sensitive but can match anywhere in the username." + "/admin ~AWill admin anyone with an A in their name" + "/mod ~^\\[\\+INF\\]Will mod anyone whose name starts with [+INF]." + "/kick ~\\d$Will kick all users whose name ends with a number." + " " } GLOBAL.helps["scripts"] = function(color){ return util.tableHeader("Reborn Scripts", color, 1, 3, true) + "This script written by Nyu under the WTF Public License.
" + "The script is available for download here, with external files available here " + "and here. These files should be placed in the same directory as the server binary. " + "Of course, feel free to add/remove/modify/whatever you'd like, or talk to me if you have any questions/comments/complaints/suggestions/food/etc. " + "If you'd like to customize this script for your own server, look in the Server function, as that's where most of the things you'll want to change are hiding at. " + "Many thanks to all the people that provided testing, code extracts, ideas, and the like. Kbai~
"; } } /* }}} */ /* {{{ Map Module: Like Vim's :map, but less awesome */ function Map(){ this.init = function(){ register(1, "map", this, "maps"); register(1, "unmap", this); hook("beforeCommands", this); } this.escape = function(text){ return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); } this.showMaps = function(src, channel){ mychannel = channel if (util.isAuth(src, channel) > 0){ mychannel = 0; } var ip = sys.ip(src); if (GLOBAL[mychannel].maps == undefined || GLOBAL[mychannel].maps[ip] == undefined){ sys.sendMessage(src, "No maps defined.", channel); return; } var html = ""; var margin = 1; for (var map in GLOBAL[mychannel].maps[ip]){ margin++; html += "" + util.escapeHtml(map) + ": " + (helper("markdown", src, channel, GLOBAL[mychannel].maps[ip][map]) || GLOBAL[mychannel].maps[ip][map]) + ""; } if (!html){ sys.sendMessage(src, "No maps defined.", channel); return; } html = util.tableHeader("Maps", GLOBAL[channel].color || "green", 1, margin, true) + html + "
"; sys.sendHtmlMessage(src, html, channel); } this.unmap = function(src, channel, data){ var mychannel = channel; if (util.isAuth(src, channel) > 0){ mychannel = 0; } var ip = sys.ip(src); if (GLOBAL[mychannel].maps == undefined || GLOBAL[mychannel].maps[ip] == undefined){ sys.sendMessage(src, "Sorry, you have no maps defined.", channel); return; } if (data in GLOBAL[mychannel].maps[ip]){ delete GLOBAL[mychannel].maps[ip][data]; sys.sendMessage(src, "Map " + data + " has been removed.", channel); if (GLOBAL[mychannel].maps[ip] == {}){ delete GLOBAL[mychannel].maps[ip]; if (GLOBAL[mychannel].maps == {}){ delete GLOBAL[mychannel].maps; } } } else { sys.sendMessage(src, "Invalid or no map provided; cannot remove.", channel); } } this.map = function(src, channel, data){ if (!data){ this.showMaps(src, channel); return; } var mychannel = channel; if (util.isAuth(src, channel) > 0){ mychannel = 0; } data = data.split(" "); if (data.length < 2){ util.failParameters(src, channel); return; } var map = data.shift(); if (/^\/(?:un)?map/.test(map)){ sys.sendMessage(src, "Sorry, you cannot remap /map or /unmap.", channel); return; } var rest = data.join(" "); if (GLOBAL[mychannel].maps == undefined){ GLOBAL[mychannel].maps = {}; } var ip = sys.ip(src); if (GLOBAL[mychannel].maps[ip] == undefined){ GLOBAL[mychannel].maps[ip] = {}; } GLOBAL[mychannel].maps[ip][map] = rest; sys.sendHtmlMessage(src, util.escapeHtml(map) + " has been mapped to: " + (helper("markdown", src, channel, rest) || rest), channel); } this.beforeCommands = function(src, data, channel, mapped){ if (mapped === true || /^\/(?:un)?map/.test(data)){ return; } switch(util.isAuth(src, channel)){ case -1: mychannel = channel; break; case 0: return; default: mychannel = 0; } var ip = sys.ip(src); if (GLOBAL[mychannel].maps == undefined || GLOBAL[mychannel].maps[ip] == undefined){ return; } var newdata = data; for (var map in GLOBAL[mychannel].maps[ip]){ var mymap = new RegExp("(^|\\W)" + this.escape(map) + "(?=\\W|$)", "g"); newdata = newdata.replace(mymap, "$1" + GLOBAL[mychannel].maps[ip][map]); } if (newdata != data){ if (!callhooks("beforeCommands", src, newdata, channel, true)){ if (!command(src, newdata, channel)){ if (!callhooks("beforeChatMessage", src, newdata, channel)){ sys.sendHtmlAll(util.header(src) + util.escapeHtml(newdata)); } } } sys.stopEvent(); return true; } } this.map.help = ["map definition", "Sets a map to the given definition. All uses of map will be replaced by its definition.", "A map name must be only 1 word, but definitions can be of any length. If no arguments given; shows a list of current maps."]; this.unmap.help = ["map", "Removes the definition for the given map."]; } /* }}} */ /* {{{ Monotype Module: For teams of all 1 flavor */ function Monotype(){ this.init = function(){ hook("beforeChallengeIssued", this); hook("beforeChangeTier", this); } this.isValid = function(src){ var mytypes = []; var pokes = 0; /* Initialize mytypes; 0'ify all 17 types */ for (var i=0;i<17;mytypes[i++]=0); for (var i=0;i<6;i++){ if (p = sys.teamPoke(src, i)){ pokes++; mytypes[sys.pokeType1(p)]++; mytypes[sys.pokeType2(p)]++; } } mytypes.pop(); /* Remove then ??? type */ for (var i=0;i= pokes-1){ return true; } } return false; } this.beforeChallengeIssued = function(src, trgt){ if (/mono/i.test(sys.tier(src)) || /mono/i.test(sys.tier(trgt))){ if (!this.isValid(src)){ sys.stopEvent(); sys.sendMessage(src, "You are in a Monotype tier but do not have a valid Monotype team.", channel); } else if (!this.isValid(trgt)){ sys.stopEvent(); sys.sendMessage(src, "Your opponent in a Monotype tier but do not have a valid Monotype team.", channel); } } } this.beforeChangeTier = function(src, oldt, newt){ if (/mono/i.test(newt) && !this.isValid(src)){ sys.stopEvent(); sys.sendMessage(src, "You do not have a valid Monotype team.", channel); } } } /* }}} */ /* {{{ Mute Module: Provides methods of shutting people up. */ function Mute(){ this.init = function(){ register(1, "mute", this, "m"); register(1, "eventmute", this, "em"); register(2, "evilmute", this); register(1, "unmute", this, "um"); hook("beforeChatMessage", this); hook("afterChannelJoin", this); helperregister("isMuted", this); } this.getMuteVal = function(src, channel){ var ip = (src == 0 ? 0 : sys.ip(src)); if (ip != 0 && util.isAuth(src, channel)){ return 0; } else if (GLOBAL[channel].mute == undefined){ return 0; } else if (GLOBAL[channel].mute[ip] == undefined){ return 0; } else { return GLOBAL[channel].mute[ip]; } } this.isMuted = function(src, channel){ if (util.isAuth(src, channel)){ return 0; } var m = this.getMuteVal(0, channel); if (m == 0){ m = this.getMuteVal(src, channel); } return m; } this.changeMuteVal = function(src, trgt, offline, channel, level){ var message, prev = 0; switch (level){ case 0: message = "unmuted"; break; case 1: message = "evilmuted"; break; case 2: message = "muted"; break; case 3: message = "eventmuted"; break; } if (offline){ if (sys.auth(src) > 0){ if (level == 0){ sys.removeVal("muted.reg", sys.dbIp(trgt)); } else { sys.saveVal("muted.reg", sys.dbIp(trgt), level); } sys.sendMessage(src, "You have " + message + " offline user " + trgt + " (applies to main channel only).", channel); } else { sys.sendMessage(src, "Sorry, only auths can mute offline users.", channel); } return; } if (GLOBAL[channel].mute == undefined){ GLOBAL[channel].mute = {}; } var ip = (trgt == 0 ? 0 : sys.ip(trgt)); if (GLOBAL[channel].mute[ip] != undefined){ prev = GLOBAL[channel].mute[ip]; } if (trgt == 0 && level == 1){ sys.sendMessage(src, "Sorry, no evilmuting the channel, that's just cruel.", channel); return; } else if (prev == level && src != -1){ sys.sendMessage(src, (trgt == 0 ? "The channel" : sys.name(trgt)) + " is already " + message, channel); return; } if (level == 0){ delete GLOBAL[channel].mute[ip]; if (channel == 0 && trgt != 0){ sys.removeVal("muted.reg", sys.ip(trgt)); } } else { GLOBAL[channel].mute[ip] = level; if (channel == 0 && trgt != 0){ sys.saveVal("muted.reg", sys.ip(trgt), level); } } if (prev != 1 && trgt != 0 && level != 1){ sys.sendMessage(trgt, "You have been " + message + ".", channel); } if (trgt == 0){ sys.sendHtmlAll("±Mute Notice: The channel has been " + message, channel); } else { if (src != -1){ util.tellOthers(1, channel, sys.name(src) + " has " + message + " " + sys.name(trgt)); } } } this.showMuted = function(src, channel){ var html = "", margin = 1; var m = this.getMuteVal(0, channel); if (m){ html += "The channel is currently " + (m == 2 ? "muted." : "eventmuted.") + ""; margin++; } var users = sys.playersOfChannel(channel); for (var i=0;i"; margin++; } } if (html == ""){ html += "Nobody's muted..."; margin++; } html = util.tableHeader("Mute List", (GLOBAL[channel].color || "darkblue"), 1, margin, false) + html + "
"; sys.sendHtmlMessage(src, html, channel); } this.mutify = function(src, channel, message, level){ var trgts, auth; if (!message){ this.showMuted(src, channel); return; } if ((trgts = util.parseMessage(0, message)) == null){ return; } if (trgts.users.length == 0){ util.failUsers(src, channel); return; } for (var i=0;i 0){ sys.sendMessage(src, "User " + (trgts.offline ? trgts.users[i] : sys.name(trgts.users[i])) + " is authy; cannot be muted.", channel); } else { this.changeMuteVal(src, trgts.users[i], trgts.offline, channel, level); } } } this.mute = function(src, channel, message){ this.mutify(src, channel, message, 2); } this.eventmute = function(src, channel, message){ this.mutify(src, channel, message, 3); } this.evilmute = function(src, channel, message){ this.mutify(src, channel, message, 1); } this.unmute = function(src, channel, message){ this.mutify(src, channel, message, 0); } this.beforeChatMessage = function(src, message, channel){ var c = this.getMuteVal(0, channel); var m = this.getMuteVal(src, channel); if (c == 2 && !util.isAuth(src, channel)){ sys.stopEvent(); sys.sendMessage(src, "Sorry, the channel is muted.", channel); return true; } else if (m == 2){ sys.stopEvent(); util.failMuted(src, channel); return true; } else if (m == 1){ sys.stopEvent(); var newmessage = helper("markdown", src, channel, message); if (newmessage && newmessage != message){ sys.sendHtmlMessage(src, util.header(src) + newmessage, channel); } else { sys.sendMessage(src, sys.name(src) + ": " + message, channel); } return true; } } this.afterChannelJoin = function(src, channel){ if (!util.isAuth(src, channel)){ var m = this.getMuteVal(src, channel); if (channel == 0 && m == 0){ m = parseInt(sys.getVal("muted.reg", sys.ip(src))); } if (!(isNaN(m)) && m != 0){ this.changeMuteVal(-1, src, false, channel, m); } } m = this.getMuteVal(0, channel); if (m != 0){ var message = "±Mute Notice: The channel is currently " + (m == 2 ? "muted." : "muted from events.").replace(/"/g, "\\"); sys.callQuickly("sys.sendHtmlMessage(" + src + ", \"" + message + "\", " + channel + ")", 200); } } this.mute.help = ["user", "Prevents user from speaking.", "If no user provided, shows all muted people online."]; this.eventmute.help = ["user", "Prevents user from using events.", "If no user provided, shows all muted people online."]; this.evilmute.help = ["user", "Mute user without giving any indication of their mutedness.", "If no user provided, shows all muted people online."]; this.unmute.help = ["user", "Remove all mute status from user.", "If no user provided, shows all muted people online."]; } /* }}} */ /* {{{ NightClub Module: Pretty colors~ */ function NightClub() { this.init = function(){ register(1, "nightclub", this); hook("beforeCommands", this); } this.rainbowify = function(text, numcolors){ if (!numcolors){ numcolors = Math.max(Math.ceil(text.length/10), 10); } var limit = Math.ceil(text.length / numcolors); var colors = []; for (var i=0;i"; } html += util.escapeHtml(text[c]); if (++count == limit){ html += "
"; count = 0; } } if (count != 0){ html += ""; } return "
" + html + "
"; } this.toggle = function(channel){ if (GLOBAL[channel].nightclub == undefined){ GLOBAL[channel].nightclub = true; } else { GLOBAL[channel].nightclub = !GLOBAL[channel].nightclub } return GLOBAL[channel].nightclub; } this.nightclub = function(src, channel, data){ this.beforeCommands(src, "/nightclub", channel); } this.beforeCommands = function(src, data, channel){ if (helper("isBlacklisted", channel, "nightclub") && (util.isAuth(src, channel) == 1)){ return false; } if (/^\/nightclub$/.test(data) && util.isAuth(src, channel)){ if (this.toggle(channel)){ sys.sendHtmlAll("
" + this.rainbowify("Let the Night Club commence!"), channel); } else { sys.sendHtmlAll(this.rainbowify("Kay, Night Club times is over...") + "
", channel); } sys.stopEvent(); return true; } else if (GLOBAL[channel].nightclub){ sys.stopEvent(); sys.sendHtmlAll(this.rainbowify("(" + sys.name(src) + "): " + data), channel); return true; } return false; } this.nightclub.help = ["", "Colors? Colors!", "Note that when enabled, all commands (other than /nightclub) and flood-control are ignored."]; } /* }}} */ /* {{{ Randoms Module: Provides random-username thingy, team-generator, etc. */ function Randoms(){ this.init = function(){ register(0, "roulette", this, "rng"); register(2, "pewpewpew", this); hook("beforeChatMessage", this); hook("beforeMarkdown", this); } this.prettify = function(src, channel, data){ var users = sys.playerIds(channel); data = helper("markdown", src, channel, data) || util.escapeHtml(data); var user = users[sys.rand(0, users.length)]; sys.sendHtmlAll(util.header(user) + data.replace(/%s/g, sys.name(user)), channel); } this.beforeChatMessage = function(src, data, channel){ if (GLOBAL[channel].christmas != undefined && GLOBAL[channel].christmas.on == true){ sys.stopEvent(); this.prettify(src, channel, data); return true; } } this.beforeMarkdown = function(src, channel){ if (GLOBAL[channel].christmas == undefined){ return false; } return GLOBAL[channel].christmas.on; } this.pewpewpew = function(src, channel, data){ if (GLOBAL[channel].christmas == undefined){ GLOBAL[channel].christmas = {on: false}; } if (GLOBAL[channel].christmas.on == false){ GLOBAL[channel].christmas.on = true; util.tellOthers(2, channel, "Random usernames time..."); } else { GLOBAL[channel].christmas.on = false; util.tellOthers(2, channel, "Random usernames time is over."); } GLOBAL[channel].christmas.count = 0; } this.roulette = function(src, channel, data){ var valid = [3, 6, 9, 12, 15, 18, 20, 22, 24, 26, 28, 31, 34, 36, 38, 40, 45, 47, 49, 51, 53, 55, 57, 59, 62, 65, 68, 71, 73, 76, 78, 80, 83, 85, 87, 89, 91, 94, 97, 99, 101, 103, 105, 106, 107, 110, 113, 115, 119, 121, 122, 123, 124, 127, 128, 129, 130, 131, 132, 134, 135, 136, 139, 141, 142, 143, 144, 145, 146, 149, 150, 151, 154, 157, 160, 162, 164, 166, 168, 169, 171, 178, 181, 182, 184, 185, 186, 189, 192, 195, 196, 197, 199, 201, 202, 203, 205, 206, 208, 210, 211, 212, 213, 214, 217, 219, 222, 224, 225, 226, 227, 229, 230, 232, 233, 234, 235, 237, 241, 242, 243, 244, 245, 248, 249, 250, 251, 254, 257, 260, 262, 264, 267, 269, 272, 275, 277, 279, 282, 284, 286, 289, 291, 292, 295, 297, 301, 302, 303, 306, 308, 310, 311, 312, 313, 314, 317, 319, 321, 323, 324, 326, 327, 330, 332, 334, 335, 336, 337, 338, 340, 342, 344, 346, 348, 350, 351, 352, 354, 356, 357, 358, 359, 362, 365, 367, 368, 369, 370, 373, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 389, 392, 395, 398, 400, 402, 405, 407, 409, 411, 413, 414, 416, 417, 419, 421, 423, 424, 426, 428, 429, 430, 432, 435, 437, 441, 442, 445, 448, 450, 452, 454, 455, 457, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 490, 491, 492, 494, 497, 500, 503, 505, 508, 510, 512, 514, 516, 518, 521, 523, 526, 528, 530, 531, 534, 537, 538, 539, 542, 545, 547, 549, 550, 553, 555, 556, 558, 560, 561, 563, 565, 567, 569, 571, 573, 576, 579, 581, 584, 586, 587, 589, 591, 593, 594, 596, 598, 601, 604, 606, 609, 612, 614, 615, 617, 618, 620, 621, 623, 625, 626, 628, 630, 631, 632, 635, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649] var limit = isNaN(parseInt(data)) || data > 100 || data < 1 ? 6 : parseInt(data); for (var i=0, nums=[];iWhat is the Reborn League, you ask? The Reborn League is an expansive challenge " + "which pits you against a variety of mono-type teams and versatile characters that are " + "guaranteed to test any trainer to their limits.You'll register a team of six Pokemon and " + "their moves to carry you to the end and earn you the 17 badges on your shiny personalized " + "trainer card. Expect to fight battles of all types - you should be ready for anything, making " + "this the ultimate trial for any team. So, think you have what it takes? Then join us! " + "Everything you need to get started is right here." + "
"; this.message(src, channel, message, data, "reborn"); } this.rules = function(src, channel, data){ var color = function(m){ return "" + m + ""; } var message = util.tableHeader("Reborn Rules", (GLOBAL[channel].color || "blue"), 1, 9, true) + "" + color("1. ") + "Be respectful. Or at least pretend like it." + "" + color("2. ") + "At least attempt to act intelligently (No chatspeak)." + "" + color("3. ") + "No trolling." + "" + color("4. ") + "Do not be annoying. This is subjective and on a case by case basis." + "" + color("5. ") + "Do not challenge the Gym Leaders. They will challenge you." + "" + color("6. ") + "Do not advertise. Seriously." + "" + color("7. ") + "Sexual content will not be tolerated." + "" + color("8. ") + "All talk in the main-chat should be English." + "
"; this.message(src, channel, message, data, "rules"); } this.authlist = function(src, channel){ var id, user, auths = sys.dbAuths(); for (var i=0;i:" + (auth > 3 ? "Prinny, dood!" : auth == 3 ? "Owner" : auth == 2 ? "Administrator" : "Moderator") + (GLOBAL[channel].chanOp == sys.id(auths[i].substr(1)) ? " + ChanOp" : "") + ""; } if (util.username(GLOBAL[channel].chanOp) && util.isAuth(GLOBAL[channel].chanOp, channel) == -1){ message += "" + util.username(GLOBAL[channel].chanOp) + ":ChanOp"; } message += "
"; if (auths.length == 0){ sys.sendMessage(src, "Wha? No authy people? Anarchy times~", channel); } else { sys.sendHtmlMessage(src, message, channel); } } this.userlist = function(src, channel){ var players = util.playerIds(); var html = ""; var count = 0, margin = 3; for (var i=1;i(.*?)<\/b>/, i + ". $1"); } else { user = user.replace(/(.*?)/, "" + i + ". $1"); } html += "" + user + ""; } html = util.tableHeader("User List", (GLOBAL[channel].color || "grey"), 5, margin, false) + "Id 0 is the channel id. Bold users are in the current channel." + "0. " + sys.channel(channel) + "" + html + "
"; sys.sendHtmlMessage(src, html, channel); } this.eval = function(src, channel, data){ if (!data){ util.failParameters(src, channel); return; } if (sys.auth(src) < 5 && /sys\.system\(/.test(data)){ sys.sendMessage(src, "Sorry, sys.system() is disabled in /eval for security reasons.", channel); return; } else if (sys.auth(src) < 5 && /sys\.shutDown\(/.test(data)){ sys.sendMessage(src, "Sorry, sys.shutDown() is disabled in /eval for security reasons.", channel); } else { sys.eval(data); } } this.changeAuth = function(src, channel, data, level, title){ var message, auth, trgt; if ((message = util.parseMessage(0, data, true, false)) == null){ sys.sendMessage(src, "Trying to authify a channel doesn't really make sense, now does it?", channel); return; } if (message.users.length == 0){ sys.sendMessage(src, "Sorry, no user(s) found.", channel); return; } for (var i=0;i auth){ if (auth != level){ (message.offline ? sys.changeDbAuth : sys.changeAuth)(message.users[i], level); util.tellOthers(1, channel, sys.name(src) + " has set " + trgt + " as " + title); } else { (message.offline ? sys.changeDbAuth : sys.changeAuth)(message.users[i], 0); util.tellOthers(1, channel, sys.name(src) + " has removed " + trgt + " as " + title); } } else { sys.sendMessage(src, "Sorry, user " + trgt + " has equal or higher authority than you; cannot change.", channel); } } } this.selfkick = function(src, channel, data){ var ip = sys.ip(src); var players = sys.playerIds(); for (var i=0; i" + sys.channel(channel) + "
" : util.username(message.users[i]) || message.users[i]) + ", "; somebody = true; } userstr = userstr.replace(/, $/, ""); if (!somebody){ util.failUsers(src, channel); } else { sys.sendHtmlMessage(src, "Matched users: " + userstr, channel); } } this.afterLogIn = function(src, channel){ if (!channel) channel = 0; var m = sys.getVal("welcome"); if (m){ sys.sendHtmlMessage(src, "±Welcome Message: " + m, channel); } } this.rules.help = ["", "Displays the rules. Yay rules~"]; this.reborn.help = ["", "Provides information about the Reborn Server."]; this.authlist.help = ["", "Displays all the people preventing this place from exploading."]; this.userlist.help = ["", "Displays all users currently on the server."]; this.selfkick.help = ["", "Removes all users with the same IP as yourself."]; this.regex.help = ["regex", "Displays all matched users for a given regex.", "Also works for the other user-input methods, so you can also try it for offline users or user IDs"]; this.eval.help = ["script", "Evaluates the given script."]; this.idle.help = ["user", "Toggles user's idle status."]; this.mod.help = ["user", "Toggles user's status as a moderator."]; this.admin.help = ["user", "Toggles user's status as an administrator."]; this.announce.help = ["announcement", "Changes the announcement.", "HTML allowed. A %s in the announcement will be replaced by the current announcement."]; this.welcome.help = ["message", "Displays the welcome message.", "If message is provided, sets the welcome message. HTML allowed. A %s in the message will be replaced by the current welcome message."]; this.reloadscript.help = ["", "Refreshes the scripts."]; } /* }}} */ /* {{{ TextModify Module: Allows methods for modifying text before it gets sent */ function TextModify(){ this.init = function(){ register(2, "censor", this); register(2, "uncensor", this); hook("beforeChatMessage", this); helperregister("markdown", this); } this.markdown = function(src, channel, message){ message = this.evalCensors(src, channel, message); if (message === false){ return null; } message = util.escapeHtml(message); message = message.replace(/^[.!\/]([!\/]+.*)$/, "$1"); message = message.replace(/^(>>(?!.?(?:>|<)|[:;]?[3DOo0\]\[](?:$|\s)).*?(?=\S).*)$/, "$1"); message = message.replace(/^(>(?!.?(?:>|<)|[:;]?[3DOo0\]\[|](?:$|\s)).*?(?=\S).*)$/, "$1"); message = message.replace(/\\\*/g, "*").replace(/\\_/g, "_"); message = message.replace(/\\\[/g, "[").replace(/\\\]/g, "]"); message = message.replace(/\\\(/g, "(").replace(/\\\)/g, ")"); message = message.replace(/\\-/g, "-").replace(/\\\)/g, ")"); message = message.replace(/(^|\W)_\^_(?=$|\s)/g, "$1↑").replace(/(^|\W)_[vV]_(?=$|\s)/g, "$1↓"); message = message.replace(/(^|\W)_>_(?=$|\s)/g, "$1→").replace(/(^|\W)_<_(?=$|\s)/g, "←"); message = message.replace(/(^|\W|_)\*\*(\S(?:.*?\S)?)\*\*(?=_|\W|$)/g, "$1$2"); message = message.replace(/(^|\W)_(?![\.oO0@](?:\s|$))(\S(?:.*?\S)?)_(?=\W|$)/g, "$1$2"); message = message.replace(/(^|\W|_)--(\S(?:.*?\S)?)--(?=_|\W|$)/g, "$1$2"); message = message.replace(/\[(?!\s\])([^\[]+)\]\(([^\s\)]+)(?:\s(['"])([^'"]+)\3)?\)/g, "$1"); var hashttp = /$2$3"); return message; } this.showCensors = function(src, channel){ var html = "", margin = 1; if (GLOBAL[channel].censor != undefined){ for (var i=0;i" + (GLOBAL[channel].censor[i][2] ? GLOBAL[channel].censor[i][0] : GLOBAL[channel].censor[i][0].source.replace(/\\/g, "")) + ":" + (GLOBAL[channel].censor[i][1] || "<disallowed>") + ""; margin++; } } if (html == ""){ html += "Nothing censored..."; margin++; } html = util.tableHeader("Censor List", (GLOBAL[channel].color || "darkblue"), 4, margin, false) + html + "
"; sys.sendHtmlMessage(src, html, channel); } this.evalCensors = function(src, channel, message){ if (GLOBAL[channel].censor == undefined || util.isAuth(src, channel)){ return message; } for (var i=0;i GLOBAL[channel].censor.length || n < 1){ util.failParameters(src, channel); return; } var removed = GLOBAL[channel].censor.splice(n-1, 1); util.tellOthers(2, channel, sys.name(src) + " has uncensored " + (removed[0][2] ? removed[0][0] : removed[0][0].source.replace(/\\/g, ""))); if (GLOBAL[channel].censor.length == 0){ delete GLOBAL[channel].censor; } } this.censor = function(src, channel, data){ if (!data){ this.showCensors(src, channel); return; } var flags = "gi"; if (/^\s*\//.test(data)){ newdata = data.replace(/\\\//g, "/"); regex = /^\s*\/([^\/]+)\/(?:$|([^\/]*)(?:\/?$|\/([gi]{0,2})\/?))/i.exec(newdata); if (!regex){ sys.sendMessage(src, "Invalid regex =/", channel); return; } args = [regex[1], regex[2], true]; flags = regex[3].toLowerCase(); } else { args = data.split(" ", 2); if (args.length == 1){ args.push(""); } args[0] = args[0].replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); args.push(false); } try { regex = new RegExp(args[0], flags); } catch (e){ sys.sendMessage(src, args[0] + " is not valid regex...", channel); return; } args[0] = regex; if (GLOBAL[channel].censor == undefined){ GLOBAL[channel].censor = []; } GLOBAL[channel].censor.push(args); util.tellOthers(1, channel, sys.name(src) + " has censored: " + util.escapeHtml((args[2] ? args[0] : args[0].source.replace(/\\/g, "")).toString()) + " " + (args[1] == "" ? "(completely disallowed)" : "to " + util.escapeHtml(args[1]))); } this.beforeChatMessage = function(src, message, channel){ var newmessage = this.markdown(src, channel, message); if (newmessage === null){ sys.stopEvent(); return; } var muteval = helper("isMuted", src, channel); if (muteval == 2 || muteval == 1){ return; } if (!callhooks("beforeMarkdown", src, channel)){ if (newmessage != message){ sys.stopEvent(); sys.sendHtmlAll(util.header(src) + newmessage, channel); callhooks("afterChatMessage", src, newmessage, channel); return true; } } } GLOBAL.helps["markdown"] = function(color){ return util.tableHeader("Markdown", color, 2, 10, true) + "Markdown provides a method of formatting text into something prettier.
" + "Inputted TextDisplayed As" + "_italics_italics" + "**bold**bold" + "--strikethrough--strikethrough" + "[link](http://ffff00.com)link" + ">color1>color1" + ">>color2>>color2" + "\\_escaped\\__escaped_" + " " } this.censor.help = ["text replace", "Censors text.", "If replace is given, changes text to replace, otherwise blocks message completely. text/replace can also be given in sed-style /find/replace/flags notation, which allows regex. If no arguments, lists censors."]; this.uncensor.help = ["id", "Uncensors the censor by id.", "Use /censor with no arguments to list ids"]; } /* }}} */ /* {{{ Tournament Module: Tournaments are evil */ function Tournament(){ this.init = function(){ register(0, "join", this, "touradd", "j"); register(0, "leave", this, "disqualify", "dq"); register(0, "viewmatches", this); register(1, "tour", this); register(1, "starttour", this); register(1, "endtour", this); register(1, "toursize", this); register(1, "tourswap", this); hook("beforeChallengeIssued", this); hook("afterBattleEnded", this); hook("afterChannelJoin", this); } this.getTourMode = function(channel){ if (GLOBAL[channel].tour == undefined){ return -1; } return GLOBAL[channel].tour.mode; } this.index = function(src, channel){ if (GLOBAL[channel].tour == undefined){ return -1; } return GLOBAL[channel].tour.users.indexOf(src); } this.announce = function(channel){ if (GLOBAL[channel].tour == undefined){ return null; } var me = GLOBAL[channel].tour; var typemsg = /single/i.test(me.type) ? "Single Elimination" : /double/i.test(me.type) ? "Double Elimination" : "Round-Robin"; var limitmsg = me.limit == 0 ? '∞' : me.limit - me.users.length; var margin = me.limit == 0 ? 5 : 4; return util.tableHeader("A tournament is starting", (GLOBAL[channel].color || "darkred"), 6, margin, false) + "" + limitmsg + "
slots" + me.tier + "" + "" + typemsg + "" + (me.limit == 0 ? "Remaining time to join: ~" + me.time + " seconds" : "") + "~~~~~~ Type /join to enter ~~~~~~
"; } this.message = function(data, channel){ if (GLOBAL[channel].tour == undefined){ return; } sys.sendHtmlAll("±" + GLOBAL[channel].tour.tier + " Tournament: " + data, channel); } this.showRound = function(channel){ if (this.getTourMode(channel) != 1){ return null; } var html = ""; if (/single|double/.test(GLOBAL[channel].tour.type)){ var margin = 1; for (var i=0;ivs." + (util.username(sys.id(GLOBAL[channel].tour.users[++i]) || GLOBAL[channel].tour.users[i])) + ""; } if (GLOBAL[channel].tour.users.length % 2 == 1){ margin++; html += "" + (util.username(sys.id(GLOBAL[channel].tour.users[GLOBAL[channel].tour.users.length-1])) || GLOBAL[channel].tour.users[GLOBAL[channel].tour.users.length-1]) + " does not fight this round..."; } if (GLOBAL[channel].tour.winners[GLOBAL[channel].tour.round] != undefined){ margin++; html += "~~~ Completed Matches ~~~"; for (var i=0;ivs." + (GLOBAL[channel].tour.losers[GLOBAL[channel].tour.round][i] == "" ? "No opponent." : "L: " + (util.username(sys.id(GLOBAL[channel].tour.losers[GLOBAL[channel].tour.round][i])) || GLOBAL[channel].tour.losers[GLOBAL[channel].tour.round][i])) + ""; } } var header = GLOBAL[channel].tour.users.length == 2 ? "Final Round: " : "Round " + (GLOBAL[channel].tour.round+1) + ": "; html = util.tableHeader(header + GLOBAL[channel].tour.tier, (GLOBAL[channel].color || "darkred"), 7, margin, false) + html + "
"; } else if (/round/.test(GLOBAL[channel].tour.type)){ html = util.tableHeader("Remaining Battles: " + GLOBAL[channel].tour.remaining, (GLOBAL[channel].color || "darkred"), 3, (GLOBAL[channel].tour.users.length+2), false) + "[Score] PlayerRemaining Opponents"; for (var i=0;i] " + (util.username(sys.id(n)) || n) + ":"; var someone = false; for (var j=0;j 0 && GLOBAL[channel].tour.users.length == GLOBAL[channel].tour.limit){ this.modeBattle(channel); } } this.removeUser = function(user, channel, forced){ var message = forced ? " has been removed from the tournament." : " has left the tournament."; if (this.getTourMode(channel) == 0){ GLOBAL[channel].tour.users.splice(GLOBAL[channel].tour.users.indexOf(user), 1); this.message((util.username(sys.id(user)) || user) + message + (GLOBAL[channel].tour.limit > 0 ? " " + (GLOBAL[channel].tour.limit - GLOBAL[channel].tour.users.length) + " spots remaining." : ""), channel); } else { var index = this.index(user, channel); if (/single|double/.test(GLOBAL[channel].tour.type)){ if (index != -1){ var index2 = index % 2 == 0 ? index+1 : index-1; this.message(GLOBAL[channel].tour.users[index] + message, channel); this.advance(GLOBAL[channel].tour.users[index2], GLOBAL[channel].tour.users[index], channel); } else { var round = GLOBAL[channel].tour.round; index = GLOBAL[channel].tour.winners[round].indexOf(src); if (index != -1){ this.message(GLOBAL[channel].tour.winners[round][index] + message, channel); GLOBAL[channel].tour.winners[round].splice(index, 1); GLOBAL[channel].tour.losers[round].splice(index, 1); if (GLOBAL[channel].tour.winners[round].length == 0){ delete GLOBAL[channel].tour.winners[round]; delete GLOBAL[channel].tour.losers[round]; } } } } else if (/round/.test(GLOBAL[channel].tour.type)){ var rem = 0; for (var i=0;i/viewmatches to see remaining battles.", channel); GLOBAL[channel].tour.mode = 1; } else { if (GLOBAL[channel].tour.users.length == 1){ this.modeWinner(channel); } else { GLOBAL[channel].tour.mode = 1; sys.sendHtmlAll(this.showRound(channel), channel); if (GLOBAL[channel].tour.users.length % 2 == 1){ var bye = GLOBAL[channel].tour.users[GLOBAL[channel].tour.users.length-1]; this.advance(bye, "", channel); } } } } this.nextRound = function(channel){ if (/single|double/.test(GLOBAL[channel].tour.type)){ GLOBAL[channel].tour.users = GLOBAL[channel].tour.winners[GLOBAL[channel].tour.round++]; if (GLOBAL[channel].tour.users.length == 1){ this.modeWinner(channel); } else { this.modeBattle(channel); } } else if (/round/.test(GLOBAL[channel].tour.type)){ this.makeScoreboard(channel); } } this.modeWinner = function(channel){ if (/single|double/.test(GLOBAL[channel].tour.type)){ this.message("Congratulations, " + (util.username(sys.id(GLOBAL[channel].tour.users[0])) || GLOBAL[channel].tour.users[0]) + " has won the tournament!", channel); } else { var users, max = -1; for (var i in GLOBAL[channel].tour.scoreboard){ var sum = this.getScore(i, channel); if (sum > max){ max = sum; users = [i]; } else if (sum == max && max > 0){ users.push(i); } } if (users.length == 1){ this.message("Congratulations, " + (util.username(sys.id(users[0])) || users[0]) + " has won the tournament with " + max + " points!", channel); } else { GLOBAL[channel].tour.users = users; GLOBAL[channel].tour.tiebreaker = max; GLOBAL[channel].tour.remaining = (users.length/2)*(users.length-1); this.nextRound(channel); var message = "There is a " + (users.length > 2 ? users.length + "-way tie" : "tie") + " between "; for (var i=0;i 0){ message += " " + remaining+ " match" + (remaining == 1 ? "" : "es") + " remaining."; } else { if (GLOBAL[channel].tour.users.length > 2){ message += " Round " + (GLOBAL[channel].tour.round+1) + " of the tournament is complete."; } } this.message(message, channel); } if (GLOBAL[channel].tour.winners[round] == undefined){ GLOBAL[channel].tour.winners[round] = []; } GLOBAL[channel].tour.winners[round].push(winner); if (GLOBAL[channel].tour.losers[round] == undefined){ GLOBAL[channel].tour.losers[round] = []; } GLOBAL[channel].tour.losers[round].push(loser); if (GLOBAL[channel].tour.users.length == 0){ this.nextRound(channel); } } else if (/round/.test(GLOBAL[channel].tour.type)){ GLOBAL[channel].tour.remaining--; GLOBAL[channel].tour.scoreboard[winner][loser] = 3; GLOBAL[channel].tour.scoreboard[loser][winner] = 0; this.message(("[" + (this.getScore(winner, channel)) + "]" + util.username(sys.id(winner)) || winner) + " has won a match against [" + (this.getScore(loser, channel)) + "]" + (util.username(sys.id(loser)) || loser) + ". " + GLOBAL[channel].tour.remaining + " battle" + (GLOBAL[channel].tour.remaining == 1 ? "" : "s") + " remaining.", channel); if (GLOBAL[channel].tour.remaining == 0){ this.modeWinner(channel); } } } this.rematch = function(user1, user2, channel){ if (/single|double/.test(GLOBAL[channel].tour.type)){ this.message("The battle between " + (util.username(sys.name(user1)) || user1) + " and " + (util.username(sys.name(user2)) || user2) + " was a tie; please battle again.", channel); } else if (/round/.test(GLOBAL[channel].tour.type)){ GLOBAL[channel].tour.remaining--; GLOBAL[channel].tour.scoreboard[user1][user2] = 1; GLOBAL[channel].tour.scoreboard[user1][user2] = 1; if (GLOBAL[channel].tour.remaining == 0){ this.modeWinner(channel); } } } this.tour = function(src, channel, data){ var slots, tier, type = "single"; data = data.split(" "); if (data.length < 1){ util.failParameters(src, channel); return; } var arg = data.shift(); if (isNaN(parseInt(arg))){ type = arg.toLowerCase(); arg = data.shift(); } slots = parseInt(arg); if (isNaN(slots)){ sys.sendMessage(src, "Invalid number of slots...", channel); return; } if (/double/.test(type)){ sys.sendMessage(src, "Sorry, double elimination hasn't been written yet...", channel); return; } if (!/^single|double|round$/.test(type)){ sys.sendMessage(src, "Not a valid tournament type. Must be one of 'single', 'double', or 'round'", channel); return; } tier = data.join(" "); if (!tier){ tier = "OverUsed"; } var n, tiers = sys.getTierList(); if ((n = tiers.indexOf(tier, true)) == -1){ sys.sendMessage(src, tier + " is an invalid tier; check the Tier menu for valid options.", channel); return; } if (slots == 2 || slots == 1){ sys.sendMessage(src, "A tournament with less than 3 users doesn't really make sense...", channel); return; } this.modeEntry(src, channel, type, tiers[n], slots); if (slots == 0){ this.timer(channel, true); } } this.timer = function(channel, nomessage){ if (this.getTourMode(channel) != 0){ return; } if (GLOBAL[channel].tour.time == 0){ this.starttour(-1, channel, "", true); } else { if (!(nomessage === true)){ this.message(GLOBAL[channel].tour.time + " seconds remaining...", channel); } GLOBAL[channel].tour.time -= 30; sys.callLater("GLOBAL.modules['Tournament'].timer("+ channel + ")", 30); } } this.join = function(src, channel, data){ if (this.getTourMode(channel) != 0){ sys.sendMessage(src, "A tournament is not in the sign-up phase.", channel); return; } var message = util.parseMessage(0, data, true, false); if (!message){ util.failParameters(src, channel); return; } var forced = false; if (message.users.length == 0){ if (data){ sys.sendMessage(src, "User does not exist or you do not have permission for that.", channel); return; } if (this.index(sys.name(src), channel) == -1){ message.users.push(src); } else { sys.sendMessage(src, "You are already in this tournament...", channel); return; } } else if (!util.isAuth(src, channel)){ util.failPermission(src, channel); return; } else { forced = true; } for (var i=0;i" + n + ".", channel); if (n == GLOBAL[channel].tour.users.length){ this.starttour(src, channel, "", true); } else { GLOBAL[channel].tour.limit = n; } } this.tourswap = function(src, channel, data){ if (this.getTourMode < 1){ sys.sendMessage(src, "There is no tournament running...", channel); return; } var message = util.parseMessage(0, data, true, false); if (!message || message.users.length != 2){ util.failParameters(src, channel); return; } var user1 = message.offline ? message.users[0] : sys.name(message.users[0]); var user2 = message.offline ? message.users[1] : sys.name(message.users[1]); var u1index = this.index(user1, channel); var u2index = this.index(user2, channel); if (/single|double/.test(GLOBAL[channel].tour.type)){ if (u1index != -1 && u2index != -1){ if (Math.abs(u2index-u1index) == 1 && Math.max(u1index, u2index) % 2 == 1){ sys.sendMessage(src, "Uhh, these users are already matched up; swapping will have no effect.", channel); return; } GLOBAL[channel].tour.users[u1index] = user2; GLOBAL[channel].tour.users[u2index] = user1; } else if (u1index != -1){ u2index = GLOBAL[channel].tour.winners[GLOBAL[channel].tour.round].indexOf(user2); if (u2index != -1){ GLOBAL[channel].tour.winners[GLOBAL[channel].tour.round][u2index] = user1; } GLOBAL[channel].tour.users[u1index] = user2; } else if (u2index != -1){ u1index = GLOBAL[channel].tour.winners[GLOBAL[channel].tour.round].indexOf(user1); if (u1index != -1){ GLOBAL[channel].tour.winners[GLOBAL[channel].tour.round][u1index] = user2; } GLOBAL[channel].tour.users[u2index] = user1; } else { sys.sendMessage(src, "Sorry, neither user is in the tournament.", channel); return; } this.message((util.username(sys.id(user1)) || user1) + " has been swapped with " + (util.username(sys.id(user2)) || user2) + ". See /viewmatches for the new matchups.", channel); } else { sys.sendMessage(src, "Sorry, /tourswap is not supported for this tournament type at this time...", channel); } } this.tour.help = ["type slots tier", "Starts a tournament. Type is optional and one of single, double, or round.", "If slots is 0, then the tournament will be open to all sign-ups: anyone can join and the tournament will automatically start after 90 seconds. If invalid or no tier provided; defaults to OverUsed."]; this.starttour.help = ["", "Starts the tournament with the current number of users."]; this.endtour.help = ["", "Ends the current tournament."]; this.tourswap.help = ["user1 user2", "Swaps users in the tournament."]; this.toursize.help = ["size", "Changes the size of the tournament.", "New size must be at least 3 and at least as large as the current number of sign-ups."]; this.join.help = ["user", "Joins the tournament.", "If user provided, adds user to tournament."]; this.leave.help = ["user", "Leaves the tournament.", "If user provided, removes user from tournament."]; this.viewmatches.help = ["", "Displays the matches for the current tournament round."]; } /* }}} */ /* {{{ Util: Miscellaneous functions for whatevs and such */ var util = new function(){ this.parseMessage = function(argc, message, offline, channel){ var data = {args: [], users: [], offline: false}; if (argc == -1){ data.args = message.split(" "); return data; } message = message.split(" "); for (var i=0;i" + this.escapeHtml(sys.name(src)) + ""; } this.header = function(src){ return "" + (sys.auth(src) > 0 && sys.auth(src) < 4 ? "+" : "") + "" + sys.name(src) + ":" + (sys.auth(src) > 0 && sys.auth(src) < 4 ? "" : "") + " "; } this.tableHeader = function(title, color, colspan, margin, wrap){ var html = ""; if (!wrap){ html = html.replace(/>$/, " style='white-space: nowrap;'>"); } html += ""; return html; } this.escapeHtml = function(str){ if (typeof(str) == "string"){ return str.replace(/&/g, "&").replace(//g, ">"); } } this.isAuth = function(src, channel){ if (sys.auth(src) > 0){ return sys.auth(src); } if (src == GLOBAL[channel].chanOp){ return -1; } return 0; } this.tellOthers = function(auth, channel, message){ var players = (channel == -1 ? sys.loggedIn() : sys.playersOfChannel(channel)); for (var i=0;i= auth || players[i] == GLOBAL[channel].chanOp){ sys.sendHtmlMessage(players[i], message, channel); } } } this.failUsers = function(src, channel){ sys.sendMessage(src, "Sorry, no matching user(s) found...", channel); } this.failParameters = function(src, channel){ sys.sendMessage(src, "Your arguments are suckful or nonexist or something", channel); } this.failMuted = function(src, channel){ sys.sendMessage(src, "Oh looky, you're muted. Stop doing things.", channel); } this.failCommand = function(src, channel){ sys.sendMessage(src, "Hmm, that's not a command or you don't have permissions or something of that sort.", channel); } this.failBlacklisted = function(src, channel){ sys.sendMessage(src, "Sorry, that command has been blacklisted.", channel); } this.failPermission = function(src, channel){ sys.sendMessage(src, "Sorry, you do not have permission to do that...", channel); } }(); /* }}} */ function include(m){ var module = eval("new " + m + "();"); GLOBAL.modules[m] = module; if (module.init != undefined){ module.init(); } } function register(auth, name, module){ if (module == undefined){ return false; } GLOBAL.calls[auth][name] = module; GLOBAL.calls[auth][name][name].authonly = false; for (var i=3;i 3 ? 3 : auth);i>=0;i--){ if ((module = GLOBAL.calls[i][call]) != undefined){ if (src == GLOBAL[channel].chanOp && sys.auth(src) < i){ if (module[call].authonly){ util.failCommand(src, channel); return true; } } else if (helper("isBlacklisted", channel, call) && sys.auth(src) == i){ util.failBlacklisted(src, channel); return true; } message.shift(); module[call](src, channel, message.join(" ")); return true; } } util.failCommand(src, channel); return true; } return false; } function helper(func){ var args = Array.prototype.slice.call(arguments); args.shift(); if (!(func in GLOBAL.helpers)){ return null; } return GLOBAL.helpers[func][func].apply(GLOBAL.helpers[func], args); } function callhooks(type){ /* Remove first arg as it's the hook name and not a parameter */ var retval = false; var args = Array.prototype.slice.call(arguments); args.shift(); if (type in GLOBAL.hooks){ for (var i=0;i
   ~~~ " + title + " ~~~