Documente Academic
Documente Profesional
Documente Cultură
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");
include("Queue");
}
Array.prototype.indexOf = function(item, insensitive){
for (var i=0;i<this.length;i++){
if (this[i] == item || (insensitive && typeof(this[i]) == "string" && th
is[i].toLowerCase() == item.toLowerCase())){
return i;
}
}
return -1;
}
Array.prototype.shuffle = function(){
for (var i=0;i<this.length;i++){
var tmp = this[i];
var pt = sys.rand(0, this.length);
this[i] = this[pt];
this[pt] = tmp;
}
}
/* {{{ Automod Module: Provides basic flood control methods */
function Automod(){
this.init = function(){
register(1, "automod", this, "am");
register(1, "resetautomod", this);
hook("afterChannelJoin", this);
hook("beforeChannelCreated", this);
hook("afterChatMessage", this);
hook("beforeCommands", this);
hook("afterLogIn", this);
}
this.create = function(){
return {lastmessage: 0, flood: 0, kicks: 0, join: 0};
}
this.preflood = function(src, channel, data){
var auth = util.isAuth(src, channel);
if (auth > 2){
return false;
} else if (/[\u2028\u2029\u200E\u200F\u202A\u202B\u202C\u202D\u202E]/.te
st(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){
if (util.isEvent(src)){
return;
}
var ip = sys.ip(src);
GLOBAL[channel].automod[ip].flood = 0;
GLOBAL[channel].automod[ip].lastmessage = 0;
GLOBAL[channel].automod[ip].kicks++;
/* Just mute the first few times... */
if (GLOBAL[channel].automod[ip].kicks < 3){
if (helper("changeMuteVal", -1, src, util.isOffline(src), channel, 2
)){
sys.sendHtmlAll("<" + src + "><font color='" + (GLOBAL[channel].
color || "darkblue") + "'><timestamp/><b>±Flood Notice: </b></font>" + (util.usern
ame(src) || util.escapeHtml(sys.name(src))) + " has been muted for overactivity.
", channel);
if (!util.isOffline(src)){
sys.sendMessage(src, "PM an admin/mod when you feel like bei
ng less spammy. In the meantime, feel free to start a separate channel and talk
there.", channel);
}
} else {
util.tellOthers(1, channel, "Overactive user " + sys.name(src) +
" could not be muted; Mute module not enabled.");
}
} else {
/* Ban hammar! */
if (GLOBAL[channel].automod[ip].kicks > 4){
if (channel == 0){
helper("changeMuteVal", -1, sys.name(src), true, 0, 0);
sys.ban(sys.name(src));
GLOBAL[channel].automod[ip].kicks = 0;
sys.sendHtmlAll("<" + src + "><font color='" + (GLOBAL[chann
el].color || "red") + "'><b>" + (util.username(src) || util.escapeHtml(sys.name(
src))) + " has been banned for overactivity.</b></font>", channel)
} else {
if (helper("autoban", src, channel)){
GLOBAL[channel].automod[ip].kicks = 0;
}
}
/* Kick kick kick */
} else {
sys.sendHtmlAll("<" + src + "><font color='" + (GLOBAL[channel].
color || "orange") + "'><timestamp/><b>±Flood Notice: </b></font>" + (util.usernam
e(src) || util.escapeHtml(sys.name(src))) + " has been kicked for overactivity."
, channel);
}
util.setEvent(src, true);
if (channel == 0){
sys.callQuickly("sys.kick(" + src + ")", 100);
} else {
sys.callQuickly("sys.kick(" + src + ", " + channel + "); util.se
tEvent(" + src + ", false)", 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;i<message.users.length;i++){
var ip = util.isOffline(message.users[i]) ? sys.dbIp(message.users[i
]) : sys.ip(message.users[i]);
if (GLOBAL[channel].automod[ip] != undefined){
var oldjoin = GLOBAL[channel].automod[ip].join;
GLOBAL[channel].automod[ip] = this.create();
GLOBAL[channel].automod[ip].join = oldjoin;
}
if (channel == 0){
sys.removeVal("automod.reg", ip);
}
util.tellOthers(1, channel, sys.name(src) + " has cleared automod da
ta for " + (util.isOffline(message.users[i]) ? message.users[i] : sys.name(messa
ge.users[i])));
}
}
this.automod = function(src, channel, data){
switch(data.toLowerCase()){
case "off":
GLOBAL[channel].automod[0].flood = 0;
util.tellOthers(1, channel, (sys.name(src) || "The channel") + "
has turned off the automod.");
return;
case "light":
GLOBAL[channel].automod[0].flood = 10;
break;
case "medium":
GLOBAL[channel].automod[0].flood = 7;
break;
case "heavy":
GLOBAL[channel].automod[0].flood = 5;
break;
default:
var l = GLOBAL[channel].automod[0].flood;
sys.sendHtmlMessage(src, "Current automod level: <b>" + (l == 0
? "off" : l == 5 ? "heavy" : l == 7 ? "medium": "light") + "</b>", channel);
return;
}
GLOBAL[channel].automod[0].title = data;
util.tellOthers(1, channel, (sys.name(src) || "The channel") + " has set
the automod to " + data);
}
this.beforeCommands = function(src, message, channel){
if (this.preflood(src, channel, message)){
sys.stopEvent();
if (channel == 0){
sys.kick(src);
} else {
sys.kick(src, channel);
}
return true;
}
}
this.afterChatMessage = function(src, message, channel){
this.postflood(src, channel, message);
}
this.beforeChannelCreated = function(id, name, src){
GLOBAL[id].automod = {};
GLOBAL[id].automod[0] = {flood: 0};
}
this.afterLogIn = function(src){
this.afterChannelJoin(src, 0);
}
this.afterChannelJoin = function(src, channel){
var ip = sys.ip(src);
if (GLOBAL[channel].automod[ip] == undefined){
GLOBAL[channel].automod[ip] = this.create();
GLOBAL[channel].automod[ip].join = sys.time();
}
if (channel == 0){
var oldkicks = parseInt(sys.getVal("automod.reg", ip));
if (!isNaN(oldkicks)){
GLOBAL[channel].automod[ip].kicks = oldkicks;
}
}
}
this.automod.help = ["level", "Sets the automod level.", "Valid levels are <
i>off</i>, <i>light</i>, <i>medium</i>, and <i>heavy</i>. 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. If no level provided, display the
current automod status."];
this.resetautomod.help = ["user", "Clears automod data for user.", "User's f
lood 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 += "<tr><td>Nothing blacklisted.</td></tr>";
margin++;
} else {
GLOBAL[channel].blacklist.sort();
for (var i=0;i<GLOBAL[channel].blacklist.length;i++){
html += "<tr><td><b>/" + GLOBAL[channel].blacklist[i] + "</b></t
d></tr>";
margin++;
}
}
html = util.tableHeader("Blacklist", (GLOBAL[channel].color || "darkred"
), 1, margin, false) + html + "</table><br/>";
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<data.length;i++){
if (command = /[!\/]?(.+)/.exec(data[i])){
command = translate(command[1]);
if (GLOBAL[channel].blacklist == undefined){
GLOBAL[channel].blacklist = [];
}
if (GLOBAL[channel].blacklist.indexOf(command) != -1){
sys.sendMessage(src, "/" + command + " is already blackliste
d.", channel);
err = true;
continue;
} else {
var auth = util.isAuth(src, channel);
var auth = auth > 3 ? 3 : auth == -1 ? 2 : auth;
for (var j=0;j<auth;j++){
if (command in GLOBAL.calls[j] && !(GLOBAL.calls[j][comm
and][command].authonly)){
something.push(command);
GLOBAL[channel].blacklist.push(command);
break;
}
}
}
}
}
if (GLOBAL[channel].blacklist.length == 0){
delete GLOBAL[channel].blacklist;
}
if (something.length == 0){
if (!err){
sys.sendMessage(src, "Either one of the commands does not exist
or you do not have the auth required to blacklist it.", channel);
}
} else {
util.tellOthers(1, channel, sys.name(src) + " has blacklisted: /" +
something.join(", /"));
}
}
this.whitelist = function(src, channel, data){
var command, index, something = [], err = false;
if (data == ""){
this.showBlacklist(src, channel);
return;
}
data = data.split(" ");
if (GLOBAL[channel].blacklist == undefined){
sys.sendMessage(src, "There is nothing blacklisted... cannot whiteli
st.", channel);
return;
}
for (var i=0;i<data.length;i++){
if (command = /[!\/]?(.*)/.exec(data[i])){
command = translate(command[1]);
index = GLOBAL[channel].blacklist.indexOf(command);
if (index != -1){
var auth = util.isAuth(src, channel);
var auth = auth > 3 ? 3 : auth == -1 ? 2 : auth;
for (var j=0;j<auth;j++){
if (command in GLOBAL.calls[j] && !(GLOBAL.calls[j][comm
and][command].authonly)){
something.push(GLOBAL[channel].blacklist.splice(inde
x, 1));
break;
}
}
}
}
}
if (GLOBAL[channel].blacklist.length == 0){
delete GLOBAL[channel].blacklist;
}
if (something.length == 0){
sys.sendMessage(src, "Either one of the commands does not exist or y
ou do not have the auth required to whitelist it.", channel);
} else {
util.tellOthers(1, channel, sys.name(src) + " has whitelisted: /" +
something.join(", /"));
}
}
this.blacklist.help = ["command", "Prevents usage of commands.", "Multiple c
ommands can be specified, and the leading / or ! is optional. If no command is g
iven, shows a list of currently-blacklisted commands."];
this.whitelist.help = ["command", "Allows usage of commands.", "Multiple com
mands can be specified, and the leading / or ! is optional. If no command is giv
en, shows a list of currently-blacklisted commands."];
} /* }}} */
/* {{{ Channels Module: Provides commands for moderating channels */
function Channels(){
this.init = function(){
register(0, "topic", this);
register(1, "kick", this, "k");
register(1, "silentkick", this, "sk");
register(1, "setkick", this);
register(1, "clearkick", this);
register(1, "cleartopic", this);
register(1, "setcolor", this, "color");
register(2, "ban", this, "b");
register(2, "unban", this);
register(2, "private", this, "authy");
authregister(1, "invite", this);
helperregister("autoban", this);
hook("beforeChannelJoin", this);
hook("afterChannelJoin", this);
hook("beforeChannelCreated", this);
}
this.autoban = function(channel, user){
this.ban(0, channel, sys.name(user));
return true;
}
this.isChannelBanned = function(src, channel){
if (typeof(src) == "number" && util.isAuth(src, channel)){
return false;
}
var ip = (typeof(src) == "string" ? sys.dbIp : sys.ip)(src);
if (GLOBAL[channel].ban == undefined){ return false; }
return GLOBAL[channel].ban.indexOf(ip) != -1;
}
this.showTopic = function(channel){
if (GLOBAL[channel].topic != undefined){
return "<font color='" + (GLOBAL[channel].color || "orange") + "'><t
imestamp/><b>±Topic: </b></font>" + 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;
}
for (var i=0;i<message.users.length;i++){
if (util.isEvent(message.users[i])){
continue;
}
if (sys.auth(src) <= sys.auth(message.users[i])){
sys.sendMessage(src, sys.name(message.users[i]) + "'s auth level
is at or above your own; cannot kick.", channel);
continue;
}
if (kickmessage){
sys.sendHtmlAll(kickmessage.replace(/%s/g, util.escapeHtml(sys.n
ame(message.users[i]))), channel);
} else {
util.tellOthers(1, channel, sys.name(src) + " has silently kicke
d " + sys.name(message.users[i]));
}
util.setEvent(message.users[i], true);
if (channel == 0){
sys.callQuickly("sys.kick(" + message.users[i] + ")", 100);
} else {
sys.callQuickly("sys.kick(" + message.users[i] + ", " + channel
+ "); util.setEvent(" + message.users[i] + ", false);", 100);
}
}
return;
}
this.clearkick = function(src, channel, data){
if (sys.auth(src) > 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...", chan
nel);
} 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) || da
ta;
GLOBAL[channel].topic = GLOBAL[channel].topic.replace(/%s/g, old);
if (channel == 0){
sys.saveVal("topic", GLOBAL[channel].topic);
}
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 = "<" + src + "><font color='" + color + "'><b>" + sys.name(
src) + (/^'/.test(data) ? "" : " ") + util.escapeHtml(data) + "</b></font>";
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 = "<" + src + "><font color='" + (GLOBAL[channel].color || "
red") + "'><b>" + sys.name(src) + " has kicked %s to death. He might not be Reb
orn.</font></b>";
}
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..", c
hannel);
}
return;
}
for (var i=0;i<message.users.length;i++){
trgt = (util.isOffline(message.users[i]) ? message.users[i] : sys.na
me(message.users[i]));
ip = (util.isOffline(message.users[i]) ? sys.dbIp : sys.ip)(messag
e.users[i]);
auth = (util.isOffline(message.users[i]) ? sys.dbAuth : sys.auth)(me
ssage.users[i]);
if ((!util.isOffline(message.users[i]) && util.isAuth(message.users[
i], channel)) || (auth > 0)){
if (src != 0){
sys.sendMessage(src, "No banning the authy-flavored or chanO
py-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("<" + src + "><font color='" + (GLOBAL[channel].
color || "red") + "'><b>" + (sys.name(src) == "" ? trgt + " has been banned" : s
ys.name(src) + " has banned " + trgt) + ".</font></b>", channel);
helper("changeMuteVal", -1, trgt, true, 0, 0);
sys.ban(trgt);
if (!util.isOffline(message.users[i])){
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...", cha
nnel);
}
continue;
}
GLOBAL[channel].ban.push(ip);
sys.sendHtmlAll("<" + src + "><font color='" + (GLOBAL[channel].
color || "red") + "'><b>" + (sys.name(src) == "" ? trgt + " has been banned" : s
ys.name(src) + " has banned " + trgt) + ".</font></b>", channel);
if (!util.isOffline(message.users[i])){
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..", cha
nnel);
return;
}
if (message.users.length == 0){
util.failUsers(src, channel);
return;
}
for (var i=0;i<message.users.length;i++){
trgt = (util.isOffline(message.users[i]) ? message.users[i] : sys.na
me(message.users[i]));
ip = (util.isOffline(message.users[i]) ? sys.dbIp : sys.ip)(messag
e.users[i]);
if (channel == 0){
if (sys.banList().indexOf(trgt, true) == -1){
sys.sendMessage(src, trgt + " is not banned; cannot unban.",
channel);
return;
}
util.tellOthers(1, channel, sys.name(src) + " has unbanned " + t
rgt);
sys.unban(trgt);
} else {
if (!this.isChannelBanned(message.users[i], channel)){
sys.sendMessage(src, "Looks like " + trgt + " isn't banned..
.", channel);
break;
}
index = GLOBAL[channel].ban.indexOf(ip);
if (index != -1){
delete GLOBAL[channel].ban[j];
util.tellOthers(1, channel, sys.name(src) + " has unbanned "
+ trgt);
}
if (GLOBAL[channel].ban.length == 0){
delete GLOBAL[channel].ban;
}
}
}
}
this.setcolor = function(src, channel, data, nomessage){
if (!data){
sys.sendHtmlMessage(src, "Current channel color: <b><font color='" +
(GLOBAL[channel].color || "black") + "'>" + (GLOBAL[channel].color || "(None)")
+ "</font></b>", channel);
return;
}
data = data.split(" ");
if (data.length > 1){
util.failParamters(src, channel);
return;
}
if (!(/#[A-Fa-f0-9]{1,6}|\w+/.test(data[0]))){
data[0] = "black";
}
data[0] = data[0].replace(/'/g, "");
GLOBAL[channel].color = data[0];
if (!(nomessage === true)){
util.tellOthers(2, channel, sys.name(src) + " has changed the colort
heme to <b><font color='" + (data[0] || "black") + "'>" + data[0] + "</font></b>
");
}
}
this.private = function(src, channel, data){
if (channel == 0){
sys.sendMessage(src, "Sorry, /private cannot be used in the main cha
nnel.", channel);
return;
}
var msg;
if (GLOBAL[channel].private == undefined){
var msg;
data = util.parseMessage(0, data, false, true);
if (data.users.indexOf(0) == -1){
GLOBAL[channel].private = 1;
msg = "The channel is now auth-only; all non-auth users are bein
g removed.";
} else {
GLOBAL[channel].private = 2;
msg = "The channel is now private; all non-invited people are be
ing removed.";
}
var players = sys.playersOfChannel(channel);
for (var i=0;i<players.length;i++){
if (players[i] == src){
continue;
} else if (GLOBAL[channel].private == 2 || !util.isAuth(players[
i], channel)){
if (!data || data.users.indexOf(players[i]) == -1){
sys.kick(players[i], channel);
}
}
}
} else {
delete GLOBAL[channel].private;
msg = "Private channel times is over...";
}
sys.sendHtmlAll("<font color='" + (GLOBAL[channel].color || "purple") +
"'><timestamp/><b>±Private Channel Notice:</b></font> " + 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 = [];
var temp = 0;
if (GLOBAL[channel].private != undefined){
var temp = GLOBAL[channel].private;
delete GLOBAL[channel].private;
}
for (var i=0;i<message.users.length;i++){
if (!sys.isInChannel(message.users[i], channel)){
sys.putInChannel(message.users[i], channel);
somebody.push(sys.name(message.users[i]));
}
}
if (temp){
GLOBAL[channel].private = temp;
}
if (somebody.length == 0){
util.failUsers(src, channel);
} else {
util.tellOthers(1, channel, sys.name(src) + " has /invite'ed " + som
ebody.join(", "));
}
}
} /* }}} */
/* {{{ 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 += "<tr><td align='center'>" + util.escapeHtml(map) + ": " + (h
elper("markdown", src, channel, GLOBAL[mychannel].maps[ip][map]) || GLOBAL[mycha
nnel].maps[ip][map]) + "</tr>";
}
if (!html){
sys.sendMessage(src, "No maps defined.", channel);
return;
}
html = util.tableHeader("Maps", GLOBAL[channel].color || "green", 1, mar
gin, true) + html + "</table><br/>";
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.", c
hannel);
}
}
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.", chan
nel);
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][m
ap]);
}
if (newdata != data){
if (!callhooks("beforeCommands", src, newdata, channel, true)){
if (!command(src, newdata, channel)){
if (!callhooks("beforeChatMessage", src, newdata, channel)){
sys.sendHtmlAll("<" + src + ">" + util.header(src) + uti
l.escapeHtml(newdata), channel);
}
}
}
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 wor
d, 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<mytypes.length;i++){
if (mytypes[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 no
t 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.", chann
el);
}
}
} /* }}} */
/* {{{ 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);
helperregister("changeMuteVal", this);
}
this.MUTEREG = "/srv/pokemon/.config/muted.reg.conf"
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);
}
util.tellOthers(1, channel, sys.name(src) + " has " + message +
" offline user " + trgt);
} else {
sys.sendMessage(src, "Sorry, only auths can mute offline users."
, channel);
}
return true;
}
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 true;
} else if (prev == level && src != -1){
sys.sendMessage(src, (trgt == 0 ? "The channel" : sys.name(trgt)) +
" is already " + message, channel);
return true;
}
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("<font color='" + (GLOBAL[channel].color || "purple"
) + "'><timestamp/><b>±Mute Notice:</b></font> The channel has been " + message, c
hannel);
} else {
if (src != -1){
util.tellOthers(1, channel, sys.name(src) + " has " + message +
" " + sys.name(trgt));
}
}
return true;
}
this.showMuted = function(src, channel){
var html = "", margin = 1;
var m = this.getMuteVal(0, channel);
if (m){
html += "<tr><td><b>The channel is currently " + (m == 2 ? "muted."
: "eventmuted.") + "</b></td></tr>";
margin++;
}
var users = sys.playersOfChannel(channel);
for (var i=0;i<users.length;i++){
if ((m = this.getMuteVal(users[i], channel)) != 0){
html += "<tr><td>" + util.username(users[i]) + "</td><td>" + (m
== 1 ? " (evilmuted)" : (m == 3 ? " (eventmuted)" : "")) + "</td></tr>";
margin++;
}
}
/* Offline mute users */
if (channel == 0){
var regex = /Script_([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})
=([0-9])/;
file = sys.getFileContent(this.MUTEREG);
if (file){
var lines = file.split("\n");
for (var i=0; i<lines.length; i++){
var user = regex.exec(lines[i]);
if (user){
var name = sys.aliases(user[1]);
if (name && name.length > 0){
name = name[0];
} else {
continue;
}
var m = parseInt(user[2]);
html += "<tr><td>" + name + "</td><td>" + (m == 1 ? " (e
vilmuted)" : (m == 3 ? " (eventmuted)" : "")) + " [Offline]</td></tr>";
margin++;
}
}
}
}
if (html == ""){
html += "<tr><td>Nobody's muted...</td></tr>";
margin++;
}
html = util.tableHeader("Mute List", (GLOBAL[channel].color || "darkblue
"), 2, margin, false) + html + "</table><br/>";
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, true, true)) == null){ return
; }
if (trgts.users.length == 0){
util.failUsers(src, channel);
return;
}
for (var i=0;i<trgts.users.length;i++){
if (trgts.users[i] != 0 && (auth = util.isOffline(trgts.users[i]) ?
sys.dbAuth(trgts.users[i]) : sys.auth(trgts.users[i])) > 0){
sys.sendMessage(src, "User " + (util.isOffline(trgts.users[i]) ?
trgts.users[i] : sys.name(trgts.users[i])) +
" is authy; cannot be muted.", channel);
} else {
this.changeMuteVal(src, trgts.users[i], util.isOffline(trgts.use
rs[i]), 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 === false){
return;
}
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 = "<font color='" + (GLOBAL[channel].color || "blue") +
"'><timestamp/><b>±Mute Notice:</b></font> 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 provid
ed, shows all muted people online. If channel ID is provided (/mute *0), a chann
el-wide mute occurs."];
this.eventmute.help = ["user", "Prevents user from using events.", "If no us
er provided, shows all muted people online."];
this.evilmute.help = ["user", "Mute user without giving any indication of th
eir mutedness.", "If no user provided, shows all muted people online."];
this.unmute.help = ["user", "Remove all mute status from user.", "If no use
r 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<numcolors;i++){
colors.push("#"
+ sys.rand(100, 256).toString(16) // Red
+ sys.rand(100, 256).toString(16) // Green
+ sys.rand(100, 256).toString(16) // Blue
)
}
var html = "", count = 0;
for (var c=0;c<text.length;c++){
if (count == 0){
html += "<font color='" + colors[sys.rand(0, colors.length)] + "
'>";
}
html += util.escapeHtml(text[c]);
if (++count == limit){
html += "</font>";
count = 0;
}
}
if (count != 0){
html += "</font>";
}
return "<table cellpadding='12' cellspacing='0' width='100%' " +
"bgcolor='black' style='margin: -12'><tr><td><b>" + html +
"</b></td></tr></table>";
}
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, c
hannel) == 1)){
return false;
}
if (/^\/nightclub$/.test(data) && util.isAuth(src, channel)){
if (this.toggle(channel)){
sys.sendHtmlAll("<br/>" + this.rainbowify("Let the Night Club co
mmence!"), channel);
} else {
sys.sendHtmlAll(this.rainbowify("Kay, Night Club times is over..
.") + "<br/>", channel);
}
sys.stopEvent();
return true;
} else if (GLOBAL[channel].nightclub){
sys.stopEvent();
sys.sendHtmlAll("<" + src + ">" + this.rainbowify("(" + sys.name(src
) + "): " + data), channel);
return true;
}
return false;
}
this.nightclub.help = ["", "Colors? Colors!", "Note that when enabled, all c
ommands (other than /nightclub) and flood-control are ignored."];
} /* }}} */
function Queue(){
this.init = function(){
register(0, "queue", this, "q");
register(1, "makequeue", this, "mq");
register(1, "endqueue", this, "eq");
hook("afterChannelJoin", this);
}
this.showQueue = function(channel, n, authy){
if (GLOBAL[channel].queues != undefined && GLOBAL[channel].queues.names[
n] != undefined){
return "<font color='" + (GLOBAL[channel].color || "blue") + "'><tim
estamp/><b>±" + (authy ? "[" + n + "] " : "") + GLOBAL[channel].queues.names[n] +
" Queue: </b></font>" + (GLOBAL[channel].queues.texts[n] || "(empty)");
}
return null;
}
this.afterChannelJoin = function(src, channel){
if (GLOBAL[channel].queues){
sys.callQuickly("GLOBAL.modules['Queue'].queue(" + src + ", " + chan
nel + ");", 150);
}
}
this.queue = function(src, channel, data){
if (!data){
if (GLOBAL[channel].queues == undefined){
sys.sendMessage(src, "No active queues...", channel);
return;
}
var n = 1;
var found = 0;
var displayed = 0;
while (found < GLOBAL[channel].queues.len){
if (GLOBAL[channel].queues.names[n] != undefined){
sys.sendHtmlMessage(src, this.showQueue(channel, n, util.isA
uth(src, channel)), channel);
found++;
}
n++;
}
return;
}
if (!util.isAuth(src, channel)){
util.failPermission(src, channel);
return;
}
if (GLOBAL[channel].queues == undefined){
sys.sendMessage(src, "No queues created. Use /makequeue to create a
new queue...", channel);
return;
}
var index;
try{
index = parseInt(data.split(" ")[0]);
} catch (e){
index = "";
}
if (!isNaN(index)){
if (GLOBAL[channel].queues.names[index] != undefined){
GLOBAL[channel].queues.srcs[src] = index;
sys.sendMessage(src, "Your default queue has been set to " + ind
ex + " (" + GLOBAL[channel].queues.names[index] + ").", channel);
} else {
sys.sendMessage(src, "Invalid queue ID; see /queues for availabl
e queues.", channel);
}
return;
}
data = data.replace(/^\\/, "");
if (data){
if (GLOBAL[channel].queues.srcs[src] == undefined || GLOBAL[channel]
.queues.names[GLOBAL[channel].queues.srcs[src]] == undefined){
sys.sendMessage(src, "You have no specified queue; please use /q
ueue [id] to specify a queue.", channel);
return;
}
var old = GLOBAL[channel].queues.texts[GLOBAL[channel].queues.srcs[s
rc]] || "";
GLOBAL[channel].queues.texts[GLOBAL[channel].queues.srcs[src]] = hel
per("markdown", src, channel, data) || util.escapeHtml(data);
GLOBAL[channel].queues.texts[GLOBAL[channel].queues.srcs[src]] = GLO
BAL[channel].queues.texts[GLOBAL[channel].queues.srcs[src]].replace(/%s/g, old);
sys.sendHtmlAll(this.showQueue(channel, GLOBAL[channel].queues.srcs[
src]), channel);
} else {
util.failParameters(src, channel);
}
}
this.makequeue = function(src, channel, data){
if (GLOBAL[channel].queues == undefined){
GLOBAL[channel].queues = {len: 0, srcs: {}, names: {}, texts: {}}
}
GLOBAL[channel].queues.len++;
var n = 1;
while (GLOBAL[channel].queues.names[n] != undefined){
n++;
}
GLOBAL[channel].queues.names[n] = data || n.toString();
GLOBAL[channel].queues.srcs[src] = n;
util.tellOthers(1, channel, "Queue " + GLOBAL[channel].queues.names[n] +
" (id: " + n + ") has been created.");
}
this.endqueue = function(src, channel, data){
if (GLOBAL[channel].queues == undefined){
sys.sendMessage(src, "No queues have been created; cannot delete.",
channel);
}
var index = GLOBAL[channel].queues.srcs[src];
if (data){
index = parseInt(data);
if (isNaN(index) || GLOBAL[channel].queues.names[index] == undefined
){
sys.sendMessage(src, "Invalid queue ID; see /queues for availabl
e queues.", channel);
return;
}
}
if (index == undefined){
sys.sendMessage(src, "You have no specified queue; please use /endqu
eue [id] to specify a queue.", channel);
return;
}
util.tellOthers(1, channel, "Queue " + GLOBAL[channel].queues.names[inde
x] + " has been deleted.");
delete GLOBAL[channel].queues.srcs[src];
delete GLOBAL[channel].queues.names[index];
delete GLOBAL[channel].queues.texts[index];
GLOBAL[channel].queues.len--;
if (GLOBAL[channel].queues.len <= 0){
delete GLOBAL[channel].queues;
}
}
this.queue.help = ["id|text", "List queues, changes default queue or updates
text.", "If no arguments, list all queues. If text needs to start with a number
, escape it with a preceeding backslash, like: /queue \\2"];
this.makequeue.help = ["name", "Creates a queue with the given name", "If na
me is not provided, a crappy name is used instead. Creating a queue also change
s your default queue to the queue being created."];
this.endqueue.help = ["id", "Deletes a queue.", "If no id provided, deletes
your default queue."];
}
/* {{{ Randoms Module: Provides random-username thingy, team-generator, etc. */
function Randoms(){
this.init = function(){
register(0, "roulette", this, "rng");
register(2, "pewpewpew", this);
register(2, "secret", this);
hook("beforeChatMessage", this);
hook("beforeMarkdown", this);
}
this.prettify = function(src, channel, data){
var users = util.playerIds();
var regex = /^\*([0-9]+)(.+)$/.exec(data);
var user = null;
if (regex){
data = regex[2];
user = parseInt(regex[1]);
if (!isNaN(user) && user > 0 && user < users.length){
user = users[user];
}
}
if (!user){
user = users[sys.rand(1, users.length)];
}
newdata = helper("markdown", src, channel, data);
if (newdata === false){
return;
} else if (newdata === null){
newdata = util.escapeHtml(data);
}
sys.sendHtmlAll("<" + src + ">" + util.header(user) + newdata.replace(/%
s/g, sys.name(user)), channel);
}
this.prettify2 = function(src, channel, data){
newdata = helper("markdown", src, channel, data);
if (newdata === false){
return;
} else if (newdata === null){
newdata = util.escapeHtml(data);
}
var site = sys.rand(0, 2) ? "http://reddit.com/random" : "http://sadpanc
ake.com/randwall";
sys.sendHtmlAll("<" + src + ">" + util.header(src) + "<font color='black
'>" + newdata.replace(/\.(?!\.|.*?<)/g, "<a href='" + site + "' style='text-deco
ration: none; color: black;'>.</a>") + "</font>", channel)
}
this.beforeChatMessage = function(src, data, channel){
if (GLOBAL[channel].pewpewpew){
sys.stopEvent();
this.prettify(src, channel, data);
return true;
} else if (GLOBAL[channel].secret){
sys.stopEvent();
this.prettify2(src, channel, data);
return true;
}
}
this.beforeMarkdown = function(src, channel){
return GLOBAL[channel].pewpewpew == true || GLOBAL[channel].secret == tr
ue;
}
this.pewpewpew = function(src, channel, data){
if (GLOBAL[channel].pewpewpew == undefined){
GLOBAL[channel].pewpewpew = true;
util.tellOthers(2, channel, "Pew pew pews!");
if (GLOBAL[channel].secret){
delete GLOBAL[channel].secret;
}
} else {
delete GLOBAL[channel].pewpewpew;
util.tellOthers(2, channel, "No more pew pew pews...");
}
}
this.secret = function(src, channel, data){
if (GLOBAL[channel].secret == undefined){
GLOBAL[channel].secret = true;
util.tellOthers(2, channel, "Secret stuff!");
if (GLOBAL[channel].pewpewpew){
delete GLOBAL[channel].pewpewpew;
}
} else {
delete GLOBAL[channel].secret;
util.tellOthers(2, channel, "No more secret stuffs...");
}
}
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 : parseI
nt(data);
for (var i=0, nums=[];i<limit;i++){
var n = valid[sys.rand(0, valid.length)];
nums.push(n + ". " + sys.pokemon(n));
}
sys.sendMessage(src, "Your numbers: " + nums.join(", "), channel);
}
this.pewpewpew.help = ["", "Pew pew pew!"];
this.roulette.help = ["n", "Generates n random numbers.", "If n is not provi
ded or invalid, defaults to 6."];
} /* }}} */
/* {{{ Server Module: Provides links and descriptions for all things Reborn, and
commands for server control */
function Server(){
this.STATUS = "status";
this.init = function(){
register(0, "reborn", this, "R");
register(0, "rules", this, "r");
register(0, "authlist", this, "al");
register(0, "selfkick", this, "pwnclone", "ghost");
register(0, "userlist", this, "ul");
register(0, "welcome", this);
register(1, "regex", this);
register(2, "chanop", this);
authregister(2, "idle", this);
authregister(2, "mod", this);
authregister(2, "reloadscript", this);
authregister(2, "announce", this, "an");
authregister(3, "eval", this);
authregister(3, "admin", this);
authregister(3, "status", this);
hook("afterLogIn", this);
}
this.message = function(src, channel, message, data, command){
if (!data){
sys.sendHtmlMessage(src, message, channel);
} else {
if (!util.isAuth(src, channel)){
util.failPermission(src, channel);
return;
}
var m = util.parseMessage(0, data, false, false);
if (!m){
util.failParameters(src, channel);
return;
} else if (m.users.length == 0){
util.failUsers(src, channel);
return;
}
for (var i=0;i<m.users.length;i++){
if (util.isAuth(m.users[i], channel)){
sys.sendMessage(src, "Pretty sure the authy people already k
now about this, no need to force it on them.", channel);
continue;
}
sys.sendHtmlMessage(m.users[i], message, channel);
util.tellOthers(1, channel, sys.name(src) + " has /" + command +
"'d " + sys.name(m.users[i]));
}
}
}
this.reborn = function(src, channel, data){
var message = util.tableHeader("Poke-Place [[Reborn]]", (GLOBAL[channel]
.color || "blue"), 7, 2, true) +
"<tr><td colspan='5' align='justify'>What is the Reborn League,
you ask? The Reborn League is an expansive challenge " +
"which pits you against a variety of mono-type teams and versati
le 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 i
t takes? Then join us! " +
"Everything you need to get started is right <a href='http://www
.poke-place.com/index.php?id=4'>here</a>." +
"</td><td colspan='2' style='padding-right: 20px'><ul><li><a hre
f='http://poke-place.com/'>Website</a></li><li><a href='http://www.poke-place.co
m/index.php?id=4'>Rules</a></li><li>" +
"<a href='http://www.poke-place.com/forum/index.php?showtopic=35
1'>Registration</a></li><li><a href='http://www.poke-place.com/index.php?id=6'>"
+
"Leaders</a></li><li><a href='http://www.poke-place.com/forum/in
dex.php?showtopic=20'>Hall of Fame</a></ul></td></tr></table><br/>";
this.message(src, channel, message, data, "reborn");
}
this.rules = function(src, channel, data){
var color = function(m){ return "<font color='" + (GLOBAL[channel].color
|| "blue") + "'><b>" + m + "</b></font>"; }
var message = util.tableHeader("Reborn Rules", (GLOBAL[channel].color ||
"blue"), 1, 9, true) +
"<tr><td>" + color("1. ") + "Be respectful. Or at least pretend
like it.</td></tr>" +
"<tr><td>" + color("2. ") + "At least attempt to act intelligent
ly (No chatspeak).</td></tr>" +
"<tr><td>" + color("3. ") + "No trolling.</td></tr>" +
"<tr><td>" + color("4. ") + "Do not be annoying. This is subject
ive and on a case by case basis.</td></tr>" +
"<tr><td>" + color("5. ") + "Do not challenge the Gym Leaders. T
hey will challenge you.</td></tr>" +
"<tr><td>" + color("6. ") + "Do not advertise. Seriously.</td></
tr>" +
"<tr><td>" + color("7. ") + "Sexual content will not be tolerate
d.</td></tr>" +
"<tr><td>" + color("8. ") + "All talk in the main-chat should be
English.</td></tr>" +
"</table><br/>";
this.message(src, channel, message, data, "rules");
}
this.status = function(src, channel, data){
if (!data){
sys.sendMessage(src, "Current Status: " + (sys.getFileContent(this.S
TATUS) || "Online"), channel);
return;
}
sys.writeToFile(this.STATUS, data);
util.tellOthers(1, channel, sys.name(src) + " has set the server status
to: " + data);
}
this.authlist = function(src, channel){
var id, user, auths = sys.dbAuths();
for (var i=0;i<auths.length;i++){
auths[i] = sys.dbAuth(auths[i]) + auths[i];
}
auths = auths.sort().reverse();
var message = util.tableHeader("Authy Users", (GLOBAL[channel].color ||
"darkred"), 3, auths.length+2, false);
for (var i=0;i<auths.length;i++){
var auth = parseInt(auths[i].substr(0, 1));
user = util.username(sys.id(auths[i].substr(1))) || auths[i].substr(
1);
message += "<tr><td>" + user + "</td><td align='center'>:</td><td>"
+ (auth > 3 ? "Nyu!" : auth == 3 ? "Owner" : auth == 2 ? "Administrator" : "Mode
rator") + (GLOBAL[channel].chanOp == sys.id(auths[i].substr(1)) ? " + ChanOp" :
"") + "</td></tr>";
}
if (util.username(GLOBAL[channel].chanOp) && util.isAuth(GLOBAL[channel]
.chanOp, channel) == -1){
message += "<tr><td>" + util.username(GLOBAL[channel].chanOp) + "</t
d><td align='center'>:</td><td>ChanOp</td></tr>";
}
message += "</table><br/>";
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<players.length;i++){
if (++count == 5){
margin++;
html += "</tr><tr>";
count = 0;
}
var user = util.username(players[i]) || sys.name(players[i]) || "";
if (!sys.isInChannel(players[i], channel)){
user = user.replace(/<b>(.*?)<\/b>/, i + ". $1");
} else {
user = user.replace(/<b>(.*?)/, "<b>" + i + ". $1");
}
html += "<td style='padding: 0 5px;'>" + user + "</td>";
}
html = util.tableHeader("User List", (GLOBAL[channel].color || "grey"),
5, margin, false) +
"<tr><td colspan='5' align='center' style='padding: 0 5px;'>Id 0 is
the channel id. Bold users are in the current channel.</td></tr>" +
"<tr><td style='padding: 0 5px;'><b>0. <i>" + sys.channel(channel) +
"</i></b></td>" + html + "</tr></table><br/>";
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 s
ecurity 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 mak
e 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<message.users.length;i++){
auth = (util.isOffline(message.users[i]) ? sys.dbAuth(message.users[
i]) : sys.auth(message.users[i]));
trgt = (util.isOffline(message.users[i]) ? message.users[i] : sys.na
me(message.users[i]));
if (sys.auth(src) > auth){
if (auth != level){
(util.isOffline(message.users[i]) ? sys.changeDbAuth : sys.c
hangeAuth)(message.users[i], level);
util.tellOthers(1, channel, sys.name(src) + " has set " + tr
gt + " as " + title);
} else {
(util.isOffline(message.users[i]) ? sys.changeDbAuth : sys.c
hangeAuth)(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 high
er authority than you; cannot change.", channel);
}
}
}
this.selfkick = function(src, channel, data){
var aliases = sys.aliases(sys.ip(src));
var someone = false;
for (var i=0;i<aliases.length;i++){
var id = sys.id(aliases[i]);
if (id && id != src){
sys.sendMessage(src, "Found user " + sys.name(id) + "; kicking."
, channel);
sys.kick(id);
someone = true;
}
}
if (!someone){
util.failUsers(src, channel);
}
}
this.idle = function(src, channel, data){
var idle, message = util.parseMessage(0, data, false, false);
if (!message || message.users.length == 0){
util.failParameters(src, channel);
} else {
for (var i=0;i<message.users.length;i++){
idle = !sys.away(message.users[i]);
sys.changeAway(message.users[i], idle);
util.tellOthers(2, channel, sys.name(src) + " has " + (idle ? "i
dled " : "unidled ") + sys.name(message.users[i]));
}
}
}
this.mod = function(src, channel, data){
this.changeAuth(src, channel, data, 1, "a moderator");
}
this.chanop = function(src, channel, data){
if (channel == 0){
sys.sendMessage(src, "The main channel does not allow chanOps.", cha
nnel);
return;
}
if (!data){
sys.sendHtmlMessage(src, "Current chanOp: " + (util.isOffline(GLOBAL
[channel].chanOp) ? "(none)" : util.username(GLOBAL[channel].chanOp)), channel);
return;
}
message = util.parseMessage(0, data, false, false);
if (message && message.users.length > 0){
if (GLOBAL[channel].chanOp == message.users[0]){
sys.sendHtmlMessage(src, util.username(message.users[0]) + " is
already the chanOp for this channel...", channel);
return;
}
GLOBAL[channel].chanOp = message.users[0];
sys.sendHtmlAll("<font color='" + (GLOBAL[channel].color || "darkblu
e") + "'><timestamp/><b>±ChanOp Notice: </b></font>" + util.username(GLOBAL[channe
l].chanOp) + " is now the channel operator.", channel);
} else {
util.failUsers(src, channel);
}
}
this.admin = function(src, channel, data){
this.changeAuth(src, channel, data, 2, "an administrator");
}
this.reloadscript = function(src, channel, data){
var newscript = sys.getFileContent("scripts.js");
try {
eval(newscript);
} catch (err) {
sys.sendMessage(src, "Syntax error in script file. Nothing reloaded
.", channel);
return;
}
data = data ? " (" + data + ")" : "";
util.tellOthers(2, channel, sys.name(src) + " has reloaded the scripts."
+ data);
sys.changeScript(newscript);
}
this.announce = function(src, channel, data){
sys.changeAnnouncement(data.replace(/%s/g, sys.getAnnouncement()));
}
this.welcome = function(src, channel, data){
if (!data){
this.afterLogIn(src, channel);
} else {
if (sys.auth(src) < 2){
util.failPermission(src, channel);
return;
}
data = data.replace(/%s/g, sys.getVal("welcome"));
sys.saveVal("welcome", data);
util.tellOthers(2, channel, sys.name(src) + " has changed the welcom
e message: " + data);
}
}
this.regex = function(src, channel, data){
if (!data){
util.failParameters(src, channel);
return;
}
message = util.parseMessage(0, data, true, true);
if (!message){
sys.sendMessage(src, "Your regex isn't even valid...", channel);
return;
}
var somebody = false;
var userstr = "";
for (var i=0;i<message.users.length;i++){
userstr += (message.users[i] == 0 ? "<b><i>" + sys.channel(channel)
+ "</i></b>" : 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, "<font color='" + (GLOBAL[0].color || "dark
blue") + "'><timestamp/><b>±Welcome Message: </b></font>" + 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 fro
m exploding."];
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 off
line 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.chanop.help = ["user", "Sets the user as the channel operator.", "If
no user provided, list current chanOp."];
this.status.help = ["text", "Sets server status (as shown on website).", "
If text is not given, display current status."];
this.announce.help = ["announcement", "Changes the announcement.", "HTML all
owed. A %s in the announcement will be replaced by the current announcement."];
this.welcome.help = ["message", "Displays the welcome message.", "If messag
e is provided, sets the welcome message. HTML allowed. A %s in the message will
be replaced by the current welcome message."];
this.reloadscript.help = ["message", "Refreshes the scripts.", "If message i
s present, displays message along with the reloadscript notification."];
} /* }}} */
/* {{{ TextModify Module: Allows methods for modifying text before it gets sent
*/
function TextModify(){
this.init = function(){
register(1, "quotecolor", this);
register(2, "censor", this);
register(2, "uncensor", this);
register(0, "link", this);
hook("beforeChatMessage", this);
helperregister("markdown", this);
}
this.markdown = function(src, channel, message){
message = this.evalCensors(src, channel, message);
if (message === false){
return false;
}
var c1 = GLOBAL[channel].quotecolor ? GLOBAL[channel].quotecolor[0] : "d
arkblue";
var c2 = GLOBAL[channel].quotecolor ? GLOBAL[channel].quotecolor[1] : "g
reen";
message = util.escapeHtml(message);
message = message.replace(/^[.!\/]([!\/]+.*)$/, "$1");
message = message.replace(/^(>>(?![;:]|.?(?:>|<)|[:;]?[3DOo0
\]\[](?:$|\s)).*?(?=\S).*)$/, "<font color='" + c2 + "'>$1</font>");
message = message.replace(/^(>(?!_+>|.?(?:>|<)|[:;]?[3DOo0\]
\[|](?:$|\s)).*?(?=\S).*)$/, "<font color='" + c1 + "'>$1</font>");
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≠");
message = message.replace(/(^|\W)_\^_(?=$|\s)/g, "$1↑").replace(/(^|\W)_[v
V]_(?=$|\s)/g, "$1↓");
message = message.replace(/(^|\W)_>_(?=$|\s)/g, "$1→").replace(/(^|\W)_
<_(?=$|\s)/g, "←");
message = message.replace(/(^|\W|_)\*\*(\S(?:.*?\S)?)\*\*(?=_|\W|$)/g, "
$1<b>$2</b>");
message = message.replace(/(^|\W)_(?![\.oO0@](?:\s|$))(\S(?:.*?\S)?)_(?=
\W|$)/g, "$1<i>$2</i>");
message = message.replace(/(^|\W|_)--(?!--)(\S(?:.*?\S)?)--(?=_|\W|$)/g,
"$1<s>$2</s>");
message = message.replace(/\[(?!\s\])([^\[]+)\]\(([^\s\)]+)(?:\s(['"])([
^'"]+)\3)?\)/g, "<a href='$2' style='color:" + util.nameColor(src) + ";' title='
$4'>$1</a>");
message = message.replace(/\\\s/g, "");
var hashttp = /<a href='(.+)'/.exec(message);
if (hashttp){
if (!(/^(?:https?|ftp):\/\//.test(hashttp[1]))){
message = message.replace(hashttp[1], "http://" + hashttp[1]);
}
}
if (GLOBAL[0].links != undefined && GLOBAL[0].links[src] != undefined){
message = "<nop/>" + message;
}
message = message.replace(/(^|\s+)((?:https?|ftp):\/\/[\S]+)($|\s+)/, "$
1<a href='$2'>$2</a>$3");
return message;
}
this.quotecolor = function(src, channel, data){
message = util.parseMessage(-1, data, false, false);
if (!message || !message.args || message.args.length != 2){
var c1 = GLOBAL[channel].quotecolor ? GLOBAL[channel].quotecolor[0]
: "darkblue";
var c2 = GLOBAL[channel].quotecolor ? GLOBAL[channel].quotecolor[1]
: "green";
sys.sendHtmlMessage(src, "Current quote colors: <font color='" + c1
+ "'>>" + c1 + "</font>, <font color='" + c2 + "'>>>" + c2 + "</font>",
channel);
return;
}
if (!(/#[A-Fa-f0-9]{1,6}|\w+/.test(message.args[0]))){
message.args[0] = "black";
}
if (!(/#[A-Fa-f0-9]{1,6}|\w+/.test(message.args[1]))){
message.args[1] = "black";
}
sys.sendMessage(src, message.args, channel);
GLOBAL[channel].quotecolor = message.args;
util.tellOthers(1, channel, sys.name(src) + " has changed the quote colo
rs to <font color='" + GLOBAL[channel].quotecolor[0] + "'>>" + GLOBAL[channel
].quotecolor[0] + "</font>, <font color='" +
GLOBAL[channel].quotecolor[1] + "'>>>" + GLOBAL[channel].q
uotecolor[1] + "</font>");
}
this.showCensors = function(src, channel){
var html = "", margin = 1;
if (GLOBAL[channel].censor != undefined){
for (var i=0;i<GLOBAL[channel].censor.length;i++){
html += "<tr><td><b>" + (i+1) + ".</b></td><td>" + (GLOBAL[chann
el].censor[i][2] ? GLOBAL[channel].censor[i][0] : GLOBAL[channel].censor[i][0].s
ource.replace(/\\/g, "")) + "</td><td align='center'>:</td><td>" + (GLOBAL[chann
el].censor[i][1] || "<disallowed>") + "</td></tr>";
margin++;
}
}
if (html == ""){
html += "<tr><td colspan='3'>Nothing censored...</td></tr>";
margin++;
}
html = util.tableHeader("Censor List", (GLOBAL[channel].color || "darkbl
ue"), 4, margin, false) + html + "</table><br/>";
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;i++){
var t = GLOBAL[channel].censor[i][0].exec(message);
if ((!GLOBAL[channel].censor[i][1]) && t){
sys.sendMessage(src, "Sorry, " + t + " is censored.", channel);
return false;
}
message = message.replace(GLOBAL[channel].censor[i][0], GLOBAL[chann
el].censor[i][1]);
}
return message;
}
this.uncensor = function(src, channel, data){
if (GLOBAL[channel].censor == undefined){
sys.sendMessage(src, "Sorry, no censors are defined.", channel);
return;
}
var n = parseInt(data);
if (isNaN(n) || n > 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 " + (remove
d[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.e
xec(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.esc
apeHtml((args[2] ? args[0] : args[0].source.replace(/\\/g, "")).toString()) + "
" + (args[1] == "" ? "(completely disallowed)" : "to " + util.escapeHtml(args[1
])));
}
this.link = function(src, channel, data){
if (data){
if (GLOBAL[0].links == undefined){
GLOBAL[0].links = {};
}
GLOBAL[0].links[src] = data;
}
}
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();
var link = GLOBAL[0].links != undefined ? GLOBAL[0].links[src] :
null;
sys.sendHtmlAll("<" + src + ">" + util.header(src, link) + newme
ssage, channel);
callhooks("afterChatMessage", src, newmessage, channel);
return true;
}
}
}
GLOBAL.helps["markdown"] = function(color){ return util.tableHeader("Markdow
n", color, 2, 10, true) +
"<tr><td colspan='2' align='justify'>Markdown provides a method of forma
tting text into something prettier.<br/></td></tr>" +
"<tr><th>Inputted Text</th><th>Displayed As</th></tr>" +
"<tr><td>_italics_</td><td><i>italics</i></td></tr>" +
"<tr><td>**bold**</td><td><b>bold</b></td></tr>" +
"<tr><td>--strikethrough--</td><td><s>strikethrough</s></td></tr>" +
"<tr><td>[link](http://ffff00.com)</td><td><a href='http://ffff00.com'>l
ink</a></td></tr>" +
"<tr><td>>color1</td><td><font color='darkblue'>>color1</font></td
></tr>" +
"<tr><td>>>color2</td><td><font color='green'>>>color2</font
></td></tr>" +
"<tr><td>\\_escaped\\_</td><td>_escaped_</td></tr>" +
"<tr><td colspan='2'> </td></tr></table>"
}
this.quotecolor.help = ["color1 color2", "Changes the markdown'd quote color
s.", "First color is for >single quotes, second color is for >>double q
uotes. If no colors given, display current colors."];
this.censor.help = ["text replace", "Censors text.", "If replace is given,
changes text to replace, otherwise blocks message completely. text/replace can a
lso be given in sed-style /find/replace/flags notation, which allows regex. If n
o 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].col
or || "darkred"), 6, margin, false) +
"<tr><td rowspan='2' colspan='2' align='center'><font size='+1'>
<b>" + limitmsg +
"</b></font><br/>slots</td><td align='center' colspan='4'><b>" +
me.tier + "</b></td></tr>" + "<tr><td align='center' colspan='4'>" +
typemsg + "</td></tr>" + (me.limit == 0 ? "<tr><td align='center
' colspan='6'>Remaining time to join: <b>~" + me.time + "</b> seconds</td></tr>"
: "") +
"<tr><th colspan='6'><font color='" + (GLOBAL[channel].color ||
"darkred") +
"'>~~~~~~ Type <i>/join</i> to enter ~~~~~~</font></th></tr></ta
ble><br/>";
}
this.message = function(data, channel){
if (GLOBAL[channel].tour == undefined){
return;
}
sys.sendHtmlAll("<font color='" + (GLOBAL[channel].color || "darkred") +
"'><timestamp/><b>±" + GLOBAL[channel].tour.tier + " Tournament: </b></font>" + d
ata, 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;i<GLOBAL[channel].tour.users.length-1;i++){
margin++;
html += "<tr><td align='center' colspan='3'>" + (util.username(s
ys.id(GLOBAL[channel].tour.users[i])) || GLOBAL[channel].tour.users[i]) + "</td>
<td align='center'>vs.</td><td align='center' colspan='3'>" + (util.username(sys
.id(GLOBAL[channel].tour.users[++i]) || GLOBAL[channel].tour.users[i])) + "</td>
</tr>";
}
if (GLOBAL[channel].tour.users.length % 2 == 1){
margin++;
html += "<tr><td colspan='7' align='center'>" + (util.username(s
ys.id(GLOBAL[channel].tour.users[GLOBAL[channel].tour.users.length-1])) || GLOBA
L[channel].tour.users[GLOBAL[channel].tour.users.length-1]) + " does not fight t
his round...</td></tr>";
}
if (GLOBAL[channel].tour.winners[GLOBAL[channel].tour.round] != unde
fined){
margin++;
html += "<tr><th colspan='7'><font color='" + (GLOBAL[channel].c
olor || "darkred") + "'>~~~ Completed Matches ~~~</font></th></tr>";
for (var i=0;i<GLOBAL[channel].tour.winners[GLOBAL[channel].tour
.round].length;i++){
margin++;
html += "<tr><td colspan='3' align='center'>W: " +
(util.username(sys.id(GLOBAL[channel].tour.winners[GLOBA
L[channel].tour.round][i])) || GLOBAL[channel].tour.winners[GLOBAL[channel].tour
.round][i]) +
"</td><td align='center'>vs.</td><td colspan='3' align='
center'>" +
(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[ch
annel].tour.round][i])) + "</td></tr>";
}
}
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 + "</table><br/>";
} 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) + "<tr><td><b>[Score] Player</b></td><td/><td><b>Remaining Op
ponents</td></tr>";
for (var i=0;i<GLOBAL[channel].tour.users.length;i++){
var n = GLOBAL[channel].tour.users[i];
html += "<tr><td>[<b>" + this.getScore(n, channel) + "</b>] " +
(util.username(sys.id(n)) || n) + "</td><td align='center'>:</td><td>";
var someone = false;
for (var j=0;j<GLOBAL[channel].tour.users.length;j++){
if (GLOBAL[channel].tour.users[j] == n
|| GLOBAL[channel].tour.scoreboard[n][GLOBAL[channel].to
ur.users[j]] != undefined){
continue;
}
someone = true;
html += (util.username(sys.id(GLOBAL[channel].tour.users[j])
) || GLOBAL[channel].tour.users[j]) + ", ";
}
if (!someone){
html += "Battles completed...";
}
html = html.replace(/, $/, "");
html += "</td></tr>";
}
html += "</table><br/>";
}
return html;
}
this.isMatchedUp = function(user1, user2){
var channels = sys.channelIds();
for (var i=0;i<channels.length;i++){
if (this.getTourMode(channels[i]) != -1){
var index1 = this.index(user1, channels[i]);
var index2 = this.index(user2, channels[i]);
if (index1 != -1 && index2 != -1){
if (/single|double/.test(GLOBAL[channels[i]].tour.type)){
if (Math.abs(index1 - index2) == 1 && Math.max(index1, i
ndex2) % 1 == 0){
return channels[i];
}
} else if (/round/.test(GLOBAL[channels[i]].tour.type)){
if (GLOBAL[channels[i]].tour.scoreboard[user1][user2] ==
undefined){
return channels[i];
}
}
}
}
}
return -1;
}
this.addUser = function(src, channel, forced){
GLOBAL[channel].tour.users.push(src);
var message = (util.username(sys.id(src)) || src) + (forced? " has been
added to" : " has joined") + " the tournament. ";
if (GLOBAL[channel].tour.limit != 0){
var rem = GLOBAL[channel].tour.limit - GLOBAL[channel].tour.users.le
ngth;
message += "<b>" + rem + "</b> spot" + (rem == 1 ? "" : "s") + " rem
aining.";
}
this.message(message, channel);
if (GLOBAL[channel].tour.limit > 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 + (GLOB
AL[channel].tour.limit > 0 ? " <b>" + (GLOBAL[channel].tour.limit - GLOBAL[chann
el].tour.users.length) + "</b> 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, ch
annel);
this.advance(GLOBAL[channel].tour.users[index2], GLOBAL[chan
nel].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<GLOBAL[channel].tour.users.length;i++){
if (GLOBAL[channel].tour.scoreboard[GLOBAL[channel].tour.use
rs[i]][user] == undefined){
rem++;
}
GLOBAL[channel].tour.scoreboard[GLOBAL[channel].tour.users[i
]][user] = 0;
}
this.message((util.username(sys.id(user)) || user) + message + "
Scores have been adjusted accordingly.", channel);
GLOBAL[channel].tour.remaining -= rem;
if (GLOBAL[channel].tour.remaining == 0){
this.modeWinner(channel);
} else {
delete GLOBAL[channel].tour.scoreboard[user];
GLOBAL[channel].tour.users.splice(index, 1);
}
}
}
}
this.modeEntry = function(src, channel, type, tier, limit){
if (GLOBAL[channel].tour == undefined){
GLOBAL[channel].tour = {mode: 0, users: [], type: type, limit: limit
, tier: tier};
if (limit == 0){
GLOBAL[channel].tour.time = 90;
}
if (/single|double/.test(type)){
GLOBAL[channel].tour.winners = [];
GLOBAL[channel].tour.losers = [];
GLOBAL[channel].tour.round = 0;
}
if (/round/.test(type)){
GLOBAL[channel].tour.scoreboard = {};
GLOBAL[channel].tour.remaining = 0;
}
} else {
sys.sendMessage(src, "A tournament has already been started in this
channel", channel);
return;
}
sys.sendHtmlAll(this.announce(channel), channel);
}
this.makeScoreboard = function(channel){
if (GLOBAL[channel].tour != undefined && GLOBAL[channel].tour.scoreboard
!= undefined){
GLOBAL[channel].tour.scoreboard = {};
}
for (var i=0;i<GLOBAL[channel].tour.users.length;i++){
var me = GLOBAL[channel].tour.users[i];
GLOBAL[channel].tour.scoreboard[me] = {};
GLOBAL[channel].tour.scoreboard[me][me] = -1;
}
}
this.getScore = function(user, channel){
var sum = 1;
for (var i in GLOBAL[channel].tour.scoreboard[user]){
sum += GLOBAL[channel].tour.scoreboard[user][i];
}
if (GLOBAL[channel].tour.tiebreaker != undefined){
sum += GLOBAL[channel].tour.tiebreaker;
}
return sum;
}
this.modeBattle = function(channel){
GLOBAL[channel].tour.users.shuffle();
if (/round/.test(GLOBAL[channel].tour.type)){
this.makeScoreboard(channel);
GLOBAL[channel].tour.remaining = (GLOBAL[channel].tour.users.length/
2)*(GLOBAL[channel].tour.users.length-1);
this.message("The tournament has begun. Everyone go battle everyone
, or type <i>/viewmatches</i> 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.us
ers.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[cha
nnel].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[chan
nel].tour.users[0])) || GLOBAL[channel].tour.users[0]) + " has won the tournamen
t!", 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 <b>" + max + "</b> points!", ch
annel);
} 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<users.length-1;i++){
message += (util.username(sys.id(users[0])) || users[0]) + "
, ";
}
if (users.length == 2){
message = message.replace(/, $/, " ");
}
message += " and " + (util.username(sys.id(users[users.length-1]
)) || users[length-1]) + ". A tiebreaker round is starting!";
this.message(message, channel);
return;
}
}
delete GLOBAL[channel].tour;
}
this.advance = function(winner, loser, channel){
var round = GLOBAL[channel].tour.round;
if (/single|double/.test(GLOBAL[channel].tour.type)){
GLOBAL[channel].tour.users.splice(GLOBAL[channel].tour.users.indexOf
(winner), 1);
if (loser != ""){
GLOBAL[channel].tour.users.splice(GLOBAL[channel].tour.users.ind
exOf(loser), 1);
var remaining = GLOBAL[channel].tour.users.length/2;
var message = (util.username(sys.id(winner)) || util.escapeHtml(
winner)) + " has won a match! " + (util.username(sys.id(loser)) || util.escapeHt
ml(loser)) + " is out of the tournament.";
if (remaining > 0){
message += " <b>" + remaining+ "</b> 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(("[<b>" + (this.getScore(winner, channel)) + "</b>]" +
util.username(sys.id(winner)) || winner) + " has won a match against [<b>" +
(this.getScore(loser, channel)) + "</b>]" + (util.username(s
ys.id(loser)) || loser) + ". " + GLOBAL[channel].tour.remaining + " battle" + (G
LOBAL[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 men
u for valid options.", channel);
return;
}
if (slots == 2 || slots == 1){
sys.sendMessage(src, "A tournament with less than 3 users doesn't re
ally 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.", ch
annel);
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 per
mission 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...", ch
annel);
return;
}
} else if (!util.isAuth(src, channel)){
util.failPermission(src, channel);
return;
} else {
forced = true;
}
for (var i=0;i<message.users.length;i++){
if (this.index(sys.name(message.users[i]), channel) == -1){
this.addUser((sys.name(message.users[i]) || message.users[i]), c
hannel, forced);
if (this.getTourMode(channel) != 0 && i != message.users.length-
1){
sys.sendMessage(src, "Tournament is full; not adding remaini
ng users", channel);
return;
}
} else {
sys.sendMessage(src, sys.name(message.users[i]) + " is already i
n the tournament; not adding.", channel);
}
}
}
this.leave = function(src, channel, data){
if (this.getTourMode(channel) == -1){
sys.sendMessage(src, "A tournament is not running...", 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 per
mission for that.", channel);
return;
}
if (this.index(sys.name(src), channel) != -1){
message.users.push(src);
} else {
sys.sendMessage(src, "You are not in this tournament...", channe
l);
return;
}
} else if (!util.isAuth(src, channel)){
util.failPermission(src, channel);
return;
} else {
forced = true;
}
for (var i=0;i<message.users.length;i++){
var user = util.isOffline(message.users[i]) ? message.users[i] : sys
.name(message.users[i]);
if (this.index(user, channel) != -1 || GLOBAL[channel].tour.winners[
GLOBAL[channel].tour.round].indexOf(sys.name(message.users[i]) != -1)){
this.removeUser(user, channel, forced);
} else {
sys.sendMessage(src, user + " is not in the tournament...", chan
nel);
}
}
}
this.beforeChallengeIssued = function(src, target, clauses){
var channel = this.isMatchedUp(sys.name(src), sys.name(target));
if (channel != -1){
if (GLOBAL[channel].tour.tier == "Challenge Cup"){
if (clauses[4] == 0){
sys.stopEvent();
sys.sendMessage(src, "Sorry, you must have the Challenge Cup
clause enabled for this tournament.", channel);
}
} else if (sys.tier(src) != GLOBAL[channel].tour.tier){
sys.stopEvent();
sys.sendMessage(src, "Sorry, you are not in the correct tier for
this tournament match.", channel);
} else if (sys.tier(target) != GLOBAL[channel].tour.tier){
sys.stopEvent();
sys.sendMessage(src, "Sorry, your opponent is not in the correct
tier for this tournament match.", channel);
}
}
}
this.afterBattleEnded = function(winner, loser, result){
winner = sys.name(winner);
loser = sys.name(loser);
var channel = this.isMatchedUp(winner, loser);
if (channel != -1){
if (result == "tie"){
this.rematch(winner, loser, channel);
} else {
this.advance(winner, loser, channel);
}
}
}
this.starttour = function(src, channel, data, nomessage){
if (this.getTourMode(channel) != 0){
if (!(nomessage === true)){
sys.sendMessage(src, "There is no tournament in the sign-up phas
e.", channel);
}
return;
}
if (GLOBAL[channel].tour.users.length < 3){
if (nomessage === true){
this.message("Not enough entries; cancelling tournament.", channe
l);
} else {
sys.sendMessage(src, "Not enough entries in tournament; cannot s
tart.", channel);
}
delete GLOBAL[channel].tour;
return;
}
GLOBAL[channel].tour.limit = GLOBAL[channel].tour.users.length;
this.modeBattle(channel);
}
this.endtour = function(src, channel, data){
if (this.getTourMode(channel) != -1){
this.message("The tournament has been cancelled.", channel);
delete GLOBAL[channel].tour;
} else {
sys.sendMessage(src, "There's no tournament running...", channel);
}
}
this.viewmatches = function(src, channel, data){
var message = this.showRound(channel);
if (message){
sys.sendHtmlMessage(src, message, channel);
} else {
sys.sendMessage(src, "No tournament started or tournament is still i
n sign-up phase...", channel);
}
}
this.afterChannelJoin = function(src, channel){
if (this.getTourMode(channel) == 0){
sys.callQuickly("sys.sendHtmlMessage(" + src + ", GLOBAL.modules['To
urnament'].announce(" + channel + "), " + channel + ")", 200);
}
}
this.toursize = function(src, channel, data){
if (this.getTourMode(channel) != 0){
sys.sendMessage(src, "There is no tournament running...", channel);
return;
}
if (GLOBAL[channel].tour.limit == 0){
sys.sendMessage(src, "You cannot change the size of an open sign-up
tournament. Use /starttour instead.", channel);
return;
}
var n = parseInt(data);
if (isNaN(n)){
util.failParameters(src, channel);
return;
}
if (n < 3){
sys.sendMessage(src, "Sorry, that's not enough slots for a tournamen
t, must be greater than 3.", channel);
return;
}
if (n < GLOBAL[channel].tour.users.length){
sys.sendMessage(src, "Sorry, you cannot set the size less than the c
urrent number of sign-ups (" + GLOBAL[channel].tour.users.length + ")", channel)
;
return;
}
this.message("The tournament size has been changed to <b>" + n + "</b>."
, 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 = util.isOffline(message.users[0]) ? message.users[0] : sys.na
me(message.users[0]);
var user2 = util.isOffline(message.users[1]) ? message.users[1] : sys.na
me(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 u
p; 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.roun
d].indexOf(user2);
if (u2index != -1){
GLOBAL[channel].tour.winners[GLOBAL[channel].tour.round][u2i
ndex] = user1;
}
GLOBAL[channel].tour.users[u1index] = user2;
} else if (u2index != -1){
u1index = GLOBAL[channel].tour.winners[GLOBAL[channel].tour.roun
d].indexOf(user1);
if (u1index != -1){
GLOBAL[channel].tour.winners[GLOBAL[channel].tour.round][u1i
ndex] = 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 sw
apped with " + (util.username(sys.id(user2)) || user2) + ". See <i>/viewmatches
</i> for the new matchups.", channel);
} else {
sys.sendMessage(src, "Sorry, /tourswap is not supported for this tou
rnament type at this time...", channel);
}
}
this.tour.help = ["type slots tier", "Starts a tournament. Type is optiona
l and one of <i>single</i>, <i>double</i>, or <i>round</i>.",
"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 inva
lid 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 si
ze 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, remo
ves user from tournament."];
this.viewmatches.help = ["", "Displays the matches for the current tournamen
t 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<argc.length;i++){
data.args.push(message.shift());
}
message = message.join(" ");
var regex = /^~(.+)$/.exec(message);
if (regex){
/* Regex by username */
var rawusers = sys.playerIds();
for (var i=0;i<rawusers.length;i++){
rawusers[i] = sys.name(rawusers[i]);
}
try {
regex = new RegExp(regex[1]);
} catch (err){
return null;
}
if (regex){
for (var i=0;i<rawusers.length;i++){
if (regex.exec(rawusers[i].toString())){
data.users.push(sys.id(rawusers[i]));
}
}
}
} else {
regex = message.match(/[:*]?[^:*]+/g) || [];
var users = util.playerIds();
for (var i=0;i<regex.length;i++){
var type;
if (/^[:*]/.test(regex[i])){
type = regex[i].substr(0, 1);
regex[i] = regex[i].substr(1);
}
regex[i] = regex[i].replace(/^\s+/g, "").replace(/\s+$/g, "");
if (type == "*"){
if (regex[i] == "0"){
if (channel){
if (data.users.indexOf(0) == -1){
data.users.push(0);
}
}
} else {
var id = parseInt(regex[i]);
if (!isNaN(id) && id < users.length && id > 0){
if (sys.loggedIn(users[id]) && data.users.indexOf(us
ers[id]) == -1){
data.users.push(users[id]);
}
}
}
} else {
var user = sys.id(regex[i]);
if (sys.loggedIn(user) && data.users.indexOf(user) == -1){
data.users.push(user);
} else {
if (offline){
if (sys.dbLastOn(regex[i]) && data.users.indexOf(reg
ex[i]) == -1){
data.users.push(regex[i]);
}
}
}
}
}
}
return data;
}
this.setEvent = function(src, on){
if (on){
if (GLOBAL[0].events == undefined){
GLOBAL[0].events = {};
}
GLOBAL[0].events[src] = true;
} else {
if (GLOBAL[0].events != undefined){
delete GLOBAL[0].events[src];
}
}
}
this.isEvent = function(src){
return GLOBAL[0].events && GLOBAL[0].events[src];
}
this.isOffline = function(val){
if (val == 0){
return null;
}
return !(sys.loggedIn(val));
}
this.playerIds = function(){
var ids = sys.playerIds().sort();
ids.unshift(0); // The channel
return ids;
}
this.nameColor = function(src){
if (sys.getColor(src) == '#000000') {
var clist = ['#5811b1','#399bcd','#0474bb','#f8760d','#a
00c9e','#0d762b','#5f4c00','#9a4f6d','#d0990f','#1b1390','#028678','#0324b1'];
return clist[src % clist.length];
}
return sys.getColor(src);
}
this.username = function(src){
if (!sys.loggedIn(src)){
return null;
}
return "<font color='" + this.nameColor(src) + "'><b>" + this.escapeHtml
(sys.name(src)) + "</b></font>";
}
this.header = function(src, link){
var str = "<font color='" + util.nameColor(src) + "'><timestamp/>" + (sy
s.auth(src) > 0 && sys.auth(src) < 4 ? "+<i>" : "") + "<b>";
if (link){
str += "<a href='" + link + "' style='text-decoration: none; color:
" + this.nameColor(src) + ";'>" + sys.name(src) + "</a>";
} else {
str += sys.name(src);
}
str += ":</b>" + (sys.auth(src) > 0 && sys.auth(src) < 4 ? "</i>" : "")
+ "</font> ";
return str;
}
this.tableHeader = function(title, color, colspan, margin, wrap){
var html = "<table>";
if (!wrap){
html = html.replace(/>$/, " style='white-space: nowrap;'>");
}
html += "<tr><td rowspan='" + margin + "'> </td><th col
span='" + colspan +"'><font color='" + color + "'>~~~ " + title + " ~~~</font></
th></tr>";
return html;
}
this.escapeHtml = function(str){
if (typeof(str) == "string"){
return str.replace(/&/g, "&").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(cha
nnel));
for (var i=0;i<players.length;i++){
if (sys.auth(players[i]) >= auth || players[i] == GLOBAL[channel].ch
anOp){
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 somethin
g", channel);
}
this.failMuted = function(src, channel){
sys.sendMessage(src, "Oh looky, you're muted. Stop doing things.", chan
nel);
}
this.failCommand = function(src, channel){
sys.sendMessage(src, "Hmm, that's not a command or you don't have permis
sions or something of that sort.", channel);
}
this.failBlacklisted = function(src, channel){
sys.sendMessage(src, "Sorry, that command has been blacklisted.", channe
l);
}
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<arguments.length;i++){
GLOBAL.aliases[arguments[i]] = name;
}
return true;
}
function authregister(auth, name, module){
if (register.apply(this, arguments)){
GLOBAL.calls[auth][name][name].authonly = true;
}
}
function helperregister(func, module){
if (module == undefined){
return;
}
GLOBAL.helpers[func] = module;
}
function hook(type, module){
if (module == undefined){
return;
}
if (!(type in GLOBAL.hooks)){
GLOBAL.hooks[type] = [];
}
GLOBAL.hooks[type].push(module);
}
function command(src, message, channel){
var module, call;
var auth = sys.auth(src);
if (src == GLOBAL[channel].chanOp && auth < 2){
auth = 2;
}
if (call = /^[!\/]([^!\/][^\s]*).*$/.exec(message)){
message = message.split(" ");
call = translate(call[1]);
sys.stopEvent();
for (var i=(auth > 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(sr
c) == 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<GLOBAL.hooks[type].length;i++){
if (GLOBAL.hooks[type][i][type].apply(GLOBAL.hooks[type][i], args) =
== true){
retval = true;
}
}
}
return retval;
}
function translate(alias){
if (alias in GLOBAL.aliases){
return GLOBAL.aliases[alias];
} else {
return alias;
}
}
function makeGlobal(){
var old = typeof(GLOBAL) == "undefined" ? null : GLOBAL;
GLOBAL = {
/* Index in calls is the required index for the command */
"calls": [ {}, {}, {}, {} ],
"hooks": { /* Functions to call with the events */ },
"modules": { /* Loaded modules */ },
"aliases": { /* Aliases for commands */ },
"helps" : { /* Non-command help strings */ },
"helpers": { /* Helper functions */ },
}
if (old){
for (var i in old){
if (!isNaN(parseInt(i))){
GLOBAL[i] = old[i];
}
}
}
}
({
afterNewMessage: function(message){
if (message == "Script Check: OK"){
init();
}
},
serverStartUp: function(){
init();
this.beforeChannelCreated(0, sys.channel(0), 0);
},
beforeChatMessage: function(src, message, channel){
if (util.isEvent(src)){
sys.stopEvent();
return;
}
if (!callhooks("beforeCommands", src, message, channel)){
if (!command(src, message, channel)){
callhooks("beforeChatMessage", src, message, channel);
}
}
},
beforeChannelCreated: function(id, name, src){
GLOBAL[id] = {chanOp: src};
callhooks("beforeChannelCreated", id, name, src);
},
beforeChannelDestroyed: function(id){
delete GLOBAL[id];
},
beforeChannelJoin: function(src, id){
callhooks("beforeChannelJoin", src, id);
},
beforeChannelLeave: function(src, id){
callhooks("beforeChannelLeave", src, id);
},
beforeChallengeIssued: function(src, trgt, clauses, rated, mode){
callhooks("beforeChallengeIssued", src, trgt, clauses, rated, mode);
},
beforeLogOut: function(src){
util.setEvent(src, false);
},
beforeChangeTier: function(src, oldt, newt){
callhooks("beforeChangeTier", src, oldt, newt);
},
afterChatMessage: function(src, message, channel){
callhooks("afterChatMessage", src, message, channel);
},
afterLogOut: function(src){
callhooks("afterLogOut", src);
},
afterLogIn: function(src){
callhooks("afterLogIn", src);
},
afterChannelJoin: function(src, channel){
callhooks("afterChannelJoin", src, channel);
},
afterBattleEnded: function(winner, loser){
callhooks("afterBattleEnded", winner, loser);
}
})