// Bumble // http://puu.sh/87TqH.png // TODO: ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // maybe make Commands.handle return a bool for if it threw an error or whatever, idk if this would be useful atm though // // make plugins more traceable maybe // // we should make some default plugins or somethin so ppl think they're cool and not dumb, like why yell // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // pup // /* !-------------! ! c",its ! !-------------! ! ~ ~ ~ ~ ~ ~ ! !-------------! ! wardrober ! !-------------! ! pup ! ! uso ! ! vnistelrooy ! !-------------! ! ~ ~ ~ ~ ~ ~ ! !-------------! ! directors ! !-------------! ! songysing ! !-------------! */ // version things, caps bc thats how version things are. // var VERSION = "0.9.8.7"; var VERSIONNAME = "rad sux"; var WHATSNEW = [ "

0.9.8.0

• Dumb link buge (thanks us o)", "

0.9.8.1

• Emote bge", "

0.9.8.2

• Ignore bug", "

0.9.8.3

• Autoresponse bug", "

0.9.8.4

• /tiers is show more (all) tiers now", "

0.9.8.5

• fixed pastebin thing", "

0.9.8.6

• Added option to not have timestamps copy message to textbox for jinora", "

0.9.8.7

• Allow same response and keyphrase" ].join("
"); // actual things start here // var globe = this; var network = client.network(); var alphabet = "abcdefghijklmnopqrstuvwxyz"; // this isnt a joke lol then why are you laughing var celebiPic = ""; var acceptCommand = true; var stopSay = true; var oaCounter = 0; var oaTimer = undefined; var initCheck = false; var emotesCheck = false; var settings = {}; // holds settings var emotes = {}; // holds emote data, not the actual img tag and everything, so use Emotes.emote(name) instead of emotes[name] var tiers = {}; // holds tier data var cache = {}; // holds various things, used for dynamic vars that aren't necessarily needed. Good for passing vars throughout the script. var timers = {}; // holds timers var emoteString = ""; var emoteList = []; var commandTypes = ["general", "social", "settings", "all"]; var defaults = { "botColour": "#318739", "botName": "Celebi", "botSymbol": "±", "commandSymbol": "~", "paramSeparator": ";", "authSymbols": { "0": "", "1": "+", "2": "+", "3": "+", "4": "" }, "authStyles": { "0": "", "1": "", "2": "", "3": "", "4": "" }, "enrichedText": true, "emotes": true, "flashColour": "gold", // dr gold "flashes": true, "stalkwords": [], "friends": [], "fullwidth": false, "shortcuts": {}, "ignoreChallenges": false, "autoUpdate": true, "commandLinkStyle": "text-decoration:none; font-weight:bold;", "logChannels": [], "logEvents": true, "logEventChannels": {}, "txtLogs": "txt", "responses": {}, "responseBlacklist": [ "Tohjo Falls", "Tournaments", "Trivia", "Mafia", "Blackjack" ], "allowDefine": false, "responsesOn": true, "cleanSettings": true, "overactiveLimit": 40, "overactiveSeconds": 40, "version": VERSION, "timestampCopy": true }; var settingsPath = "bumble.json"; var emotesPath = "emotes.json"; var tiersPath = "tiers.json"; var logPath = "Channel Logs/"; var pluginsPath = "Bumble Plugins/"; var scriptUrl = "https://raw.githubusercontent.com/SongSing/ClientScripts/master/bumble.js"; var emotesUrl = "https://raw.githubusercontent.com/SongSing/ClientScripts/master/Emotes.json"; // commands - don't need to be in order by type (ordered automatically in Commands.print), i just think it makes the code look nicer :3 // // format: [type]commandname [param]((sep))[param] - description // var commands = [ "[general]commandslist - Shows general commands", "[general]commandslist [type] - Shows commands related to [type]. [type] can be: ((types))", "[general]update - Checks for updates", "[general]updateemotes - Downloads the emotes file", "[general]updatetiers - Parses and downloads PO's current tiers for use with the ((cs))tiers command", "[general]lookup [name] - Displays information about [name]", "[general]pm [name] - Opens PM window with [name] selected", "[general]ranking [name] - Opens ranking window and selects [name]", "[general]changename [name] - Attempts to change your name to [name]", "[general]eval [string] - Runs [string] through a JavaScript evaluator. Can be used for math and things!", "[general]emotes - Shows available emotes", "[general]emotes [on/off] - Enables/disables emotes", "[general]ignorechallenges [on/off] - Enables or disables auto-ignored challenges", "[general]tier [tier] - Gives information on [tier]", "[general]tiers [pokemon] - Lists some tiers that [pokemon] is in", "[general]usage [tier] - Gives top 50 used Pokémon in [tier]", "[general]usage [tier]((sep))[amt] - Gives top [amt] used Pokémon in [tier]", "[general]whatsnew - Displays the What's New? message for your current version", "[general]randomno [min]((sep))[max] - Gives a random number between [min] and [max]", "[general]trivia [thing] - Attempts to retrieve trivia for [thing] from Bulbapedia", "[general]pastebin [string] - Creates a pastebin of [string] and displays link; Use \\n for newlines", "[general]timers - Shows a list of your set timers", "[general]settimer [name]((sep))[duration]((sep))[message?] - Sets a timer that will go off after [duration]; [duration] can be something like 5m or 12s", "[general]unsettimer [name] - Unsets timer [name]", "[general]reconnect - Attempts to reconnect to the server", "[social]stalkwords - Shows a list of your stalkwords", "[social]addstalkword [stalkword] - Adds [stalkword] to your stalkwords", "[social]removestalkword [stalkword] - Removes [stalkword] from your stalkwords", "[social]friends - Shows a list of your friends", "[social]addfriend [name] - Adds [name] to your friends", "[social]removefriend [name] - Removes [name] from your friends", "[social]shortcuts - Shows a list of your shortcuts", "[social]addshortcut [shortcut]((sep))[text] - Makes it so [shortcut] is automatically replaced with [text] in messages you send", "[social]removeshortcut [shortcut] - Removes [shortcut] from your shortcuts", "[social]logchannels - Shows a list of the channels you're logging", "[social]addlogchannel [channel] - Adds [channel] to the channels you're logging", "[social]removelogchannel [channel] - Removes [channel] from the channels you're logging", "[social]responses - Shows a list of your autoresponse keyphrases and responses", "[social]responses [on/off] - Turns autoresponse on or off", "[social]addresponse [keyphrase]((sep))[response] - Adds [response] to [keyphrase] - You won't be able to trigger this yourself", "[social]removeresponse [keyphrase]((sep))[response] - Removes [response] from [keyphrase]", "[social]clearresponses [keyphrase] - Clears all responses from [keyphrase] and deletes [keyphrase]", "[social]addblacklist [channel] - Adds [channel] to your autoresponse blacklist - Official channels are blacklisted by default", "[social]removeblacklist [channel] - Removes [channel] from your blacklist - If you remove an official channel, I hold no responsibility for your mute :)", "[social]allowdefine [on/off] - If on, allows others to create responses with ((ownName))define keyphrase((sep))response", "[settings]setcommandsymbol [symbol] - Changes your command symbol to [symbol]", "[settings]setbotname [name] - Changes my name to [name]", "[settings]setbotcolour [colour] - Changes my colour to [colour]", "[settings]enrichedtext [on/off] - Enables or disables enriched text", "[settings]setauthsymbol [symbol]((sep))[level] - Changes symbol used to denote [level]-level auth. [level] is an integer from 0 to 4", "[settings]clearauthsymbol [level] - Deletes any auth symbol used to denote [level]-level auth. [level] is still and integer from 0 to 4", "[settings]setauthstyle [style]((sep))[level] - Changes style used to denote [level]-level auth. [style] should be opening HTML tags (<b><i>)", "[settings]flashes [on/off] - Enables or disables flashes", "[settings]timestampcopy [on/off] - Enables or disables timestamp copying (click a timestamp to copy a message into the textbox)", "[settings]setflashcolour [colour] - Changes the highlight colour of your name and stalkwords", "[settings]setseparator [separator] - Sets the command parameter separator to [separator]", "[settings]fullwidth [on/off] - Turns automatic text-to-fullwidth conversion on or off", "[settings]autoupdate [on/off] - Turns automatic checking for updates at startup on or off", "[settings]logevents [on/off] - Turns logging of people entering/exiting channels on or off", "[settings]logevents [on/off]((sep))[channel] - Turns logging of people entering/exiting [channel] on or off", "[settings]txtlogs [txt/html/both] - When txt, saves logs as text; when html, saves them as HTML (which takes up more space, but arguably looks nicer); when both, saves them as both", "[settings]settings - Shows list of script settings", "[settings]setsetting [setting]((sep))[value] - Sets [settings]'s value to [value] IF YOU BREAK SCRIPTS WITH THIS IT'S YOUR FAULT", "[settings]clearsetting [setting] - Clears [setting]'s value — can be used to reset script settings to their default", "[secret]letsgetmarried [y/n] - Not a real command, but I think I'm in love with you..." ]; /*String.prototype.args = function(arg) { var ret = this; ret = ret.replace(/(%[0-9]+)/g, "($1)"); // for %10 etc for (var i = 0; i < arg.length; i++) { ret = ret.replace(new RegExp("\\(%" + (i + 1) + "\\)", "g"), arg[i].toString()); } return ret; };*/ String.prototype.args = function() { var arg = arguments; var ret = this; ret = ret.replace(/(%[0-9]+)/g, "($1)"); // for %10 etc for (var i = 0; i < arg.length; i++) { ret = ret.replace(new RegExp("\\(%" + (i + 1) + "\\)", "g"), arg[i].toString()); } return ret; }; function init() { initCheck = true; sys.unsetAllTimers(); if (sys.isSafeScripts()) { print("Hey. You don't have safe scripts off. That is a problem!! You need to go to the script window and make sure safe scripts are off to use this. Nothing bad should happen, I promise!"); sys.changeScript(""); // nop return false; } cache = {}; var newUser = false; Utilities.appendFile(settingsPath, ""); // make sure it's there! if (Utilities.readFile(settingsPath) === "") { // say hi! // print(Utilities.centerText("

Hi!

Type " + Utilities.commandLink("~commandslist", "commandslist") + " to get started!


" + celebiPic + "
")); newUser = true; } Settings.load(); Utilities.loadTiers(); Emotes.load(); Plugins.load(); if (settings.autoUpdate) { // haha this confusing // Utilities.checkForUpdate(); } if (settings.version !== VERSION || newUser) { // update version setting and print what's new // settings.version = VERSION; Settings.save(); Utilities.printWhatsNew(); } Plugins.callHooks("init", { "newUser": newUser }); return true; } function print(message, channel, html) { if (channel === undefined) { channel = client.currentChannel(); } if (html === undefined) { html = true; } client.printChannelMessage(message, channel, html); } function printAll(message) { client.printLine(message); } function printMessage(message, html, channel) { if (html === undefined) { html = true; } print(botHTML() + " " + (html ? message : Utilities.escapeHTML(message)), channel, true); } function printUserMessage(m, u, channel) { var msg = Utilities.formatMessage(m, u); print(msg, channel, true); if (cache.flash && settings.trayFlash && client.trayMessage && !client.windowActive()) { client.trayMessage("Flashed in " + client.channelName(channel), msg); } } function say(message, channel) { if (oaTimer === undefined) { oaTimer = sys.setTimer(function() { oaCounter = 0; oaTimer = undefined; }, settings.overactiveSeconds, false); } if (oaCounter < settings.overactiveLimit) { oaCounter++; if (channel === undefined) { channel = client.currentChannel(); } network.sendChanMessage(channel, message); } else if (oaCounter == settings.overactiveLimit) // i think i had reason for == but i cant remember :0 { printMessage("Ooh, saved you! You almost passed your overactive limit!"); oaCounter++; } } function botHTML(timestamp, colon, symbol) { if (timestamp === undefined) timestamp = true; if (colon === undefined) colon = true; if (symbol === undefined) symbol = true; return "" + (timestamp ? "" : "") + "" + (symbol ? settings.botSymbol : "") + Utilities.escapeHTML(settings.botName) + (colon ? ":" : "") + ""; } function cmp(x1, x2) { if (typeof x1 !== typeof x2) { return false; } else if (typeof x1 === "string") { if (x1.toLowerCase() === x2.toLowerCase()) { return true; } } return x1 === x2; } Array.prototype.indexOf = function (item, caseSensitive) { if (caseSensitive === undefined) { caseSensitive = false; } for (var i = 0; i < this.length; i++) { if ((cmp(this[i], item) && !caseSensitive) || this[i] === item) { return i; } } return -1; }; Array.prototype.format = function(fn, num) { var ret = []; if (!num) { num = false; } for (var i = 0; i < this.length; i++) { var formatted = eval('"' + fn.replace(/%i/g, this[i]) + '"'); // quotes or it thinks its a var hahas if (num) formatted = parseFloat(num); ret.push(formatted); } return ret; }; Array.prototype.copy = function() { return this.slice(0); }; Array.prototype.randomItem = function() { if (this.length === 0) return undefined; var r = Utilities.randomInt(this.length); return this[r]; }; Array.prototype.clean = function(deleteValue) { if (deleteValue) { var ret = this.copy(); for (var i = 0; i < ret.length; i++) { if (ret[i] == deleteValue) { ret.splice(i, 1); i--; } } return ret; } else { var ret = this.copy(); for (var i = 0; i < ret.length; i++) { if (!ret[i]) { ret.splice(i, 1); i--; } } return ret; } }; Array.prototype.reverse = function() { var ret = []; for (var i = this.length - 1; i >= 0; i--) { ret.push(this[i]); } return ret; } String.prototype.indexOf = function(str, caseIns) { if (str === undefined || str.length === 0 || str.length > this.length) return -1; if (caseIns === undefined) caseIns = true; if (cmp(str, this)) return 0; for (var i = 0; i < this.length; i++) { if ((cmp(this.substr(i, str.length), str) && caseIns) || (this.substr(i, str.length) === str && !caseIns)) { return i; } } return -1; }; String.prototype.startsWith = function(text, ins) { if (ins === undefined) ins = false; var str = this; if (text.length > str.length) return false; if (!ins) return str.substr(0, text.length) === text; else return cmp(str.substr(0, text.length), text) }; String.prototype.startsWithOne = function(arr, ins) { var arg = arr; for (var i = 1; i < arg.length; i++) { if (this.startsWith(arg[i], ins)) { cache.startsWithWhich = arg[i]; return true; } } return false; }; String.prototype.endsWith = function(text, ins) { if (ins === undefined) ins = false; var str = this; if (text.length > str.length) return false; if (!ins) return str.substr(str.length - text.length) === text; else return cmp(str.substr(str.length - text.length), text); }; String.prototype.trimString = function(str) { if (str === undefined) str = " "; var ret = this; while (ret.startsWith(str)) { if (ret.length < str.length) { return ret; } ret = ret.substr(str.length); } while(ret.endsWith(str)) { if (ret.length < str.length) { return ret; } ret = ret.substr(0, ret.length - str.length); } return ret; }; String.prototype.contains = function(str) { return this.indexOf(str) !== -1; }; Array.prototype.contains = function(item) { return this.indexOf(item) !== -1; }; Settings = ({ load: function(json) { if (json === undefined) { if (sys.getFileContent(settingsPath) === "") { // load default // settings = defaults; } else { settings = JSON.parse(Utilities.readFile(settingsPath)); } } else { settings = JSON.parse(json); } this.save(); }, save: function() { for (var key in defaults) { if (defaults.hasOwnProperty(key) && !settings.hasOwnProperty(key)) // defaults has values that settings don't, so we'll need to add them in! { settings[key] = defaults[key]; } else // actual setting, check to make sure its not broke { if (typeof(settings[key]) !== typeof(defaults[key])) { settings[key] = defaults[key]; printMessage(key + " was reset due to a type error! ...It's your fault!", false); } } } if (settings.cleanSettings) { for (var key in settings) { if (settings.hasOwnProperty(key) && !defaults.hasOwnProperty(key)) { delete settings[key]; // cleans up unused settings } } } Utilities.writeFile(settingsPath, JSON.stringify(settings)); } }); Emotes = ({ load: function(force) { if (force === undefined) { force = false; } Utilities.appendFile(emotesPath, ""); if (Utilities.readFile(emotesPath) === "" || force) { // get emotes printMessage("Hang on, getting emotes... This could take a sec...", false); var ejson = Utilities.webCall(emotesUrl); if (ejson.length < 1) { printMessage("There was a problem downloading emotes. Turning emotes off.", false); settings.emotes = false; // lol this was not here for several month just comment say "turn off" im rly bad return; } printMessage("Got 'em! See your emotes with %1!".args(Utilities.commandLink(settings.commandSymbol + "emotes", "emotes")), true); Utilities.writeFile(emotesPath, ejson); emotes = JSON.parse(ejson); } else { emotes = JSON.parse(Utilities.readFile(emotesPath)); } emoteString = ""; for (var x in emotes) { if (emotes.hasOwnProperty(x)) { var emote = "%2 ".args(x, Emotes.emote(x)); emoteString += emote; emoteList.push(emote); } } }, parse: function(text, force) { if (!settings.emotes && !force) { return text; } var ret = text; // we need to check to see if they did it in fullwidth, but we shouldn't just unfullwidth the whole thing // // ahahahahaha you said "did it" // ret = ret.replace(/:([qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890+-_.'!? ]+):/g, function(match) { var _match = Utilities.unfullwidth(match).toLowerCase(); if (Emotes.check(_match)) { return _match; } return match; }); return ret.replace(/\:([a-zA-Z0-9\+\-_\.'\!\?\s]+)\:/g, function(match) // extra things are for pokenames { var name = match.substr(1, match.length - 2).toLowerCase(); // special cases // if (name === "unown-a") { name = "unown"; } // now return // if (Emotes.check(name)) { return Emotes.emote(name); } return match; }); }, emote: function(name) { var pname = name.replace(/_/g, " "); if (emotes.hasOwnProperty(name)) { return ""; } else if (sys.pokeNum(pname) > 0 || cmp(pname, "missingno")) { return ""; } }, check: function(name) { var pname = name.replace(/_/g, " "); return emotes.hasOwnProperty(name) || sys.pokeNum(pname) > 0 || cmp(pname, "missingno"); } }); Plugins = ({ hooks: {}, load: function() { var files = sys.filesForDirectory(pluginsPath); if (typeof(files) === "undefined") { sys.makeDir(logPath); files = []; } for (var i = 0; i < files.length; i++) { if (!files[i].endsWith(".js")) { continue; } try { eval(Utilities.readFile(pluginsPath + files[i])); printMessage("Loaded plugin: " + files[i], false); } catch (err) { printMessage("There was an error in loading plugin " + files[i] + "!", false); printMessage("Error: " + err, false); if (err.lineNumber) { printMessage("On line: " + err.lineNumber, false); } } } }, hook: function(event, fn) { // how hook works: // // we have a json object which contains arrays of functions. // // we get the right array and append the function to be called by callHooks // if (!this.hooks.hasOwnProperty(event)) { this.hooks[event] = []; } this.hooks[event].push(function(data, scope) { if (data === undefined) data = {}; if (scope === undefined) scope = globe; // will this ever be useful?? fn.call(scope, data); // still call since obj }); }, callHooks: function(event, data, scope) { // how callHooks works: // // we have a json object which contains arrays of functions. // // we get the right array from the event name and cycle through and call all of the hooked functions // if (!this.hooks.hasOwnProperty(event)) { this.hooks[event] = []; } for (var i = 0; i < this.hooks[event].length; i++) { try { this.hooks[event][i](data, scope); // calls function } catch (err) { // we could make this more traceable but eh // printMessage("Error in hook function " + event + i + ": " + err); printMessage("On line: " + err.lineNumber); } } } }); Utilities = ({ checkForUpdate: function() { printMessage("Checking for update..."); var myScript = this.readFile(sys.scriptsFolder + "scripts.js"); var onlineScript = this.webCall(scriptUrl); if (!onlineScript) { printMessage("Couldn't connect!"); return; } if (myScript === onlineScript) { printMessage("No update available!"); return; } printMessage("There's an update available! " + Utilities.commandLink("(Click here to update)", "doupdate")); }, downloadUpdate: function() { printMessage("BEEP BOOP UPDATING BEEP"); var resp = this.webCall(scriptUrl); if (!resp) { printMessage("Coundn't update!"); return; } printMessage("Mmmkay, updated!"); sys.changeScript(resp); sys.writeToFile(sys.scriptsFolder + "scripts.js", resp); }, webCall: function(url, args) { // prevent weird webcall bug // if (!cache.webCalling) { cache.webCalling = true; var ret; if (args === undefined) ret = sys.synchronousWebCall(url); else ret = sys.synchronousWebCall(url, args); while (ret === undefined) { // wait } cache.webCalling = false; return ret; } printMessage("A webcall is currently in progress - try again later."); return ""; }, channelNames: function() { var ret = []; var channels = client.channelNames(); for (var channel in channels) { if (channels.hasOwnProperty(channel)) { ret.push(channels[channel]); } } return ret; }, isChannel: function(name) { return this.channelNames().contains(name); }, readFile: function(file) { return sys.getFileContent(file); }, writeFile: function(file, contents) { sys.writeToFile(file, contents); }, appendFile: function(file, contents) { sys.appendToFile(file, contents); }, centerText: function(text) { return "
" + text + "
"; }, getMessage: function(message) { return (message.indexOf(": ") !== -1 ? message.substr(message.indexOf(":") + 2) : message); }, getUser: function(message) { return (message.indexOf(": ") !== -1 ? message.split(": ")[0] : undefined); // throw some sort of error if we're doing something we shouldn't be }, isPlayerOnline: function(name) { return client.id(name) !== -1; }, isPlayerBattling: function(id) { return (client.player(id).flags & (1 << 2)) > 0; }, escapeHTML: function(text) { if (typeof(text) === "object") { // it's an array so we need to cycle through and yeah // var arr = text.copy(); for (var i = 0; i < arr.length; i++) { arr[i] = this.escapeHTML(arr[i]); } return arr; } if (text.length > 0) { var amp = "&am" + "p;"; var lt = "&l" + "t;"; var gt = "&g" + "t;"; return text.replace(/&/g, amp).replace(//g, gt).replace(/\$/g, "$"); } return ""; }, unescapeHTML: function(text) { if (text.length > 0) { var amp = "&"; var lt = "<"; var gt = ">"; return text.replace(/&/g, amp).replace(/</g, lt).replace(/>/g, gt); } }, escapeRegex: function(text) { return text.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); }, fixLinks: function(message) { return message.replace(/([a-zA-Z]+:\/\/|www\.)((?:(?! ).)+)/ig, "$1$2") .replace(/([abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]+://|www.)((?:(?! ).)+)/ig, function(match) { return "%2".args(Utilities.unfullwidth(match), match); }) .replace(/#(.+)/g, function(match) { var test = match.substr(1); var ret = match; for (var i = 1; i <= test.length; i++) { if (Utilities.isChannel(test.substr(0, i))) { ret = "#%1%2".args(test.substr(0, i), test.substr(i)); } } return ret; }); }, enrich: function(text) { if (!settings.enrichedText) { return text; } //if (settings.fullwidth) //{ text = text.replace(/(^|\s| )*(.+?)*($|\s| )/g, "$1*$2*$3").replace(/(^|\s| )_(.+?)_($|\s| )/g, "$1_$2_$3").replace(/(^|\s| )/(.+?)/($|\s| )/g, "$1/$2/$3"); //} var ret = text.replace(/(^|\s| |\|\)\/(.+?)\/($|\s| |\<\/u\>|\<\/b\>)/g, "$1$2$3") .replace(/(^|\s| |\|\)_(.+?)_($|\s| |\<\/i\>|\<\/b\>)/g, "$1$2$3") .replace(/(^|\s| |\|\)\*(.+?)\*($|\s| |\<\/i\>|\<\/u\>)/g, "$1$2$3"); ret = ret.replace(/(^|\s| |\|\)\/(.+?)\/($|\s| |\<\/u\>|\<\/b\>)/g, "$1$2$3") .replace(/(^|\s| |\|\)_(.+?)_($|\s| |\<\/i\>|\<\/b\>)/g, "$1$2$3") .replace(/(^|\s| |\|\)\*(.+?)\*($|\s| |\<\/i\>|\<\/u\>)/g, "$1$2$3"); ret = ret.replace(/(^|\s| |\|\)\/(.+?)\/($|\s| |\<\/u\>|\<\/b\>)/g, "$1$2$3") .replace(/(^|\s| |\|\)_(.+?)_($|\s| |\<\/i\>|\<\/b\>)/g, "$1$2$3") .replace(/(^|\s| |\|\)\*(.+?)\*($|\s| |\<\/i\>|\<\/u\>)/g, "$1$2$3"); return ret; }, fullwidth: function(text, force) { if (force === undefined) force = false; if (!settings.fullwidth && !force) return text; var ret = ""; var fw = " `1234567890-=~!@#$%^&*()_+qwertyuiop[]\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:"zxcvbnm,./ZXCVBNM<>?"; var nw = " `1234567890-=~!@#$%^&*()_+qwertyuiop[]\\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:\"zxcvbnm,./ZXCVBNM<>?"; for (var i = 0; i < text.length; i++) { if (nw.contains(text[i])) { ret += fw[nw.indexOf(text[i], false)]; } } return ret; }, unfullwidth: function(text) { var ret = ""; var fw = " `1234567890-=~!@#$%^&*()_+qwertyuiop[]\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:"zxcvbnm,./ZXCVBNM<>?"; var nw = " `1234567890-=~!@#$%^&*()_+qwertyuiop[]\\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:\"zxcvbnm,./ZXCVBNM<>?"; for (var i = 0; i < text.length; i++) { if (fw.contains(ret[i])) { ret += nw[fw.indexOf(text[i], false)]; } } return ret; }, splitLines: function(text) { return text.replace(/\r/g, "").split("\n"); }, shortcuts: function(text) { var ret = text; var keys = settings.shortcuts; for (var key in keys) { if (keys.hasOwnProperty(key)) { ret = ret.replace(new RegExp(this.escapeRegex(key), "g"), keys[key]); } } return ret; }, capitalize: function(str) { str = str.toLowerCase(); if (str.indexOf(" ") !== -1) { var _str = str.split(" "); for (var i = 0; i < _str.length; i++) { _str[i] = this.capitalize(_str[i]); } str = _str.join(" "); } if (str.indexOf("-") !== -1) { var _str = str.split("-"); for (var i = 0; i < _str.length; i++) { _str[i] = this.capitalize(_str[i]); } str = _str.join("-"); } return str.charAt(0).toUpperCase() + (str.length > 1 ? str.substr(1) : ""); }, loadTiers: function(force) { if (force === undefined) { force = false; } if (!sys.fileExists(tiersPath) || force) { if (!this.getTiers()) { return false; } } var json = this.readFile(tiersPath); if (!json) { printMessage("Couldn't load tiers!"); return false; } tiers = JSON.parse(json); return true; }, getTiers: function() { var url = "https://raw.githubusercontent.com/po-devs/po-server-goodies/master/tiers.xml"; var json = {}; printMessage("Fetching tiers..."); var xml = this.webCall(url); // is there any convenient way to parse xml? if (!xml) { printMessage("Couldn't fetch tiers!"); return false; } xml = this.splitLines(xml); // xml is an array now // for (var i = 0; i < xml.length; i++) { var line = xml[i]; var indent = line.indexOf("<"); line = line.substr(indent); // removes leading space if (line.startsWith(" xml = xml.trim(); // we could instead count the spaces or tabs and use it to make a complete json object from an xml file, but is indent mandatory? etc xml = xml.substr(xml.indexOf(" ") + 1); // now we can get individual vars by splitting spaces var xmlvars = xml.split("\" "); for (var i = 0; i < xmlvars.length; i++) { var key = xmlvars[i].split("=")[0]; var val = xmlvars[i].split("=")[1]; val = (val === "\"" ? "" : val.substr(1)); // trims quote and detects empty var if (val.indexOf("\"") !== -1) // end of line, so there's prob no space { val = val.substr(0, val.indexOf("\"")); } json[key] = val; } return json; }, link: function(text, linkCommand, linkData, style) { if (linkCommand === undefined) { linkCommand = "send"; } if (style === undefined) { style = ""; } linkData = linkData.replace(/"/g, "&q" + "uot;").replace(/\?/g, "%3F"); // so it dont break or nothin return "%4".args(linkCommand, linkData, style, text); }, commandLink: function(text, command, linkCommand) { return this.link(text, linkCommand, "/" + command, settings.commandLinkStyle); }, printWhatsNew: function() { print(Utilities.centerText("

Bumble Version %1
\"%2\"

By SongSing

What's New?

%3

".args(VERSION, VERSIONNAME, WHATSNEW))); }, randomInt: function(arg1, arg2) { if (arg2 !== undefined) // randomInt(min, max) { return Math.floor(Math.random() * (arg2 - arg1)) + arg1; } else // randomInt(max) { return Math.floor(Math.random() * arg1); } }, hexToRgb: function(hex) { hex = hex.toString(); hex = hex.replace(/#/g, ""); var bigint = parseInt(hex, 16); var r = (bigint >> 16) & 255; var g = (bigint >> 8) & 255; var b = bigint & 255; return "(%1, %2, %3)".args(r, g, b); }, plainText: function(string) { string = string.replace(/\]+\>/gi, ""); return Utilities.unescapeHTML(string.replace(/(\<([^\>]+)\>)/g, "").replace(/ /g, " ")); }, saveToLog: function(message, channel, isUserMessage) { if (settings.txtLogs === "txt" || settings.txtLogs === "both") { var log = settings.logChannels.indexOf(client.channelName(channel)) !== -1; if (!log) return; var text; if (isUserMessage === undefined) isUserMessage = false; if (isUserMessage) { var m = message.substr(message.indexOf("<\/b>") + 5); if (cache.flash) { m = m.substr(0, m.length - 4); // get rid of
at the end of an italicized flash message } if (settings.enrichedText) m = m.replace(/\<\/?b\>/g, "*").replace(/\<\/?i\>/g, "/").replace(/\<\/?u\>/g, "_"); var text = this.plainText(message.substr(0, message.indexOf("<\/b>") + 5) + m); } else { text = this.plainText(message); } if (typeof (sys.filesForDirectory(logPath) === "undefined")) { sys.makeDir(logPath); } if (typeof (sys.filesForDirectory(logPath + client.channelName(channel)) === "undefined")) { sys.makeDir(logPath + client.channelName(channel)); } // we're gonna use moogle's format for compatibility // var time = new Date(); var h = time.getHours(); var m = time.getMinutes(); var s = time.getSeconds(); var d = time.getDate(); var mo = parseInt(time.getMonth() + 1); var y = time.getFullYear(); var date = d + "-" + mo + "-" + y; m = (m < 10 ? "0" + m : m); s = (s < 10 ? "0" + s : s); var timestamp = h + ":" + m + ":" + s; Utilities.appendFile(logPath + client.channelName(channel) + "/" + client.channelName(channel) + " " + date + ".txt", "(" + timestamp + ") " + text + "\r\n"); } if (settings.txtLogs === "html" || settings.txtLogs === "both") { var log = settings.logChannels.indexOf(client.channelName(channel)) !== -1; var colour; if (isUserMessage) { // get colour for timestamps colour = message.substr(message.indexOf("" + timestamp + ""; } Utilities.appendFile(logPath + client.channelName(channel) + "/" + client.channelName(channel) + " " + date + ".html", timestamp + " " + text + "
"); } }, formatMessage: function(m, u, colour) { var id = client.id(u); if (colour === undefined) var colour = client.color(id); var auth = client.auth(id); var authSymbol = settings.authSymbols[auth]; var authStyle = settings.authStyles[auth]; var name = Utilities.escapeHTML(u); var msg = m; msg = Utilities.escapeHTML(msg); msg = msg.replace(/ /g, " "); msg = Utilities.fixLinks(msg); msg = Utilities.enrich(msg); msg = Emotes.parse(msg); var flash = false; var ps = settings.paramSeparator; if (settings.flashes) { var _msg = msg; if (!cmp(u, client.ownName())) // don't flash yourself ;) { var stalkwords = settings.stalkwords.copy(); stalkwords.push(client.ownName()); for (var i = 0; i < stalkwords.length; i++) { msg = msg.replace(new RegExp("(^|\\s| )(" + Utilities.escapeRegex(stalkwords[i]).replace(/ /g, " ") + ")($|\\s| |\\!|\\?|\\.|\"|,|\\)|\\:|;)", "gi"), "$1$2$3".args(settings.flashColour)); } } flash = msg !== _msg; } else { msg = msg.replace(/\]+)\>/gi, ""); } cache.flash = flash; cache.formattedMessage = msg; Plugins.callHooks("formattedMessage", { "user": u, "message": m, "formattedMessage": msg }); msg = cache.formattedMessage; return "%7%10%11
%2%5%3:%6 %4%8" .args ( colour, // 1 Emotes.parse(authSymbol), // 2 name, // 3 msg, // 4 authStyle, // 5 Utilities.endTags(authStyle), // 6 (flash ? "" : ""), // 7 (flash ? "" : ""), // 8 u, // 9 (settings.timestampCopy ? "".args("" + u + ": " + Utilities.escapeHTML(m).replace(/"/g, "&q" + "uot;").replace(/\?/g, "%3F")) : ""), // 10 (settings.timestampCopy ? "" : ""), // 11 "style='text-decoration:none; color:" + colour + ";'" // 12 ); }, endTags: function(tags) { // let's make it not wrong // var ret = ""; var atags = tags.split("<").clean(""); for (var i = 0; i < atags.length; i++) { atags[i] = ""; } } ret = atags.reverse().join(""); return ret; }, formatTime: function(seconds, longv) // longv is true if 5 hours, 2 minutes, and 4 seconds instead of 05:02:04 { var h = Math.floor(seconds / 3600); var m = Math.floor((seconds - h * 3600) / 60); var s = seconds % 60; if (longv) { return "%1 hours, %2 minutes, and %3 seconds".args(h, m, s); } else { return "%1:%2:%3".args((h < 10 ? "0" + h : h), (m < 10 ? "0" + m : m), (s < 10 ? "0" + s : s)); } }, secondsFromString: function(str) { var t = str; if (t.toLowerCase().endsWith("s")) { t = t.substr(0, t.length - 1); } else if (t.toLowerCase().endsWith("m")) { t = t.substr(0, t.length - 1); if (isNaN(t) || parseFloat(t) <= 0) { return 0; } t *= 60; // mins -> seconds } else if (t.toLowerCase().endsWith("h")) { t = t.substr(0, t.length - 1); if (isNaN(t) || parseFloat(t) <= 0) { return 0; } t *= 3600; // hours -> seconds } if (isNaN(t) || parseFloat(t) <= 0) { return 0; } return t; }, multiplyString: function(str, amt) { var ret = ""; for (var i = 0; i < amt; i++) { ret += str; } return ret; } // utils }); CustomCommands = ({ // custom commands are added here from plugins, yo // dont actually code anything here probaly }); Commands = ({ add: function(type, name, params, desc, func, help) { var p = params.copy(); if (p.length > 0) { for (var i = 0; i < p.length; i++) { p[i] = "[" + p[i] + "]" } } p = " " + p.join("((sep))"); // p is a string now // var cmd = "[%1]%2%3 - %4".args(type, name, p, desc); if (commands.indexOf(cmd) === -1) { commands.push(cmd); if (help !== undefined) CustomCommands[name + "_help"] = help; CustomCommands[name + "_command"] = function(data, channel) { try { func.call(globe, data, channel); // do call here since data is an array, otherwise it'll think data is multiple params } catch (err) { if (this.hasOwnProperty(name + "_help")) { printMessage(this[name + "_help"].replace(/\(\(err\)\)/g, err)); } } }; if (!commandTypes.contains(type)) { commandTypes.push(type); // so they can access it, mang } return true; } return false; }, print: function(type) { print("
"); printMessage("%1 Commands:".args(Utilities.capitalize(type))); var cs = settings.commandSymbol; if (cmp(type, "all")) { // let's make this look better for (var type = 0; type < commandTypes.length; type++) { if (cmp(commandTypes[type], "all")) { continue; } printMessage("%1 Commands:".args(Utilities.capitalize(commandTypes[type]))); var none = true; for (var i = 0; i < commands.length; i++) { if (cmp(commandTypes[type], commands[i].substr(1, commands[i].indexOf("]") - 1))) { printMessage(Commands.parseDesc(cs + commands[i])); none = false; } } if (none) { printMessage("(None)"); } } print("
"); return; } var none = true; for (var i = 0; i < commands.length; i++) { if (cmp(type, commands[i].substr(1, commands[i].indexOf("]") - 1))) { printMessage(Commands.parseDesc(cs + commands[i])); none = false; } } if (none) { printMessage("(None)"); } print("
"); }, parseDesc: function(desc) { var str = desc; var sep = settings.paramSeparator; var cs = settings.commandSymbol; var type = str.substr(0, str.indexOf("]") + 1); str = str.substr(type.length); type = type.substr(1, type.length - 2); var cmd = cs + str.split(" ")[0]; var params = str.substr(str.split(" ")[0].length).split(" - ")[0].trim(); var desc = str.substr(str.indexOf(" - ")); params = params.replace(/\(\(sep\)\)/g, sep).replace(/\[/g, "[").replace(/]/g, "]"); desc = desc.replace(/\[/g, "[").replace(/]/g, "]").replace(/\(\(cs\)\)/g, cs).replace(/\(\(sep\)\)/g, sep) .replace(/\(\(ownName\)\)/g, client.ownName()).replace(/\(\(types\)\)/g, commandTypes.join(", ")); var ret = "" + cmd + " " + params + desc; return ret; }, handle: function(command, data, channel) { var params = (data === undefined ? 0 : data.length); for (var x in CustomCommands) { if (CustomCommands.hasOwnProperty(x) && cmp(command + "_command", x)) { CustomCommands[x](data, channel); // calls func, help is inside of func so we dont need to check for it here return; } } if (command === "commandslist") { if (params === 0) { Commands.print("general"); return; } if (commandTypes.indexOf(data[0]) === -1 && !cmp(data[0], "secret")) { printMessage("That's not a type of command!"); return; } Commands.print(data[0].toLowerCase()); } else if (command === "watamote") { var base = "http://www.mangareader.net/its-not-my-fault-that-im-not-popular/%1/%2"; sys.makeDir("watamote"); var getAmt = function(html) { var i = html.indexOf(" of ") + 13; var _html = html.substr(i); return _html.substr(0, _html.indexOf("/") - 1) }; // /eval first = Utilities.webCall("http://www.mangareader.net/its-not-my-fault-that-im-not-popular/%1/%2".args(1, 1)); var i = first.indexOf(" of "); var _html = html.substr(i); printMessage(_html); for (var chapter = 0; chapter < 72; chapter++) { var c = chapter + 1; var dir = "watemote/" + c + "/"; sys.makeDir(dir); var first = Utilities.webCall(base.args(c, 1)); var amt = getAmt(first); for (var page = 0; page < amt; page++) { var p = page + 1; var html = Utilities.webCall(base.args(c, p)); var img = html.substr(html.indexOf("src=\"http://") + 5); img = img.substr(0, img.indexOf("\" ")); Utilities.appendFile(dir + "list.txt", img + "\r\n"); } } } else if (command === "setcs" || command === "setcommandsymbol") { //printMessage(settings.commandSymbol + " " + data[0]); if (params === 0) { printMessage("Set your command symbol to what?"); return; } settings.commandSymbol = data[0]; Settings.save(); printMessage("Your command symbol was changed to: %1".args(Utilities.escapeHTML(settings.commandSymbol))); } else if (command === "setbotcolour" || command === "setbotcolor" || command === "setbc") { if (params === 0) { printMessage("Set it to what?"); return; } settings.botColour = data[0]; Settings.save(); printMessage("Colour changed to %1!".args(data[0])); } else if (command === "setbotname" || command === "setbn") { if (params === 0) { printMessage("Set it to what?"); return; } settings.botName = data[0]; Settings.save(); printMessage("Call me %1!".args(botHTML(false, false, false))); } else if (command === "setbotsymbol" || command == "setbs") { if (params === 0) { printMessage("Set it to what?"); return; } settings.botSymbol = data[0]; Settings.save(); printMessage("Changed symbol to %1!".args(Utilities.escapeHTML(data[0]))); } else if (command === "changename") { if (params === 0) { printMessage("Change it to what?"); return; } client.changeName(data[0]); printMessage("Changing name to %1...".args(data[0]), false); } else if (command === "setauthsymbol" || command === "setas") { if (params === 0) { printMessage("Set it to what?"); return; } if (params === 1) { printMessage("Set it to what level auth? The command is %1setauthsymbol symbol%2level!" .args(settings.commandSymbol, settings.paramSeparator)); return; } var level = (data[1].length > 0 ? parseInt(data[1]) : "-1"); if (isNaN(level) || level > 4 || level < 0) { printMessage("Auth levels are between 0 and 4!"); return; } settings.authSymbols[level] = data[0].replace(/\(\(s\)\)/gi, " "); Settings.save(); printMessage("Symbol for %1-level auth changed to %2!".args(level, data[0])); } else if (command === "clearauthsymbol" || command === "clearas") { if (params === 0) { printMessage("Clear which?"); return; } var level = (data[0].length > 0 ? parseInt(data[0]) : "-1"); if (isNaN(level) || level > 4 || level < 0) { printMessage("Auth levels are between 0 and 4!"); return; } settings.authSymbols[level] = ""; Settings.save(); printMessage("Symbol for %1-level auth cleared!".args(level)); } else if (command === "setauthstyle" || command === "setast") { if (params === 0) { printMessage("Set it to what?"); return; } if (params === 1) { printMessage("Set it to what level auth? The command is %1setauthstyle style%2level!" .args(settings.commandSymbol, settings.paramSeparator)); return; } var level = (data[1].length > 0 ? parseInt(data[1]) : "-1"); if (isNaN(level) || level > 4 || level < 0) { printMessage("Auth levels are between 0 and 4!"); return; } settings.authStyles[level] = data[0]; Settings.save(); printMessage("Style for %1-level auth changed to: %2%3%4!".args(data[1], data[0], Utilities.escapeHTML(data[0]), Utilities.endTags(data[0]))); } else if (command === "randomno" || command === "random" || command === "randomint" || command ==="randomnumber") { var min, max; if (params === 0) { min = 0; max = 100; } else if (params === 1) { min = 1; max = parseInt(data[0]); } else { min = parseInt(data[0]); max = parseInt(data[1]); } if (isNaN(min) || isNaN(max)) { printMessage("Something was wrong with your numbers!"); return; } var res = Utilities.randomInt(min, max + 1); printMessage("Random number from %1 to %2: %3".args(min, max, res)); } else if (command === "emotes") { if (params === 0) { print("

%1 Here are all of the emotes:
%2

Note: You can also do poke icons, like :bulbasaur:

".args(botHTML(), emoteString)); return; } if (!cmp(data[0], "on") && !cmp(data[0], "off")) { printMessage("%1 or %2? (Currently %3)" .args(Utilities.commandLink("On", "emotes on"), Utilities.commandLink("off", "emotes off"), (settings.emotes ? "on" : "off"))); return; } settings.emotes = cmp(data[0], "on"); Settings.save(); printMessage("Emotes were turned %1".args((cmp(data[0], "on") ? Emotes.parse("on! :smiley:") : "off! :)"))); } else if (command === "addstalkword") { if (params === 0) { printMessage("Add what to stalkwords?"); return; } var stalkwords = settings.stalkwords.copy(); if (stalkwords.indexOf(data[0]) !== -1) { printMessage("That's already in your stalkwords!"); return; } stalkwords.push(data[0]); settings.stalkwords = stalkwords; Settings.save(); printMessage("%1 added to stalkwords!".args(data[0])); } else if (command === "removestalkword") { if (params === 0) { printMessage("Remove what from stalkwords?"); return; } var stalkwords = settings.stalkwords.copy(); if (stalkwords.indexOf(data[0]) === -1) { printMessage("That's not in your stalkwords!"); return; } stalkwords.splice(stalkwords.indexOf(data[0]), 1); settings.stalkwords = stalkwords; Settings.save(); printMessage("%1 removed from stalkwords!".args(data[0])); } else if (command === "stalkwords") { var stalkwords = settings.stalkwords.copy(); print("

%1 Stalkwords:".args(botHTML())); if (stalkwords.length > 0) { for (var i = 0; i < stalkwords.length; i++) { printMessage(Utilities.commandLink("(Remove)", "removestalkword " + stalkwords[i]) + " " + stalkwords[i]); } } else { printMessage("You have no stalkwords!"); } print("
"); } else if (command === "addfriend") { if (params === 0) { printMessage("Add whom to friends?"); return; } var friends = settings.friends.copy(); if (friends.indexOf(data[0]) !== -1) { printMessage(data[0] + " is already on your friends list!"); return; } friends.push(data[0]); settings.friends = friends; Settings.save(); printMessage("%1 was added to your friends list!".args(data[0])); // i might word it difernt later is why args } else if (command === "removefriend") { if (params === 0) { printMessage("Remove whom from friends?"); return; } var friends = settings.friends.copy(); if (friends.indexOf(data[0]) === -1) { printMessage(data[0] + " is not on your friends list!"); return; } friends.splice(friends.indexOf(data[0]), 1); settings.friends = friends; Settings.save(); printMessage("%1 was removed from your friends list!".args(data[0])); // i might word it difernt later is why args } else if (command === "friends") { var friends = settings.friends.copy(); print("

%1 Friends:".args(botHTML())); if (friends.length > 0) { for (var i = 0; i < friends.length; i++) { var online = client.id(friends[i]) !== -1; printMessage("%4 [%3] %1".args(Utilities.escapeHTML(friends[i]), (online ? "green" : "red"), (online ? "Online" : "Offline"), Utilities.commandLink("(Remove)", "removefriend " + friends[i]))); } } else { printMessage("You have no friends! ...Was that mean?"); } print("
"); } else if (command === "addlogchannel") { var chans = settings.logChannels.copy(); if (chans.indexOf(data[0]) !== -1) { printMessage("You're already logging that channel!"); return; } if (!Utilities.isChannel(data[0])) { printMessage("That's not even a channel!"); return; } chans.push(data[0]); settings.logChannels = chans; Settings.save(); printMessage("%1 was added to your log channels!".args(Utilities.channelNames()[Utilities.channelNames().indexOf(data[0])])); } else if (command === "removelogchannel") { var chans = settings.logChannels.copy(); if (chans.indexOf(data[0]) === -1) { printMessage("You're not logging that channel!"); return; } chans.splice(chans.indexOf(data[0]), 1); settings.logChannels = chans; Settings.save(); printMessage("%1 was removed from your log channels!".args(Utilities.channelNames()[Utilities.channelNames().indexOf(data[0])])); } else if (command === "logchannels") { var chans = settings.logChannels.copy(); print("

%1 Log Channels:".args(botHTML())); if (chans.length > 0) { for (var i = 0; i < chans.length; i++) { printMessage(Utilities.commandLink("(Remove)", "removelogchannel " + chans[i]) + " " + Utilities.escapeHTML(chans[i])); } } else { printMessage("You're not logging any channels!"); } print("
"); } else if (command === "addresponse") { if (params < 2) { printMessage("It's %1addresponse keyphrase%2response".args(settings.commandSymbol, settings.paramSeparator), false); cache.responseAdded = false; cache.responseError = "Wrong amount of params. There should be two!"; return; } var responses = settings.responses; // responses are an array so that people can have multiple and it chooses at random, // so it requires an initialization as an array instead of just setting if (!responses.hasOwnProperty(data[0])) { responses[data[0]] = []; } if (responses[data[0]].indexOf(data[1], true) !== -1) // perhaps don't do this check so they can manually choose the odds? eh. { printMessage("That's already one of your responses!"); cache.responseAdded = false; cache.responseError = "That's already a response!"; return; } responses[data[0]].push(data[1]); settings.responses = responses; Settings.save(); cache.responseAdded = true; printMessage(data[1] + " was added to the responses for " + data[0] + "!", false); } else if (command === "removeresponse" || command === "deleteresponse") { if (params < 2) { printMessage("It's %1removeresponse keyphrase%2response".args(settings.commandSymbol, settings.paramSeparator), false); printMessage("If you're trying to remove the keyphrase entirely, use %1clearresponses keyphrase".args(settings.commandSymbol), false); return; } var responses = settings.responses; if (!responses.hasOwnProperty(data[0])) { printMessage("That's not even one of your keyphrases!"); return; } if (responses[data[0]].indexOf(data[1], true) !== -1) { responses[data[0]].splice(responses[data[0]].indexOf(data[1], true), 1); } else if (responses[data[0]].indexOf(data[1]) !== -1) { responses[data[0]].splice(responses[data[0]].indexOf(data[1]), 1); } else { printMessage("That's not even one of your responses for keyphrase %1!".args(Utilities.escapeHTML(data[0]))); return; } if (responses[data[0]].length === 0) { delete responses[data[0]]; // remove keyphrase since empty } settings.responses = responses; Settings.save(); printMessage("Response %1 was removed from keyphrase %2".args(Utilities.escapeHTML(data[1]), Utilities.escapeHTML(data[0]))); } else if (command === "clearresponses") { if (params !== 1) { printMessage("It's %1clearresponses keyphrase".args(settings.commandSymbol), false); printMessage("If you're only trying to remove only one response, use %1removeresponse keyphrase%2response " .args(settings.commandSymbol, settings.paramSeparator), false); return; } var responses = settings.responses; if (!responses.hasOwnProperty(data[0])) { printMessage("That's not even one of your keyphrases!"); return; } delete responses[data[0]]; settings.responses = responses; Settings.save(); printMessage("Keyphrase %1 was cleared and deleted!".args(Utilities.escapeHTML(data[0]))); } else if (command === "responses") { if (params > 0) { if (!cmp(data[0], "on") && !cmp(data[0], "off")) { printMessage("%1 or %2? (Currently %3)" .args(Utilities.commandLink("On", "responses on"), Utilities.commandLink("off", "responses off"), (settings.responsesOn ? "on" : "off"))); return; } settings.responsesOn = cmp(data[0], "on"); Settings.save(); printMessage("Autoresponse was turned %1!".args(data[0].toLowerCase())); return; } var responses = settings.responses; print("
"); printMessage("Reponses:"); if (JSON.stringify(responses) !== "{}") { for (var response in responses) { if (responses.hasOwnProperty(response)) { printMessage("%1 -> %2".args(Utilities.escapeHTML(response), Utilities.escapeHTML(responses[response]).join("
, "))); } } } else { printMessage("You have no autoresponses!"); } print("
"); } else if (command === "addblacklist") { if (params === 0) { printMessage("Add what channel to your blacklist?"); return; } var blacklist = settings.responseBlacklist.copy(); if (blacklist.indexOf(data[0]) !== -1) { printMessage("That's already on your blacklist!"); return; } if (!Utilities.isChannel(data[0])) { printMessage("That's not even a channel!"); return; } var cc = Utilities.channelNames()[Utilities.channelNames().indexOf(data[0])]; blacklist.push(cc); settings.responseBlacklist = blacklist; Settings.save(); printMessage(cc + " was added to your blacklist!", false); } else if (command === "removeblacklist" || command === "deleteblacklist") { if (params === 0) { printMessage("Remove what channel from your blacklist?"); return; } var blacklist = settings.responseBlacklist.copy(); if (blacklist.indexOf(data[0]) === -1) { printMessage("That's not on your blacklist!"); return; } var cc = (Utilities.isChannel(data[0]) ? Utilities.channelNames()[Utilities.channelNames().indexOf(data[0])] : data[0]); blacklist.splice(blacklist.indexOf(cc), 1); settings.responseBlacklist = blacklist; Settings.save(); printMessage(cc + " was remooved from your blacklist! (I'm a cow :3)", false); } else if (command === "blacklist") { var blacklist = settings.responseBlacklist.copy(); print("
"); printMessage("Blacklist:"); if (blacklist.length > 0) { for (var i = 0; i < blacklist.length; i++) { printMessage(Utilities.commandLink("(Remove)", "removeblacklist " + blacklist[i]) + " " + Utilities.escapeHTML(blacklist[i])); } } else { printMessage("There are no channels on your blacklist! This isn't recommended!!!"); } print("
"); } else if (command === "allowdefine") { if (params === 0 || (!cmp(data[0], "on") && !cmp(data[0], "off"))) { printMessage("%1 or %2? (Currently %3)" .args(Utilities.commandLink("On", "allowdefine on"), Utilities.commandLink("off", "allowdefine off"), (settings.allowDefine ? "on" : "off"))); return; } settings.allowDefine = cmp(data[0], "on"); Settings.save(); printMessage("External defining was turned %1!".args(data[0].toLowerCase())); } else if (command ==="lookup") { var id = client.id(data[0]); var user = client.name(id); // for correct case if (id === -1) { printMessage("That user is not on the server!"); return; } var avatar = client.player(id).avatar; var htr = Utilities.hexToRgb(client.color(id)); var _tiers = client.tiers(id); for (var i = 0; i < _tiers.length; i++) { _tiers[i] = Utilities.commandLink(_tiers[i], "tier " + _tiers[i]); } print("
"); print(Utilities.centerText("%1 Here's info for %2:

%2

" + "ID: %5
" + "Auth Level: %6
" + "Ignoring?: %7
" + "Colour: %4 / %8
" + "Tiers: %9" + "
" + "Actions: PM, Challenge%10" + ", Toggle Ignore, " + (settings.friends.indexOf(user) === -1 ? Utilities.commandLink("Add to friends", "addfriend " + user) : Utilities.commandLink("Remove from friends", "removefriend " + user)) + "

") .args(botHTML(), user, avatar, client.color(id), id, client.auth(id), (client.isIgnored(id) ? "Yes" : "No"), htr, _tiers.join(", "), (Utilities.isPlayerBattling(id) ? ", Watch Battle" : ""), "style='" + settings.commandLinkStyle + "'")); print("
"); } else if (command === "usage") { var tierList = client.getTierList(); if (params === 0 || tierList.indexOf(data[0]) === -1) { printMessage("Which tier? Valid tiers are: " + tierList.format("%i").join(", ")); return; } var amt = parseInt((params >= 2 && !isNaN(data[1]) ? data[1] : 50)); var url = "http://stats.pokemon-online.eu/%1/".args(tierList[tierList.indexOf(data[0])].replace(/ /g, "%20")); printMessage("Fetching usage stats..."); var html = Utilities.webCall(url + "ranked_stats.txt"); if (!html) { printMessage("Couldn't connect or there's no usage or something weird like that! Try again later or something!"); return; } html = Utilities.splitLines(html); // html is array now // var pokes = []; for (var i = 0; i < html.length; i++) { if (i === amt) { break; } // format: name usage battles var line = html[i]; // we have to do this backwards bc some pokes have spaces in names // var ind = line.lastIndexOf(" "); var battles = line.substr(ind + 1); line = line.substr(0, ind); ind = line.lastIndexOf(" "); var usage = line.substr(ind + 1); line = line.substr(0, ind); var poke = line; var _poke = "%2".args(url + sys.pokeNum(poke) + ".html", poke); var no = i + 1; // clean // pokes.push("#%1 - %2 %3 %4% - %5 battles".args ( no, "", _poke, usage, battles )); } var tc = ""; var cols = 4; for (var i = 0; i < pokes.length; i++) { if (i % cols === 0) { tc += (i > 0 ? "" : ""); } tc += "" + pokes[i] + ""; } var table = "" + tc + "
"; print(Utilities.centerText("

Usage Statistics for %1:

%2


").args(tierList[tierList.indexOf(data[0])], table)); } else if (command === "pm") { if (params === 0) { printMessage("PM who?"); return; } var id = client.id(data[0]); if (id === -1) { printMessage("You can't PM that person!"); return; } client.startPM(id); } else if (command === "ranking") { if (params === 0) { acceptCommand = false; say("/ranking"); acceptCommand = true; return; } var id = client.id(data[0]); if (client.getTierList().indexOf(data[0]) !== -1) { acceptCommand = false; say("/ranking " + data[0]); acceptCommand = true; return; } client.seeRanking(id); } else if (command === "eval") { if (params === 0) { printMessage("What am I supposed to eval?"); return; } var ret = eval(data[0]); if (ret !== undefined) { printMessage("%1 returns %2" .args(Utilities.escapeHTML(data[0]), Utilities.escapeHTML(ret.toString()))); } } else if (command === "update") { Utilities.checkForUpdate(); } else if (command === "doupdate") { Utilities.downloadUpdate(); } else if (command === "setflashcolour" || command === "setflashcolor") { if (params === 0) { var colour = settings.flashColour; printMessage("Your current flash colour is: %1".args(colour)); return; } if (!sys.validColor(data[0]) || Utilities.escapeHTML(data[0]) !== data[0]) { printMessage("That's not a valid colour! Try \"#88EE88\" or \"gold\" or something!"); return; } settings.flashColour = data[0]; Settings.save(); printMessage("Your flash/stalkword colour was changed to: %1".args(data[0])); } else if (command === "flash" || command === "flashes" || command === "setflash" || command === "setflashes") { if (params === 0 || !cmp(data[0], "on") && !cmp(data[0], "off")) { printMessage("%1 or %2? (Currently %3)" .args(Utilities.commandLink("On", "flashes on"), Utilities.commandLink("off", "flashes off"), (settings.flashes ? "on" : "off"))); return; } var toggle = cmp(data[0], "on"); settings.flashes = toggle; Settings.save(); if (toggle) { printMessage("Flashes were enabled!"); } else { printMessage("Flashes were disabled!"); } } else if (command === "enrichedtext" || command === "etext") { if (params === 0 || (!cmp(data[0], "on") && !cmp(data[0], "off"))) { printMessage("%1 or %2? (Currently %3)" .args(Utilities.commandLink("On", "enrichedtext on"), Utilities.commandLink("off", "enrichedtext off"), (settings.enrichedText ? "on" : "off"))); return; } settings.enrichedText = cmp(data[0], "on"); Settings.save(); printMessage("Enriched text was turned %1!".args(data[0].toLowerCase())); } else if (command === "fullwidth") { if (params === 0 || (!cmp(data[0], "on") && !cmp(data[0], "off"))) { printMessage("%1 or %2? (Currently %3)" .args(Utilities.commandLink("On", "fullwidth on"), Utilities.commandLink("off", "fullwidth off"), (settings.fullwidth ? "on" : "off"))); return; } settings.fullwidth = cmp(data[0], "on"); Settings.save(); printMessage("Fullwidth text was turned %1!".args(data[0].toLowerCase())); } else if (command === "ignorechallenges" || command === "ignorechals") { if (params === 0 || (!cmp(data[0], "on") && !cmp(data[0], "off"))) { printMessage("%1 or %2? (Currently %3)" .args(Utilities.commandLink("On", "ignorechallenges on"), Utilities.commandLink("off", "ignorechallenges off"), (settings.ignoreChallenges ? "on" : "off"))); return; } settings.ignoreChallenges = cmp(data[0], "on"); Settings.save(); if (cmp(data[0], "on")) { printMessage("Challenges will now be ignored!"); } else { printMessage("Challenges will no longer be ignored!"); } } else if (command === "addshortcut") { if (params < 2) { printMessage("It's %1addshortcut phrase%2shortcut".args(settings.commandSymbol, settings.paramSeparator), false); return; } if (data[0] === data[1]) { printMessage("Uh... no! Can't be the same!"); return; } settings.shortcuts[data[0]] = data[1]; Settings.save(); printMessage("%1 will now be replaced automatically with %2!".args(data[0], data[1]), false); } else if (command === "removeshortcut") { if (params === 0) { printMessage("Remove what shortcut?") return; } var sc = settings.shortcuts; if (!sc.hasOwnProperty(data[0])) { printMessage("That's not a shortcut! " + Utilities.commandLink("(View shortcuts)", "shortcuts")); return; } delete sc[data[0]]; Settings.save(); printMessage("%1 was removed from your shortcuts!".args(data[0]), false); } else if (command === "shortcuts") { print("
"); printMessage("Shortcuts:"); var hasSc = false; var keys = settings.shortcuts; for (var key in keys) { if (keys.hasOwnProperty(key)) { printMessage("%1 -> %2".args(Utilities.escapeHTML(key), Utilities.escapeHTML(keys[key]))); hasSc = true; } } if (!hasSc) { printMessage("You have no shortcuts!"); } print("
"); } else if (command === "tier") { if (tiers === {}) { if (!Utilities.loadTiers(true)) { return; } } var tierList = client.getTierList(); if (params === 0 || tierList.indexOf(data[0]) === -1) { printMessage("Which tier? Valid tiers are: " + tierList.format("%i").join(", ")); return; } var tier = tierList[tierList.indexOf(data[0])]; // correct case var t = tiers[tier]; var b = (t.banMode === "ban" ? "Banned" : "Eligable"); var info = [ "%1 Pokémon: %2".args(b, t.pokemons.split(", ").format("%i").join(", ")), "%1 Moves: %2".args(b, t.moves.split(", ").format("%i").join(", ")), "%1 Items: %2".args(b, t.items.split(", ").format("%i").join(", ")), "Gen: " + t.gen, "Mode: " + [ "Singles", "Doubles", "Triples" ][t.mode], "Clauses: " + (t.hasOwnProperty("clauses") ? t.clauses.replace(/,/g, ", ") : "--"), "Max Level: " + t.maxLevel, "Number of Pokémon: " + t.numberOfPokemons ]; print("
"); print(Utilities.commandLink("

" + t.name + "

", "usage " + t.name)); print(info.join("
")); print("
"); } else if (command === "updateemotes") { Emotes.load(true); } else if (command === "fakelog") // dont put this in commands its a secret lol { if (params < 2) { printMessage("It's %1fakelog name%2message".args(settings.commandSymbol, settings.paramSeparator), false); return; } var id = client.id(data[0]); if (id === -1) { printMessage("I can't fake a log from that user! (Maybe they're offline?)"); return; } cache.fakingLog = true; printUserMessage(data[1], client.name(id), channel); cache.fakingLog = false; } else if (command === "setparamseparator" || command === "setseparator" || command === "setsep" || command === "setparamsep") { if (params === 0) { printMessage("Set it to what?"); return; } var isAlphaOrNum = true; for (var i = 0; i < data[0].length; i++) { if ((alphabet + "0987654321").indexOf(data[0][i]) === -1) { isAlphaOrNum = false; break; } } if (isAlphaOrNum) { printMessage("Param separators must contain at least one non-alphanumeric character!"); return; } settings.paramSeparator = data[0]; Settings.save(); printMessage("Your command parameter separator has been changed to: %1".args(Utilities.escapeHTML(data[0]))); } else if (command === "updatetiers") { Utilities.loadTiers(true); } else if (command === "trivia") { if (params === 0) { printMessage("Get trivia on what?"); return; } //

Trivia

var thing = Utilities.capitalize(data[0]).replace(/ /g, "_"); printMessage("Fetching trivia..."); var html = Utilities.webCall("http://bulbapedia.bulbagarden.net/wiki/" + thing); if (!html) { printMessage("Couldn't connect to Bulbapedia!"); return; } var l = "

Trivia

".length; var ind = html.indexOf("

Trivia

"); if (ind === -1) { printMessage("There's no trivia on that!"); return; } var triv = html.substr(ind + l); triv = triv.substr(0, triv.indexOf("

%1 Trivia

".args(thing)); print(triv.trim()); print("
"); } else if (command === "autoupdate") { if (params === 0 || (!cmp(data[0], "on") && !cmp(data[0], "off"))) { printMessage("%1 or %2? (Currently %3)" .args(Utilities.commandLink("On", "autoupdate on"), Utilities.commandLink("off", "autoupdate off"), (settings.autoUpdate ? "on" : "off"))); return; } settings.autoUpdate = cmp(data[0], "on"); Settings.save(); printMessage((cmp(data[0], "on") ? "I'll check for updates when you log on!" : "I won't check for updates unless you tell me to!")); } else if (command === "timestampcopy" || command === "tscopy") { if (params === 0 || (!cmp(data[0], "on") && !cmp(data[0], "off"))) { printMessage("%1 or %2? (Currently %3)" .args(Utilities.commandLink("On", "timestampcopy on"), Utilities.commandLink("off", "timestampcopy off"), (settings.timestampCopy ? "on" : "off"))); return; } settings.timestampCopy = cmp(data[0], "on"); Settings.save(); printMessage((cmp(data[0], "on") ? "Clicking a timestamp will now copy it to the textbox!" : "Clicking a timestamp won't do anything!")); } else if (command === "whatsnew") { Utilities.printWhatsNew(); } else if (command === "setcommandlinkstyle" || command === "setcmdlinkstyle" || command === "setcls") { if (params === 0) { printMessage("Set it to what?"); return; } settings.commandLinkStyle = data[0]; Settings.save(); printMessage("Changed your " + Utilities.commandLink("command link", "commandslist") + " style!"); } else if (command === "logevents") { if (params === 0 || (!cmp(data[0], "on") && !cmp(data[0], "off"))) { printMessage("%1 or %2? (Currently %3)" .args(Utilities.commandLink("On", "logevents on"), Utilities.commandLink("off", "logevents off"), (settings.logEvents ? "on" : "off"))); return; } if (params === 1) { settings.logEvents = cmp(data[0], "on"); Settings.save(); printMessage((cmp(data[0], "on") ? "Okay, I'll log it when people come and go!~" : "Alright, I won't log when people come or go.")); } else { if (!Utilities.isChannel(data[1])) { printMessage("That's not even a channel!"); return; } data[1] = Utilities.channelNames()[Utilities.channelNames().indexOf(data[1])]; // correct case var chans = settings.logEventChannels; chans[data[1]] = cmp(data[0], "on"); settings.logEventChannels = chans; Settings.save(); printMessage((cmp(data[0], "on") ? "Okay, I'll log it when people come and go from " + data[1] + "!~" : "Alright, I won't log when people come or go from " + data[1] + "."), false); } } else if (command === "txtlogs") { if (params === 0 || [ "txt", "html", "both" ].indexOf(data[0]) === -1) { printMessage("%1, %2, or %3?".args ( Utilities.commandLink("TXT", "txtlogs txt"), Utilities.commandLink("HTML", "txtlogs html"), Utilities.commandLink("both", "txtlogs both") )); return; } settings.txtLogs = data[0].toLowerCase(); Settings.save(); printMessage((cmp(data[0], "txt") ? "Logs will be saved as *.txt files." : (cmp(data[0], "html") ? "Logs will be saved as *.html files." : "Logs will be saved as *.txt AND *.html files."))); } else if (command === "reconnect" || command === "rc") { client.reconnect(); } else if (command === "pastebin" || command === "pb") { if (params === 0) { printMessage("Pastebin what?"); return; } var url = "http://pastebin.com/api/api_post.php"; var key = "2fbef099f110f4e1d489a8ad386270ad"; var post = { "api_dev_key": key, "api_option": "paste", "api_paste_code": data[0].replace(/\\n/g, "\n") }; if (params > 1) { post["api_paste_name"] = data[1]; } printMessage("Creating paste..."); var url = Utilities.webCall(url, post); if (!url) { printMessage("Couldn't connect to Pastebin! Bummer!"); return; } print("
"); print("%1 - %2".args(url, Utilities.link("Send", "send", url, settings.commandLinkStyle))); print("
"); } else if (command === "settimer") { if (params < 2) { printMessage("It's %1settimer name%2seconds%2message".args(settings["commandSymbol"], settings["paramSeparator"]), false); return; } var time = Utilities.secondsFromString(data[1]); if (time === 0) { printMessage("Something was wrong with your duration! Try 5 or 5s or 5m or 5h."); return; } var t = time; time *= 1000; // convert to ms var message = "" + (params > 2 ? data[2] : "BEEP BOOP TIMER " + data[0] + " IS GOING OFF") + ""; message += ""; var rn = new Date(); printMessage("Timer %1 %2set for %3!".args(data[0], (timers.hasOwnProperty(data[0]) ? "re" : ""), Utilities.formatTime(t, true))); if (timers.hasOwnProperty(data[0])) { sys.unsetTimer(timers[data[0]].timer); } timers[data[0]] = { "timer": sys.setTimer(function() { printMessage(message); delete timers[data[0]]; }, time, false), "time": rn, "duration": t }; } else if (command === "unsettimer" || command === "stoptimer") { if (params === 0) { printMessage("Unset which timer?"); return; } var isT = false; for (var timer in timers) { if (timers.hasOwnProperty(timer) && cmp(timer, data[0])) { sys.unsetTimer(timers[timer].timer); printMessage("Timer %1 was unset!".args(timer), false); delete timers[timer]; isT = true; } } if (!isT) { printMessage("That's not even a timer!"); } } else if (command === "timers") { print("
"); printMessage("Timers:"); var isTimer = false; var rn = new Date(); // compare times // for (var timer in timers) { if (timers.hasOwnProperty(timer)) { var diff = Math.floor(timers[timer].duration - (rn.getTime() - timers[timer].time.getTime()) / 1000); // prob a better way but eh printMessage("%1 %2 - %3".args(Utilities.commandLink("(Unset)", "unsettimer " + timer) + " " + timer, Utilities.formatTime(diff, true) + " remaining"), false); isTimer = true; } } if (!isTimer) { printMessage("No timers!"); } print("
"); } else if (command === "tiers") { if (params === 0) { printMessage("Tiers for what?"); return; } if (sys.pokeNum(data[0]) === undefined) { printMessage("That isn't a Pokémon!"); return; } var pokeTiers = []; var tierOrder = [ "Ubers", "OU", "UU", "LU", "NU", "NEU" ]; var tierList = client.getTierList(); for (var tier in tiers) { if (tiers.hasOwnProperty(tier)) { var t = tiers[tier]; if (t.banMode === "Eligable" && (" " + t.pokemons + ",").contains(" " + data[0] + ",")) { pokeTiers.push(tier); } else { if (!tier.contains(" ") || !(" " + t.pokemons + ",").contains(" " + data[0] + ",")) { continue; } var root = tier.split(" ")[0]; var type = tier.substr(tier.indexOf(" ") + 1); if (tierOrder.contains(type) && !cmp(type, "neu") && !cmp(type, "ubers") && tierList.contains(root + " " + tierOrder[tierOrder.indexOf(type) - 1])) { pokeTiers.push(root + " " + tierOrder[tierOrder.indexOf(type) - 1]); } } } } printMessage(sys.pokemon(sys.pokeNum(data[0])) + "'s tiers: " + (pokeTiers.length > 0 ? pokeTiers.join(", ") : "Unknown"), false); } // setts else if (command === "settings" || command === "mysettings") { print("
"); printMessage("Settings:"); for (var setting in settings) { if (settings.hasOwnProperty(setting)) { var s = settings[setting]; printMessage("%1: %2" .args(setting, Utilities.escapeHTML(s.toString() === "[object Object]" ? JSON.stringify(s) : s.toString()))); } } print("
"); } else if (command === "setsetting") { if (params < 2) { printMessage("It's %1setsetting [setting]%2[value]".args(settings.commandSymbol, settings.paramSeparator)); return; } settings[data[0]] = data[1]; Settings.save(); printMessage("%1's value was set to: %2".args(data[0], data[1])); } else if (command === "clearsetting" || command === "deletesetting") { if (params === 0) { printMessage("Clear which setting?"); return; } delete settings[data[0]]; Settings.save(); printMessage("%1's value was cleared!".args(data[0])); } else if (command === "resetdefaults") { printMessage("Are you sure? " + Utilities.commandLink("Click", "doresetdefaults") + " to reset all settings to defaults (can't be undone probably!)."); } else if (command === "doresetdefaults") { printMessage("Resetting... I... I'll miss you, %1...".args(client.ownName())); // sad :c print("(you monster)"); settings = defaults; Settings.save(); printMessage("BEEP BOOP FACTORY RESET COMPLETE"); // AM ROBO } // redir else { acceptCommand = false; say("/" + command + (params > 0 ? " " + data.join(settings.paramSeparator) : "")); acceptCommand = true; } } }); PO = ({ beforeSendMessage: function(message, channel) { if (!initCheck) { if (!init()) { return; } } sys.stopEvent(); Plugins.callHooks("beforeSendMessage", { "message": message, "channel": channel }); var commandSymbol = settings.commandSymbol; var isCommand = (message.startsWith(commandSymbol) && alphabet.contains(message[commandSymbol.length])) || ((message.startsWith("/") || message.startsWith("!")) && alphabet.contains(message[1])); if (isCommand && acceptCommand) { sys.stopEvent(); message = message.replace(/\r/g, "").replace(/\n/g, "\\n"); // allows you to copy from notepad and things NO IT DOESNT var pos = message.indexOf(" "); var data; var command = message.split(" ")[0].substr(commandSymbol.length).toLowerCase(); if (pos === -1) { data = undefined; } else { if (message.length > pos + 1) { var _data = message.substr(pos + 1); if (_data.indexOf(settings.paramSeparator) !== -1) { if (command === "setparamseparator" || command === "setseparator" || command === "setsep" || command === "setparamsep") { data = [ _data ]; // so we can do like /setsep ;; if current is ;, basically ignoring current sep } else { data = _data.split(settings.paramSeparator); } } else { data = [ _data ]; } } } Commands.handle(command, data, channel); return; } message = Utilities.shortcuts(message); message = Utilities.fullwidth(message); say(message, channel); }, beforeChannelMessage: function(message, channel, html) { if (!initCheck) { init(); } /*if (!cache.acceptMessage) return;*/ Plugins.callHooks("beforeChannelMessage", { "message": message, "channel": channel, "html": html }); if (message.indexOf(": ") === -1 || !Utilities.isPlayerOnline(message.split(": ")[0])) { //Utilities.saveToLog(message, channel); return; } var m = Utilities.getMessage(message); var u = Utilities.getUser(message); cache.bcmf = m; Plugins.callHooks("beforeUserMessage", { "message": m, "user": u, "channel": channel }); m = cache.bcmf; // allows changing of it in plugin, don't allow changing of user for obvious reasons if (Utilities.isPlayerOnline(u)) { sys.stopEvent(); if (client.isIgnored(client.id(u))) { return; } if (!cache.fakingLog) Utilities.saveToLog(Utilities.formatMessage(m, u), channel, true); var colorTable = ["b58900","cb4b16","dc322f","d33682","6c71c4","268bd2","2aa198","5f8700","586e75","0073FF","A20D2D"/*,"6F3400"*/]; //var colorTable = ["b58900","cb4b16","dc322f","d33682","6c71c4","268bd2","2aa198","5f8700","586e75"/*,"0073FF","A20D2D","6F3400"*/]; var rgbToLab = (function (str) { var r = parseInt(str.substring(0,2),16), g = parseInt(str.substring(2,4),16), b = parseInt(str.substring(4,6),16); r /= 255, g /= 255, b /= 255; r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92); g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92); b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92); var x = ((r * 0.4124) + (g * 0.3576) + (b * 0.1805)) * 100; var y = ((r * 0.2126) + (g * 0.7152) + (b * 0.0722)) * 100; var z = ((r * 0.0193) + (g * 0.1192) + (b * 0.9505)) * 100; var l, a, b; x /= 95.047; y /= 100; z /= 108.883; x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116); y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116); z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116); l = (116 * y) - 16; a = 500 * (x - y); b = 200 * (y - z); return [l, a, b]; }); var c1 = rgbToLab(client.color(client.id(u)).toString().substring(1)), cd = -1, ci = -1; for (var i = 0; i < colorTable.length; i++) { var c2 = rgbToLab(colorTable[i]); var d = Math.pow(c2[0]-c1[0],2)+Math.pow(c2[1]-c1[1],2)+Math.pow(c2[2]-c1[2],2); if ((d < cd) || (cd === -1)) { cd = d; ci = i; } } var msg = Utilities.formatMessage(m, u, "#" + colorTable[ci]); print(msg, channel, true); cache.acceptMessage = false; cache.acceptMessage = true; if (settings.responsesOn && settings.responses.hasOwnProperty(m) && settings.responseBlacklist.indexOf(client.channelName(channel)) === -1) { if (cmp(u, client.ownName())) { // warn ? } else { say(settings.responses[m].randomItem()); } } if (settings.allowDefine && m.toLowerCase().startsWith(client.ownName().toLowerCase() + "define ")) { var mm = m.match(new RegExp(Utilities.escapeRegex(settings.paramSeparator))); if (mm === null || !mm.length === 1) { say("It's %1define keyphrase%2response!".args(client.ownName(), settings.paramSeparator)); } else { Commands.handle("addresponse", m.substr(client.ownName().length + 7).split(settings.paramSeparator), channel); if (cache.responseAdded) { say("Added!"); } else { say("Something went wrong: " + cache.responseError); } } } } }, onPlayerReceived: function(id) { if (!initCheck) { init(); } Plugins.callHooks("onPlayerReceived", { "id": id, "name": client.name(id) }); var friends = settings.friends.copy(); if (friends.indexOf(client.name(id)) !== -1) { printMessage("%1 is online!".args(Utilities.escapeHTML(client.name(id)))); } }, /*onBattleStarted: function(bid, p1, p2, tier, mode) { if (!initCheck) { init(); } printMessage(client.name(p1) + " vs " + client.name(p2) + " in " + tier); }, onBattleFinished: function(bid, winner, loser, res) { if (!initCheck) { init(); } printMessage(client.name(winner) + " won against " + client.name(loser) + "; res: " + res); },1*/ onPlayerRemoved: function(id) { if (!initCheck) { init(); } Plugins.callHooks("onPlayerRemoved", { "id": id, "name": client.name(id) }); var friends = settings.friends.copy(); if (friends.indexOf(client.name(id)) !== -1) { printMessage("%1 went offline!".args(Utilities.escapeHTML(client.name(id)))); } }, onPlayerJoinChan: function(id, channel) { if (!initCheck) { init(); } Plugins.callHooks("onPlayerJoinChan", { "id": id, "name": client.name(id), "channel": channel }); if (settings.logEvents || settings.logEventChannels[client.channelName(channel)]) Utilities.saveToLog(client.name(id) + " joined the channel.", channel); }, onPlayerLeaveChan: function (id, channel) { if (!initCheck) { init(); } Plugins.callHooks("onPlayerLeaveChan", { "id": id, "name": client.name(id), "channel": channel }); if (settings.logEvents || settings.logEventChannels[client.channelName(channel)]) Utilities.saveToLog(client.name(id) + " left the channel.", channel); }, beforeChallengeReceived: function(challengeId, opponentId, tier, clauses) { if (!initCheck) { init(); } Plugins.callHooks("beforeChallengeReceived", { "challengeId": challengeId, "opponentId": opponentId, "tier": tier, "clauses": clauses }); if (settings.ignoreChallenges) { sys.stopEvent(); // possibly alert, maybe not bc still spam } }, beforeNewMessage: function(message, html) { if (!initCheck) { init(); } Plugins.callHooks("beforeNewMessage", { "message": message, "html": html }); } }); // this has been bumble by songisng i hope u had a good time //