Sei sulla pagina 1di 64

this.

GLOBAL;
function init(){
makeGlobal();
include("Server");
include("Help");
include("Mute");
include("Events");
include("Channels");
include("TextModify");
include("Tournament");
include("Blacklist");
include("NightClub");
include("Automod");
include("Monotype");
include("Randoms");
include("Map");
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(", "));
}
}

this.afterChannelJoin = function(src, channel){


var t = this.showTopic(channel);
if (t){
sys.callQuickly("sys.sendHtmlMessage(" + src + ", \"" + t.replace(/"
/g, '\"') + "\", " + channel + ")", 100);
}
}
this.beforeChannelJoin = function(src, channel){
if (GLOBAL[channel].private == 2){
sys.stopEvent();
sys.sendMessage(src, "Sorry, that channel is currently private.");
} else if (GLOBAL[channel].private == 1 && !util.isAuth(src, channel)){
sys.stopEvent();
sys.sendMessage(src, "Sorry, that channel is currently auth-only.");
}
if (this.isChannelBanned(src, channel)){
sys.sendMessage(src, "You are banned from " + sys.channel(channel) +
"; cannot join.");
sys.stopEvent();
}
}
this.beforeChannelCreated = function(id, name, src){
this.setcolor(src, id, "blue", true);
if (id == 0){
GLOBAL[id].topic = sys.getVal("topic") || undefined;
}
}
this.kick.help = ["user", "Removes user from channel.", "If in main channel,
removes user from server."];
this.silentkick.help = ["user", "Removes user from channel silently.", "If i
n main channel, removes user from server."];
this.setkick.help = ["color message", "Sets kick message to given message an
d color.", "Color is any valid HTML color, or hex code if prefixed with a #. If
an invalid color is given, it will default to black. A %s is required in the ki
ck message; it will display as the kicked users' name. If no arguments are prov
ided, displays your current kick message."];
this.clearkick.help = ["", "Deletes your current kick message."];
this.topic.help = ["message", "Displays the current topic.", "If message is
provided, sets the topic. A %s in the topic message will be replaced by the curr
ent topic."];
this.cleartopic.help = ["", "Deletes the current topic."];
this.setcolor.help = ["color", "Sets the colortheme for script messages.", "
If no color given; show current color. Color is any valid HTML color or hex valu
e if prefixed with a #. If an invalid color is given, it will default to black."
];
this.ban.help = ["user", "Bans user from channel.", "If in main channel, ban
s user from server."];
this.unban.help = ["user", "Unbans user from channel.", "If in main channel,
unbans user from server."];
this.private.help = ["user", "Toggles the channel's status as private", "If
a user is provided, does not kick out that user (although rejoining isn't possib
le without /invite). If user is the channel (/private +0), then all users - incl
uding auth - are prevented from entering."];
this.invite.help = ["user", "Brings user into the channel.", "User will be f
orced into the channel, regardless of channel status."];
} /* }}} */
/* {{{ Events Module: Provides all sorts of message spamy goodness */
function Events(){
this.DEATH = "deaths.txt";
this.POKEDEATH = "pokedeaths.txt";
this.init = function(){
register(0, "me", this);
register(0, "die", this, "d");
register(0, "pokedie", this, "pokeleave", "pd", "pl");
authregister(2, "deathmod", this);
authregister(2, "pokedeathmod", this);
}
this.show = function(src, channel, file){
var html = "", margin = 1;
words = sys.getFileContent(file).split("\n");
words.pop();
for (var i=0;i<words.length;i++){
html += "<tr><td><b>" + (i+1) + ".</b></td><td>" + words[i] + "</td>
</tr>";
margin++;
}
if (html == ""){
html += "<tr><td colspan='2'>No contents...</td></tr>";
margin++;
}
html = util.tableHeader("Death List", (GLOBAL[channel].color || "darkblu
e"), 2, margin, false) + html + "</table><br/>";
sys.sendHtmlMessage(src, html, channel);
}
this.edit = function(src, channel, data, file){
if (!data){
this.show(src, channel, file);
return;
}
var words = sys.getFileContent(file).split("\n");
words.pop();
n = parseInt(data);
if (!isNaN(n)){
if (n < 1 || n > words.length){
sys.sendMessage(src, "Sorry, " + n + " is not a valid index.", c
hannel);
return;
}
var removed = words.splice(n-1, 1);
words = words.join("\n");
sys.writeToFile(file, words + "\n");
util.tellOthers(2, channel, sys.name(src) + " has removed the death:
" + util.escapeHtml(removed[0]));
} else if (/%s/.test(data)){
data = data.replace(/\\n/g, "\\n");
sys.appendToFile(file, data + "\n");
util.tellOthers(2, channel, sys.name(src) + " has added the death: "
+ util.escapeHtml(data));
} else {
sys.sendMessage(src, "Parameter must be an index to remove or a deat
h message containing %s.", channel);
}
}
this.pokedeathmod = function(src, channel, data){
this.edit(src, channel, data, this.POKEDEATH);
}
this.deathmod = function(src, channel, data){
this.edit(src, channel, data, this.DEATH);
}
this.send = function(src, channel, data){
var muteval;
if ((muteval = helper("isMuted", src, channel)) > 1){
util.failMuted(src, channel);
return;
}
if (muteval == 1){
sys.sendHtmlMessage(src, data, channel);
} else {
sys.sendHtmlAll(data, channel);
callhooks("afterChatMessage", src, data, channel);
}
return true;
}
this.death = function(src, channel, data, file){
if (util.isEvent(src)){
return;
}
var words;
if (!data){
words = sys.getFileContent(file).split("\n");
if (words.length < 1){
sys.sendMessage(src, "Broken/invalid file; please inform Nyu of
this", channel);
return;
}
var line = sys.rand(0, words.length-1);
words = words[line].replace("%s", sys.name(src));
if (!words){
sys.sendMessage(src, "Ohs noes something broke (Your magic numbe
r: " + line + "; please inform Nyu of this).", channel);
return;
}
} else {
words = sys.name(src) + (/^'/.test(data) ? "" : " ") + data;
}
var newwords = helper("markdown", src, channel, words);
if (newwords === false){
return;
} else if (newwords === null){
newwords = util.escapeHtml(words);
}
var message = "<" + src + "><font color='" + util.nameColor(src) + "'><t
imestamp/>~~~ " + newwords + " ~~~</font>";
if (this.send(src, channel, message)){
util.setEvent(src, true);
sys.callQuickly("sys.kick(" + src + ")", 100);
}
}
this.me = function(src, channel, data){
if (!data){
util.failParameters(src, channel);
return;
}
newdata = helper("markdown", src, channel, data);
if (newdata === false){
return;
} else if (newdata === null){
newdata = util.escapeHtml(data);
}
var message = "<" + src + "><font color='" + util.nameColor(src) + "'><t
imestamp/>*** " + sys.name(src)
+ (/^'/.test(data) ? "" : " ") + newdata + " ***</font>";
this.send(src, channel, message);
}
this.die = function(src, channel, data){
this.death(src, channel, data, this.DEATH);
}
this.pokedie = function(src, channel, data){
this.death(src, channel, data, this.POKEDEATH);
}
this.me.help = ["action", "Performs action."];
this.die.help = ["action", "Kills yourself.", "If no action given, a random
preset will be chosen."];
this.pokedie.help = ["", "Death by pokemon."];
this.deathmod.help = ["index|text", "Modifies the default /die texts.", "Wit
h no arguments, lists available deaths by index. If argument is an index, remov
es index from the file. If argument is text, adds text to the death file. Text
must contain %s which is substituted with the username. Note that with without
arguments, it potentially prints a really large annoying list."];
this.pokedeathmod.help = ["index|text", "Modifies the default /pokedie texts
.", "With no arguments, lists available deaths by index. If argument is an inde
x, removes index from the file. If argument is text, adds text to the death fil
e. Text must contain %s which is substituted with the username. Note that with
without arguments, it potentially prints a really large annoying list."];
} /* }}} */
/* {{{ Help Module: Provides a help command for explaining various commands */
function Help(){
this.init = function(){
register(0, "help", this, "commands", "h", "man");
register(0, "alias", this, "aliases");
}
this.colors = ['#24434B', '#FA7F4B', '#FC325B', '#24434B'];
this.alias = function(src, channel, data){
var auth = util.isAuth(src, channel);
if (auth == -1){
auth = 2;
} else if (auth > 3){
auth = 3;
}
var margin = 1, html = "";
var commands = []
for (var i in GLOBAL.aliases){
for (var j=0;j<=auth;j++){
if (GLOBAL.aliases[i] in GLOBAL.calls[j]){
if (commands[j] == undefined){
commands[j] = {};
}
if (commands[j][GLOBAL.aliases[i]] == undefined){
commands[j][GLOBAL.aliases[i]] = [];
}
commands[j][GLOBAL.aliases[i]].push(i);
break;
}
}
}
for (var i=0;i<=auth;i++){
for (var j in commands[i]){
margin++;
html += "<tr><td><font color='" + this.colors[i] + "'><b>" + j +
"</b></td><td align='center'>:</td><td>" + commands[i][j].join(", ") + "</td></
tr>";
}
}
html = util.tableHeader("Aliases", (GLOBAL[channel].color || "green"), 3
, margin, false) + html + "</table><br/>";
sys.sendHtmlMessage(src, html, channel);
}
this.help = function(src, channel, data){
var helpstr, args, auth = util.isAuth(src, channel);
if (auth == -1){
auth = 2;
} else if (auth > 3){
auth = 3;
}
var lower = 0
var n = parseInt(data);
if (!isNaN(n) && n >= 0 && n <= auth){
data = null;
lower = n;
auth = n;
}
if (data){
data = translate(data.replace(/^[\/!]/, ""))
for (var i=auth;i>=0;i--){
if ((data in GLOBAL.calls[i] && ((helpstr = GLOBAL.calls[i][data
][data].help) != undefined))){
if (GLOBAL.calls[i][data][data].authonly && sys.auth(src) <
2){
util.failPermission(src, channel);
return;
}
args = helpstr[0].replace(/^(.+?)$/, "[$1]").replace(/\s+/g,
"]&nbsp;[");
sys.sendHtmlMessage(src, "<font color='" + (GLOBAL[channel].
color || this.colors[i]) +
"'><timestamp/><b>±Help: </b></font><font color='" + t
his.colors[i] + "'><b>/" + data + "</b></font><i> " + args + "</i> - " +
helpstr[1] + (helpstr.length == 3 ? " " + helpstr[2]
: ""), channel);
break;
}
}
if (!helpstr){
if (data in GLOBAL.helps){
sys.sendHtmlMessage(src, GLOBAL.helps[data](GLOBAL[channel].
color || "purple"), channel);
} else {
util.failParameters(src, channel);
}
}
} else {
var margin = 1, html = "";
for (var i=lower;i<=auth;i++){
for (var c in GLOBAL.calls[i]){
helpstr = GLOBAL.calls[i][c][c].help;
if (helpstr){
if (GLOBAL.calls[i][c][c].authonly && sys.auth(src) < 2)
{
continue;
}
args = helpstr[0].replace(/^(.+?)$/, "[$1]").replace(/\s
+/g, "]&nbsp;[");
html += "<tr><td><font color='" + this.colors[i] + "'><b
>" + c + "</b></font><i> " + args + "</i> - " + helpstr[1] + "</td></tr>";
margin++;
}
}
}
if (lower == 0){
var other = ""
for (var i in GLOBAL.helps){
other += "<font color='" + this.colors[0] + "'><b>" + i + "<
/b></font>, ";
margin++;
}
other = other.replace(/,([^,]+), $/, " and $1.");
html += "<tr><td>Other help topics: " + other + "</td></tr>";
}
html = util.tableHeader("Help: All commands must be prefixed with ei
ther / or !", (GLOBAL[channel].color || this.colors[2]), 1, margin, true) + html
+ "</table><br/>";
sys.sendHtmlMessage(src, html, channel);
}
}
this.alias.help = ["", "Displays aliases for commands."];
this.help.help = ["level|command", "Display help on given command.", "If lev
el is provided, only display commands for that auth level. Also, yay recursion!"
]
GLOBAL.helps["users"] = function(color){ return util.tableHeader("Users", co
lor, 2, 24, true) +
"<tr><td colspan='2' align='center'>For any command which expects a user
as an argument (/kick, /join, etc.), " +
"the argument can be given in any of the following ways. " +
"<tr><th colspan='2'></th></tr><tr><th colspan='2'>Username</th></tr>" +
"<tr><td colspan='2' align='center'>The most basic form of specifying a
user." +
"Simply provide the username as an argument. " +
"Separate multiple usernames with a colon: This will also work for o
ffline users when applicable.</td></tr>" +
"<tr><td><b>/kick AnnoyingUser</b></td><td>Will kick AnnoyingUser</td></
tr>" +
"<tr><td><b>/kick Me : You : The World</b></td><td>Will kick Me, You, an
d The World.</td></tr>" +
"<tr><th colspan='2'></th></tr><tr><th colspan='2'>User ID</th></tr>" +
"<tr><td colspan='2' align='center'>Specify the user ID by prefixing a *
. " +
"See /userlist for a list of IDs.</td></tr>" +
"<tr><td><b>/mute *1 *2 *3</b></td><td>Will mute users with the IDs of 1
, 2, and 3.</td></tr>" +
"<tr><td><b>/mute *0</b></td><td>Performs a channel-mute.</td></tr>" +
"<tr><th colspan='2'></th></tr><tr><th colspan='2'>Combinations</th></tr
>" +
"<tr><td colspan='2' align='center'>You can combine any of the above met
hods:</td></tr>" +
"<tr><td><b>/ban BanAvoider *2 : Muffin</b></td><td>Will ban BanAvoider,
userID 2, and Muffin.</td></tr>" +
"<tr><th colspan='2'></th></tr><tr><th colspan='2'>Regex</th></tr>" +
"<tr><td colspan='2' align='center'>Specify a regex pattern by prefixing
a ~. " +
"For complete regex documentation, see <a href='http://www.javascrip
tkit.com/javatutors/re2.shtml'>here</a>. " +
"Regex is case-sensitive but can match anywhere in the username. You
cannot use regex in combination with any of the above methods.</td></tr>" +
"<tr><td><b>/admin ~A</b></td><td>Will admin anyone with an <i>A</i> in
their name</td></tr>" +
"<tr><td><b>/mod ~^\\[\\+INF\\]</b></td><td>Will mod anyone whose name s
tarts with <i>[+INF]</i>.</td></tr>" +
"<tr><td><b>/kick ~\\d$</b></td><td>Will kick all users whose name ends
with a number.</td></tr>" +
"<tr><td colspan='2'>&nbsp;</td></tr></table>"
}
GLOBAL.helps["scripts"] = function(color){ return util.tableHeader("Reborn S
cripts", color, 1, 3, true) +
"<tr><td align='center'>This script written by Nyu under the <a href='ht
tp://sam.zoy.org/wtfpl/COPYING'>WTF Public License</a>.<br/></td></tr>" +
"<tr><td align='justify' style='padding-right: 20px'>All necessary files
to use this script can be found in this zip <a href='http://s.sadpancake.com/po
_scripts.zip'>here</a>." +
"Note that due to my lazyness the zip file might be slightly out of date
, in which case you can get the script itself <a href='http://sadpancake.com/reb
orn'>here</a>. " +
"This file is symlinked to Reborn's current scripts, so it is always 100
% updated, regardless of the Last Update thing that I always forget to change...
" +
"Of course, feel free to add/remove/modify/whatever you'd like, or talk
to me if you have any questions/comments/complaints/suggestions/food/etc. " +
"If you'd like to customize this script for your own server, look in the
Server function, as that's where most of the things you'll want to change are h
iding at. " +
"Many thanks to all the people that provided testing, code extracts, ide
as, and the like. Kbai~</td></tr></table><br/>";
}

} /* }}} */
/* {{{ 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(/^(&gt;&gt;(?![;:]|.?(?:&gt;|&lt;)|[:;]?[3DOo0
\]\[](?:$|\s)).*?(?=\S).*)$/, "<font color='" + c2 + "'>$1</font>");
message = message.replace(/^(&gt;(?!_+&gt;|.?(?:&gt;|&lt;)|[:;]?[3DOo0\]
\[|](?:$|\s)).*?(?=\S).*)$/, "<font color='" + c1 + "'>$1</font>");
message = message.replace(/\\\*/g, "&#42;").replace(/\\_/g, "&#95;");
message = message.replace(/\\\[/g, "&#91;").replace(/\\\]/g, "&#93;");
message = message.replace(/\\\(/g, "&#40;").replace(/\\\)/g, "&#41;");
message = message.replace(/\\-/g, "&#45;").replace(/\\\)/g, "&#41;");
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)_&gt;_(?=$|\s)/g, "$1→").replace(/(^|\W)_
&lt;_(?=$|\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
+ "'>&gt;" + c1 + "</font>, <font color='" + c2 + "'>&gt;&gt;" + 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] + "'>&gt;" + GLOBAL[channel
].quotecolor[0] + "</font>, <font color='" +
GLOBAL[channel].quotecolor[1] + "'>&gt;&gt;" + 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] || "&lt;disallowed&gt;") + "</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, "&#47");
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>&gt;color1</td><td><font color='darkblue'>&gt;color1</font></td
></tr>" +
"<tr><td>&gt;&gt;color2</td><td><font color='green'>&gt;&gt;color2</font
></td></tr>" +
"<tr><td>\\_escaped\\_</td><td>_escaped_</td></tr>" +
"<tr><td colspan='2'>&nbsp;</td></tr></table>"
}
this.quotecolor.help = ["color1 color2", "Changes the markdown'd quote color
s.", "First color is for &gt;single quotes, second color is for &gt;&gt;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 + "'>&nbsp;&nbsp;&nbsp;</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, "&amp;").replace(/</g, "&lt;").replace(/>/g
, "&gt;");
}
}
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);
}
})

Potrebbero piacerti anche