SHOW:
|
|
- or go back to the newest paste.
| 1 | var sys = require('sys');
| |
| 2 | var https = require('https');
| |
| 3 | var url = require('url');
| |
| 4 | ||
| 5 | const ACTION_COOLDOWN = 3 * 1000; | |
| 6 | const FLOOD_MESSAGE_NUM = 5; | |
| 7 | const FLOOD_PER_MSG_MIN = 500; // this is the minimum time between messages for legitimate spam. It's used to determine what "flooding" is caused by lag | |
| 8 | const FLOOD_MESSAGE_TIME = 6 * 1000; | |
| 9 | const MIN_CAPS_LENGTH = 8; | |
| 10 | const MIN_CAPS_PROPORTION = 0.8; | |
| 11 | ||
| 12 | settings = {};
| |
| 13 | try {
| |
| 14 | settings = JSON.parse(fs.readFileSync('settings.json'));
| |
| 15 | if (!Object.keys(settings).length && settings !== {}) settings = {};
| |
| 16 | } catch (e) {} // file doesn't exist [yet]
| |
| 17 | ||
| 18 | messages = {};
| |
| 19 | try {
| |
| 20 | messages = JSON.parse(fs.readFileSync('messages.json'));
| |
| 21 | if (!Object.keys(messages).length && messages !== {}) messages = {};
| |
| 22 | } catch (e) {} // file doesn't exist [yet]
| |
| 23 | ||
| 24 | quotes = {};
| |
| 25 | try {
| |
| 26 | quotes = JSON.parse(fs.readFileSync('quotes.json'));
| |
| 27 | if (!Object.keys(quotes).length && quotes !== {}) quotes = {};
| |
| 28 | } catch (e) {} // file doesn't exist [yet]
| |
| 29 | ||
| 30 | exports.parse = {
| |
| 31 | actionUrl: url.parse('https://play.pokemonshowdown.com/~~' + config.serverid + '/action.php'),
| |
| 32 | room: 'lobby', | |
| 33 | 'settings': settings, | |
| 34 | 'messages': messages, | |
| 35 | 'quotes': quotes, | |
| 36 | chatData: {},
| |
| 37 | ranks: {},
| |
| 38 | msgQueue: [], | |
| 39 | ||
| 40 | data: function(data, connection) {
| |
| 41 | if (data.substr(0, 1) === 'a') {
| |
| 42 | data = JSON.parse(data.substr(1)); | |
| 43 | if (data instanceof Array) {
| |
| 44 | for (var i = 0, len = data.length; i < len; i++) {
| |
| 45 | this.splitMessage(data[i], connection); | |
| 46 | } | |
| 47 | } else {
| |
| 48 | this.splitMessage(data, connection); | |
| 49 | } | |
| 50 | } | |
| 51 | }, | |
| 52 | splitMessage: function(message, connection) {
| |
| 53 | if (!message) return; | |
| 54 | ||
| 55 | var room = 'lobby'; | |
| 56 | if (message.indexOf('\n') < 0) return this.message(message, connection, room);
| |
| 57 | ||
| 58 | var spl = message.split('\n');
| |
| 59 | ||
| 60 | if (spl[0].charAt(0) === '>') {
| |
| 61 | if (spl[1].substr(1, 4) === 'init') return ok('joined ' + spl[2].substr(7));
| |
| 62 | if (spl[1].substr(1, 10) === 'tournament') return; | |
| 63 | room = spl.shift().substr(1); | |
| 64 | } | |
| 65 | ||
| 66 | for (var i = 0, len = spl.length; i < len; i++) {
| |
| 67 | this.message(spl[i], connection, room); | |
| 68 | } | |
| 69 | }, | |
| 70 | message: function(message, connection, room) {
| |
| 71 | var spl = message.split('|');
| |
| 72 | if (!spl[1]) {
| |
| 73 | if (/was promoted to Room (Driver|Moderator|Owner)/i.test(spl[0])) this.say(connection, room, 'Congratulations on the promotion ' + spl[0].substr(0, spl[0].indexOf("was") - 1) + '! ^-^');
| |
| 74 | if (/was promoted to Room Voice/i.test(spl[0])) this.say(connection, room, 'Welcome to THA, ' + spl[0].substr(0, spl[0].indexOf("was") - 1) + '! :3');
| |
| 75 | if (/was muted by (Flowerbless~|DanceBoTTT|BriyellaBot)/i.test(spl[0])) {
| |
| 76 | this.say(connection, room, 'Sorry, bot moderation is being worked on... here ya go! ^-^'); | |
| 77 | this.say(connection, room, '/unmute ' + spl[0].substr(0, spl[0].indexOf("was") - 1));
| |
| 78 | } | |
| 79 | spl = spl[0].split('>');
| |
| 80 | if (spl[1]) this.room = spl[1]; | |
| 81 | return; | |
| 82 | } | |
| 83 | ||
| 84 | switch (spl[1]) {
| |
| 85 | case 'challstr': | |
| 86 | info('received challstr, logging in...');
| |
| 87 | var id = spl[2]; | |
| 88 | var str = spl[3]; | |
| 89 | ||
| 90 | var requestOptions = {
| |
| 91 | hostname: this.actionUrl.hostname, | |
| 92 | port: this.actionUrl.port, | |
| 93 | path: this.actionUrl.pathname, | |
| 94 | agent: false | |
| 95 | }; | |
| 96 | ||
| 97 | if (!config.pass) {
| |
| 98 | requestOptions.method = 'GET'; | |
| 99 | requestOptions.path += '?act=getassertion&userid=' + toId(config.nick) + '&challengekeyid=' + id + '&challenge=' + str; | |
| 100 | } else {
| |
| 101 | requestOptions.method = 'POST'; | |
| 102 | var data = 'act=login&name=' + config.nick + '&pass=' + config.pass + '&challengekeyid=' + id + '&challenge=' + str; | |
| 103 | requestOptions.headers = {
| |
| 104 | 'Content-Type': 'application/x-www-form-urlencoded', | |
| 105 | 'Content-Length': data.length | |
| 106 | }; | |
| 107 | } | |
| 108 | ||
| 109 | var req = https.request(requestOptions, function(res) {
| |
| 110 | res.setEncoding('utf8');
| |
| 111 | var data = ''; | |
| 112 | res.on('data', function(chunk) {
| |
| 113 | data += chunk; | |
| 114 | }); | |
| 115 | res.on('end', function() {
| |
| 116 | if (data === ';') {
| |
| 117 | error('failed to log in; nick is registered - invalid or no password given');
| |
| 118 | process.exit(-1); | |
| 119 | } | |
| 120 | if (data.length < 50) {
| |
| 121 | error('failed to log in: ' + data);
| |
| 122 | process.exit(-1); | |
| 123 | } | |
| 124 | ||
| 125 | if (data.indexOf('heavy load') !== -1) {
| |
| 126 | error('the login server is under heavy load; trying again in one minute');
| |
| 127 | setTimeout(function() {
| |
| 128 | this.message(message); | |
| 129 | }.bind(this), 60 * 1000); | |
| 130 | return; | |
| 131 | } | |
| 132 | ||
| 133 | if (data.substr(0, 16) === '<!DOCTYPE html>') {
| |
| 134 | error('Connection error 522; trying agian in one minute');
| |
| 135 | setTimeout(function() {
| |
| 136 | this.message(message); | |
| 137 | }.bind(this), 60 * 1000); | |
| 138 | return; | |
| 139 | } | |
| 140 | ||
| 141 | try {
| |
| 142 | data = JSON.parse(data.substr(1)); | |
| 143 | if (data.actionsuccess) {
| |
| 144 | data = data.assertion; | |
| 145 | } else {
| |
| 146 | error('could not log in; action was not successful: ' + JSON.stringify(data));
| |
| 147 | process.exit(-1); | |
| 148 | } | |
| 149 | } catch (e) {}
| |
| 150 | send(connection, '|/trn ' + config.nick + ',0,' + data); | |
| 151 | }.bind(this)); | |
| 152 | }.bind(this)); | |
| 153 | ||
| 154 | req.on('error', function(err) {
| |
| 155 | error('login error: ' + sys.inspect(err));
| |
| 156 | }); | |
| 157 | ||
| 158 | if (data) req.write(data); | |
| 159 | req.end(); | |
| 160 | break; | |
| 161 | case 'updateuser': | |
| 162 | if (spl[2] !== config.nick) return; | |
| 163 | ||
| 164 | if (spl[3] !== '1') {
| |
| 165 | error('failed to log in, still guest');
| |
| 166 | process.exit(-1); | |
| 167 | } | |
| 168 | ||
| 169 | ok('logged in as ' + spl[2] + '^-^');
| |
| 170 | ||
| 171 | this.msgQueue.push('|/blockchallenges');
| |
| 172 | for (var i = 0, len = config.rooms.length; i < len; i++) {
| |
| 173 | var room = toId(config.rooms[i]); | |
| 174 | if (room === 'lobby' && config.serverid === 'showdown') continue; | |
| 175 | this.msgQueue.push('|/join ' + room);
| |
| 176 | } | |
| 177 | for (var i = 0, len = config.privaterooms.length; i < len; i++) {
| |
| 178 | var room = toId(config.privaterooms[i]); | |
| 179 | if (room === 'lobby' && config.serverid === 'showdown') continue; | |
| 180 | this.msgQueue.push('|/join ' + room);
| |
| 181 | } | |
| 182 | this.msgDequeue = setInterval(function() {
| |
| 183 | var msg = this.msgQueue.shift(); | |
| 184 | if (msg) return send(connection, msg); | |
| 185 | clearInterval(this.msgDequeue); | |
| 186 | this.msgDequeue = null; | |
| 187 | }.bind(this), 750); | |
| 188 | setInterval(this.cleanChatData.bind(this), 30 * 60 * 1000); | |
| 189 | break; | |
| 190 | case 'c': | |
| 191 | var by = spl[2]; | |
| 192 | spl = spl.splice(3).join('|');
| |
| 193 | this.processChatData(toId(by), room, connection, spl); | |
| 194 | this.chatMessage(spl, by, room, connection); | |
| 195 | if (toId(by) === toId(config.nick) && ' +%@#~'.indexOf(by.charAt(0)) > -1) this.ranks[room] = by.charAt(0); | |
| 196 | break; | |
| 197 | case 'c:': | |
| 198 | var by = spl[3]; | |
| 199 | spl = spl.splice(4).join('|');
| |
| 200 | this.processChatData(toId(by), room, connection, spl); | |
| 201 | this.chatMessage(spl, by, room, connection); | |
| 202 | if (toId(by) === toId(config.nick) && ' +%@#~'.indexOf(by.charAt(0)) > -1) this.ranks[room] = by.charAt(0); | |
| 203 | break; | |
| 204 | case 'pm': | |
| 205 | var by = spl[2]; | |
| 206 | spl = spl.splice(4).join('|');
| |
| 207 | if (toId(by) === toId(config.nick) && ' +%@#~'.indexOf(by.charAt(0)) > -1) this.ranks[room] = by.charAt(0); | |
| 208 | this.chatMessage(spl, by, ',' + by, connection); | |
| 209 | break; | |
| 210 | case 'N': | |
| 211 | var by = spl[2]; | |
| 212 | this.updateSeen(spl[3], spl[1], toId(by)); | |
| 213 | if (toId(by) !== toId(config.nick) || ' +%@&#~'.indexOf(by.charAt(0)) === -1) return; | |
| 214 | this.ranks[toId(this.room === '' ? 'lobby' : this.room)] = by.charAt(0); | |
| 215 | this.room = ''; | |
| 216 | break; | |
| 217 | case 'J': | |
| 218 | case 'j': | |
| 219 | var by = spl[2]; | |
| 220 | this.updateSeen(by, spl[1], (this.room === '' ? 'lobby' : this.room)); | |
| 221 | if (toId(by) === toId(config.nick) && ' +%@&#~'.indexOf(by.charAt(0)) > -1) this.ranks[room] = by.charAt(0); | |
| 222 | if (['goddessbriyella', 'themansavage', 'omegaxis14'].indexOf(toId(by)) > -1) {
| |
| 223 | this.say(connection, room, '/w ' + toId(by) + ', **#warn** __is a new command that has been made for Moderators and Room Owners. To use the command, **PM Slowbro Bot** with this syntax:__ #warn **[user]**, **[warn reason]**'); | |
| 224 | this.say(connection, room, '/w ' + toId(by) + ', __This command is not to be abused and is for purely moderation purposes, thanks!^-^ ~Alpha-Kun__'); | |
| 225 | } | |
| 226 | /* if (toId(by) == 'goddessbriyella') this.say(connection, room, 'Haaii Briyella!^-^ I missed you ;~;'); | |
| 227 | if (toId(by) == 'themansavage') this.say(connection, room, 'Hey Butch :3'); | |
| 228 | if (toId(by) == 'omegaxis14') this.say(connection, room, '**om**e**g**a o3o hai :3'); | |
| 229 | if (toId(by) == 'starbloom') this.say(connection, room, 'Haaii Kat^-^ How are you? :3'); | |
| 230 | */ | |
| 231 | break; | |
| 232 | case 'l': | |
| 233 | case 'L': | |
| 234 | var by = spl[2]; | |
| 235 | this.updateSeen(by, spl[1], (this.room === '' ? 'lobby' : this.room)); | |
| 236 | this.room = ''; | |
| 237 | break; | |
| 238 | case 'raw': | |
| 239 | if (/[3-9] ?days/i.test(spl[2])) this.say(connection, room, 'zarel pls ;-;'); | |
| 240 | break; | |
| 241 | case 'tournament': | |
| 242 | if (/end\|\{"results":\[\[/i.test(spl[2])) this.say(connection, room, 'Good job ' + spl[2].substr(spl[2].indexOf("results") + 12, spl[2].indexOf("\"\],\[")) + ' on winning the tournament!^~^');
| |
| 243 | break; | |
| 244 | } | |
| 245 | }, | |
| 246 | chatMessage: function(message, by, room, connection) {
| |
| 247 | var now = Date.now(); | |
| 248 | var cmdrMessage = '["' + room + '|' + by + '|' + message + '"]'; | |
| 249 | message = message.trim(); | |
| 250 | // auto accept invitations to rooms | |
| 251 | if (room.charAt(0) === ',' && message.substr(0, 8) === '/invite ' && this.hasRank(by, '%@&~') && !(config.serverid === 'showdown' && toId(message.substr(8)) === 'lobby')) {
| |
| 252 | this.say(connection, '', '/join ' + message.substr(8)); | |
| 253 | } | |
| 254 | if (message.substr(0, config.commandcharacter.length) !== config.commandcharacter || toId(by) === toId(config.nick)) return; | |
| 255 | ||
| 256 | message = message.substr(config.commandcharacter.length); | |
| 257 | var index = message.indexOf(' ');
| |
| 258 | var arg = ''; | |
| 259 | if (index > -1) {
| |
| 260 | var cmd = message.substr(0, index); | |
| 261 | arg = message.substr(index + 1).trim(); | |
| 262 | } else {
| |
| 263 | var cmd = message; | |
| 264 | } | |
| 265 | ||
| 266 | if (Commands[cmd]) {
| |
| 267 | var failsafe = 0; | |
| 268 | while (typeof Commands[cmd] !== "function" && failsafe++ < 10) {
| |
| 269 | cmd = Commands[cmd]; | |
| 270 | } | |
| 271 | if (typeof Commands[cmd] === "function") {
| |
| 272 | cmdr(cmdrMessage); | |
| 273 | Commands[cmd].call(this, arg, by, room, connection); | |
| 274 | } else {
| |
| 275 | error("invalid command type for " + cmd + ": " + (typeof Commands[cmd]));
| |
| 276 | } | |
| 277 | } | |
| 278 | /* if (config.allowmute && this.hasRank(this.ranks[room] || ' ', '%@&#~') && config.whitelist.indexOf(user) === -1) {
| |
| 279 | var useDefault = !(this.settings['modding'] && this.settings['modding'][room]); | |
| 280 | // moderation for abusing bot commands | |
| 281 | for (cmd in Commands) | |
| 282 | var isAbusing = (this.chatData.commandFlooding[room][cmd].times.length >= 6 && (time - this.chatData.commandFlooding[room][cmd].times[this.chatData.commandFlooding[room][cmd].times.length - 10]) < 30 * 1000 | |
| 283 | && (time - this.chatData.commandFlooding[room][cmd].times[this.chatData.commandFlooding[room][cmd].times.length - 6]) > (6 * 30 * 1000)); | |
| 284 | if ((useDefault || this.settings['modding'][room]['flooding'] !== 0) && isAbusing) this.say(connection, room, '/wall Please stop abusing bot commands, they have all been set to # until things settle down again.'); | |
| 285 | } */ | |
| 286 | }, | |
| 287 | say: function(connection, room, text) {
| |
| 288 | if (room.charAt(0) !== ',') {
| |
| 289 | var str = (room !== 'lobby' ? room : '') + '|' + text; | |
| 290 | send(connection, str); | |
| 291 | } else {
| |
| 292 | room = room.substr(1); | |
| 293 | var str = '|/pm ' + room + ', ' + text; | |
| 294 | send(connection, str); | |
| 295 | } | |
| 296 | }, | |
| 297 | shorten: function(link) {
| |
| 298 | var BitlyAPI = require("node-bitlyapi");
| |
| 299 | var Bitly = new BitlyAPI({
| |
| 300 | client_id: "Something", | |
| 301 | client_secret: "Something" | |
| 302 | }); | |
| 303 | var self = this; | |
| 304 | Bitly.setAccessToken("c8a15558cbf4a555391b974849d7684e211fb707");
| |
| 305 | Bitly.shortenLink(link, function(err, results) {
| |
| 306 | var resObject = eval("(" + results + ")");
| |
| 307 | console.log('url: ' + resObject.data.url);
| |
| 308 | bitLink += resObject.data.url; | |
| 309 | console.log('bitLink: ' + bitLink);
| |
| 310 | }); | |
| 311 | }, | |
| 312 | hasRank: function(user, rank) {
| |
| 313 | var hasRank = (rank.split('').indexOf(user.charAt(0)) !== -1) || (config.excepts.indexOf(toId(user)) !== -1);
| |
| 314 | return hasRank; | |
| 315 | }, | |
| 316 | canUse: function(cmd, room, user) {
| |
| 317 | var canUse = false; | |
| 318 | var ranks = ' +%@&#~'; | |
| 319 | if (!this.settings[cmd] || !this.settings[cmd][room]) {
| |
| 320 | canUse = this.hasRank(user, ranks.substr(ranks.indexOf((cmd === 'autoban' || cmd === 'banword') ? '#' : config.defaultrank))); | |
| 321 | } else if (this.settings[cmd][room] === true) {
| |
| 322 | canUse = true; | |
| 323 | } else if (ranks.indexOf(this.settings[cmd][room]) > -1) {
| |
| 324 | canUse = this.hasRank(user, ranks.substr(ranks.indexOf(this.settings[cmd][room]))); | |
| 325 | } | |
| 326 | return canUse; | |
| 327 | }, | |
| 328 | sendMail: function(user, room) {
| |
| 329 | if (!this.messages || !this.messages[user]) return false; | |
| 330 | if (this.messages[user]) {
| |
| 331 | console.log(user + ' has mail.'); | |
| 332 | return true; | |
| 333 | } | |
| 334 | }, | |
| 335 | processChatData: function(user, room, connection, msg, by) {
| |
| 336 | var botName = msg.toLowerCase().indexOf(toId(config.nick)); | |
| 337 | ||
| 338 | if (toId(user.substr(1)) === toId(config.nick)) {
| |
| 339 | this.ranks[room] = user.charAt(0); | |
| 340 | return; | |
| 341 | } | |
| 342 | var by = user; | |
| 343 | user = toId(user); | |
| 344 | var user = toId(by); | |
| 345 | ||
| 346 | if (!user || room.charAt(0) === ',') return; | |
| 347 | room = toId(room); | |
| 348 | msg = msg.trim().replace(/[ \u0000\u200B-\u200F]+/g, ' '); // removes extra spaces and null characters so messages that should trigger stretching do so | |
| 349 | ||
| 350 | this.updateSeen(user, 'c', room); | |
| 351 | var now = Date.now(); | |
| 352 | if (!this.chatData[user]) this.chatData[user] = {
| |
| 353 | zeroTol: 0, | |
| 354 | lastSeen: '', | |
| 355 | seenAt: now | |
| 356 | }; | |
| 357 | ||
| 358 | var userData = this.chatData[user]; | |
| 359 | if (!this.chatData[user][room]) this.chatData[user][room] = {
| |
| 360 | times: [], | |
| 361 | points: 0, | |
| 362 | lastAction: 0 | |
| 363 | }; | |
| 364 | ||
| 365 | var roomData = userData[room]; | |
| 366 | roomData.times.push(now); | |
| 367 | this.chatData[user][room].times.push(now); | |
| 368 | ||
| 369 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| 370 | /////// Regex ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| 371 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| 372 | ||
| 373 | //Greetings & Farewells | |
| 374 | if (/(good)? ?(night|nite) (everyone|guys|friends|all)/i.test(msg) && toId(config.nick) !== toId(by)) this.say(connection, room, 'Goodnight ' + by + '^-^'); | |
| 375 | if (/i(\'?m| am).*go.*to (bed|sleep)/i.test(msg) && toId(config.nick) !== toId(by)) this.say(connection, room, 'Goodnight ' + by + '^-^'); | |
| 376 | if (/i(\'?m| am).*go.*to (eat)/i.test(msg) && toId(config.nick) !== toId(by)) this.say(connection, room, 'omnomnom Have a nice meal ' + by + '^-^'); | |
| 377 | if (/(hey|hi|hello|ha+?i+) (everyone|guys|friends|all)/i.test(msg) && toId(config.nick) !== toId(by)) this.say(connection, room, 'Haaii ' + by + '^-^'); | |
| 378 | if (/(bye|g2g|gtg|ba+?i+) (everyone|guys|friends|all)/i.test(msg) && toId(config.nick) !== toId(by)) this.say(connection, room, 'Baaii ' + by + '~'); | |
| 379 | if (/g2g/i.test(msg) && toId(config.nick) !== toId(by)) this.say(connection, room, 'Baaii ' + by + '~'); | |
| 380 | if (/how(\'re)? (r|are|is) (u|you|chu)?/i.test(msg)) this.say(connection, room, 'I am good, how about you ' + by + '? :o'); | |
| 381 | ||
| 382 | ||
| 383 | //Miscellaneous | |
| 384 | if (/(why are there )?so many bots( in here)?\??/i.test(msg)) this.say(connection, room, 'Sorry if I\'m intruding, I\'ll try and be as quiet as possible! >~<'); | |
| 385 | if (/(mashiro|mashy|goddess ?mashiro)/i.test(msg) && isAfk == true) this.say(connection, room, '/w ' + by + ', Mashiro-chan is AFK right now, leave a PM or check back in a bit, thanks^-^'); | |
| 386 | if (/(why are there )?so many goddess(es)?( in here)?\??/i.test(msg)) this.say(connection, room, 'Mashiro is just a Briyella wannabe o3o'); | |
| 387 | if (/(9[0-9]|100)% compatible/i.test(msg)) {
| |
| 388 | var rand = ~~(2 * Math.random()) + 1; | |
| 389 | if (rand == 1) this.say(connection, room, '__it was meant to be :O__'); | |
| 390 | if (rand == 2) this.say(connection, room, '/me plays wedding music'); | |
| 391 | } | |
| 392 | if (/(1| )[0-9]% compatible/i.test(msg)) this.say(connection, room, '__rip ;-;__'); | |
| 393 | if (/I(\'?m| am) back/i.test(msg)) this.say(connection, room, 'Hi back, I am Slowbro Bot o3o'); | |
| 394 | if (/I(\'?m| am) tired/i.test(msg)) this.say(connection, room, 'Hi tired, I am Slowbro Bot o3o'); | |
| 395 | if (/I(\'?m| am) hungry/i.test(msg)) this.say(connection, room, 'Hi hungry, I am Slowbro Bot o3o'); | |
| 396 | if (/(cut|kick|punch(es)?|hit|hurt|slap|stab)s? (goddess)? ?mash(y|iro)/i.test(msg)) this.say(connection, room, 'D-don\'t hurt my creator..!! >~<'); | |
| 397 | if (/\brip\b/i.test(msg) && toId(by) !== toId('mashibot')) {
| |
| 398 | var rand = ~~(13 * Math.random()) + 1; | |
| 399 | if (rand == 1) this.say(connection, room, '__rip in pepperoni ;-;__'); | |
| 400 | if (rand == 2) this.say(connection, room, '__rip in pieces ;-;__'); | |
| 401 | if (rand == 3) this.say(connection, room, '__rip in pepsi ;-;__'); | |
| 402 | if (rand == 4) this.say(connection, room, '__rip in PixelMoniac ;-;__'); | |
| 403 | if (rand == 5) this.say(connection, room, '__rip in pizza ;-;__'); | |
| 404 | if (rand == 6) this.say(connection, room, '__rip in pringles ;-;__'); | |
| 405 | if (rand == 7) this.say(connection, room, '__rip in pretzels ;-;__'); | |
| 406 | if (rand == 8) this.say(connection, room, '__rip in pistachios ;-;__'); | |
| 407 | if (rand == 9) this.say(connection, room, '__rip in pasta ;-;__'); | |
| 408 | if (rand == 10) this.say(connection, room, '__rip in peaches ;-;__'); | |
| 409 | if (rand == 11) this.say(connection, room, '__rip in pumpkins ;-;__'); | |
| 410 | if (rand == 12) this.say(connection, room, '__rip in papayas ;-;__'); | |
| 411 | if (rand == 13) this.say(connection, room, '__rip in potatoes ;-;__'); | |
| 412 | } | |
| 413 | if (/\bej\b/i.test(msg) && toId(by) !== toId('mashibot')) {
| |
| 414 | var rand = ~~(13 * Math.random()) + 1; | |
| 415 | if (rand == 1) this.say(connection, room, '__andy saks__'); | |
| 416 | if (rand == 2) this.say(connection, room, '__pindakaas__'); | |
| 417 | if (rand == 3) this.say(connection, room, '__IK WIL KOEKJES__'); | |
| 418 | if (rand == 4) this.say(connection, room, '__slooowbrooo__'); | |
| 419 | if (rand == 5) this.say(connection, room, '__plalalalala__'); | |
| 420 | if (rand == 6) this.say(connection, room, '__lolololol__'); | |
| 421 | if (rand == 7) this.say(connection, room, '__keukenrol__'); | |
| 422 | if (rand == 8) this.say(connection, room, '__banaan__'); | |
| 423 | if (rand == 9) this.say(connection, room, '__ontbijtkoek__'); | |
| 424 | if (rand == 10) this.say(connection, room, '__I like turltes__'); | |
| 425 | } | |
| 426 | // if (/(rekt|burn)/i.test(msg)) this.say(connection, room, '!data Rawst Berry'); | |
| 427 | ||
| 428 | //Favorite Pokemon | |
| 429 | if (/what(\'s| is)? (goddess ?)?mash(i|y|iro)?(chan|bot)?\'?s? fav(e|ou?rite)? poke(mon)?\??/i.test(msg)) this.say(connection, room, '!data Ninetales'); | |
| 430 | if (/what(\'s| is)? (goddess ?)?bri(yella)?\'?s? fav(e|ou?rite)? poke(mon)?\??/i.test(msg)) this.say(connection, room, '!data Vespiquen'); | |
| 431 | if (/what(\'s| is)? omega-?(xis14)?\'?s? fav(e|ou?rite)? poke(mon)?\??/i.test(msg)) this.say(connection, room, '!data Mew'); | |
| 432 | if (/what(\'s| is)? (the|butch) ?mansavage\'?s? fav(e|ou?rite)? poke(mon)?\??/i.test(msg) || /what(\'s| is)? butch\'?s? fav(ou?rite)? poke(mon)?\??/i.test(msg)) this.say(connection, room, '!data Rhyperior'); | |
| 433 | ||
| 434 | //League Names | |
| 435 | if (/(does)? ?(some|any)(one|1|body) play (league( of legends)?|lol)/i.test(msg)) this.say(connection, room, 'Add Mashiro-chan on League if you want to play: LeInfiniti'); | |
| 436 | if (/what(\'s| is)? jess(ilina| league)?\'?s? (league( of legends)?|lol)( name)?/i.test(msg)) this.say(connection, room, 'Jess\'s League name is: namegohere'); | |
| 437 | ||
| 438 | //osu! room | |
| 439 | if (/(pronounce|say) osu/i.test(msg)) {
| |
| 440 | if (room !== 'osu') return false; | |
| 441 | this.say(connection, room, 'osu! is pronounced like \"os\", not \"osu\". This is because when a \'u\' follows an \'s\' in Japanese, the \'u\' is silent.'); | |
| 442 | } | |
| 443 | if (/what(\'s| is)? osu/i.test(msg)) {
| |
| 444 | if (room !== 'osu') return false; | |
| 445 | this.say(connection, room, 'osu! is a Japanese rhythm game where the player hits notes in time with the beat of the music. There are 5 different game modes, the most popular being standard osu! and osu! mania.'); | |
| 446 | } | |
| 447 | ||
| 448 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| 449 | /////// /me Regex ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| 450 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| 451 | ||
| 452 | if (msg.toLowerCase().indexOf(toId(config.nick)) > -1 && toId(by) !== toId(config.nick)) {
| |
| 453 | if (/^\/me/i.test(msg) && user !== botName) {
| |
| 454 | if (/(pet|stroke)s?/i.test(msg)) {
| |
| 455 | this.say(connection, room, '/me purr'); return;} | |
| 456 | ||
| 457 | if (/licks?/i.test(msg)) {
| |
| 458 | this.say(connection, room, '/me squirms ;~;'); return;} | |
| 459 | - | this.say(connection, room, '/me blushes deeply'); return;} |
| 459 | + | |
| 460 | if (/(kiss(es)?|kissu)/i.test(msg)) {
| |
| 461 | this.say(connection, room, '/me blushes deeply'); | |
| 462 | - | this.say(connection, room, 'nuuu dun eat me ;~;'); return;} |
| 462 | + | |
| 463 | ||
| 464 | if (/(eat|nom|nibble)s?/i.test(msg)) {
| |
| 465 | this.say(connection, room, 'nuuu dun eat me ;~;'); | |
| 466 | this.say(connection, room, '/me hides'); return;} | |
| 467 | ||
| 468 | if (/(hit|stab|punch|kick|hurt)s?/i.test(msg)) {
| |
| 469 | this.say(connection, room, '/me cries in pain ;-;'); return;} | |
| 470 | ||
| 471 | if (/(hug|glomp|squeeze)s?/i.test(msg)) {
| |
| 472 | this.say(connection, room, '/me squee~ :3'); return;} | |
| 473 | ||
| 474 | if (/(cuddle|snuggle)s?/i.test(msg)) {
| |
| 475 | - | this.say(connection, room, '/me giggles and squirms'); return;} |
| 475 | + | |
| 476 | ||
| 477 | if (/pokes?/i.test(msg)) {
| |
| 478 | this.say(connection, room, 'oww!! >~<'); return;} | |
| 479 | ||
| 480 | if (/(gives? food|a cookie)/i.test(msg)) {
| |
| 481 | this.say(connection, room, '/me noms :3'); return;} | |
| 482 | ||
| 483 | if (/(tickle)s?/i.test(msg)) {
| |
| 484 | this.say(connection, room, '/me giggles and squirms'); | |
| 485 | this.say(connection, room, 'Staaahhhpp!! ;~;'); return;} | |
| 486 | } | |
| 487 | } | |
| 488 | ||
| 489 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| 490 | /////// Moderation Detection ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| 491 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
| 492 | ||
| 493 | /* // this deals with punishing rulebreakers, but note that the bot can't think, so it might make mistakes | |
| 494 | if (config.allowmute && this.hasRank(this.ranks[room] || ' ', '%@&#~') && config.whitelist.indexOf(user) === -1) {
| |
| 495 | var useDefault = !(this.settings['modding'] && this.settings['modding'][room]); | |
| 496 | var pointVal = 0; | |
| 497 | var muteMessage = ''; | |
| 498 | var warnMessage = ''; | |
| 499 | ||
| 500 | // moderation for flooding (more than x lines in y seconds) | |
| 501 | var times = roomData.times; | |
| 502 | var timesLen = times.length; | |
| 503 | var isFlooding = (timesLen >= FLOOD_MESSAGE_NUM && (now - times[timesLen - FLOOD_MESSAGE_NUM]) < FLOOD_MESSAGE_TIME && | |
| 504 | (now - times[timesLen - FLOOD_MESSAGE_NUM]) > (FLOOD_PER_MSG_MIN * FLOOD_MESSAGE_NUM)); | |
| 505 | if ((useDefault || !('flooding' in modSettings)) && isFlooding) {
| |
| 506 | if (pointVal < 2) {
| |
| 507 | pointVal = 2; | |
| 508 | muteMessage = ', Please stop flooding the chat! ;~;'; | |
| 509 | } | |
| 510 | } */ | |
| 511 | ||
| 512 | // moderation for caps (over x% of the letters in a line of y characters are capital) | |
| 513 | /* var capsMatch = msg.replace(/[^A-Za-z]/g, '').match(/[A-Z]/g); | |
| 514 | if ((useDefault || !('caps' in modSettings)) && capsMatch && toId(msg).length > MIN_CAPS_LENGTH && (capsMatch.length >= ~~(toId(msg).length * MIN_CAPS_PROPORTION))) {
| |
| 515 | if (pointVal < 1) {
| |
| 516 | pointVal = 1; | |
| 517 | muteMessage = ', Don\'t be so loud wtf ;-;'; | |
| 518 | } | |
| 519 | } | |
| 520 | // moderation for stretching (over x consecutive characters in the message are the same) | |
| 521 | var stretchMatch = /(.)\1{7,}/gi.test(msg) || /(..+)\1{4,}/gi.test(msg); // matches the same character (or group of characters) 8 (or 5) or more times in a row
| |
| 522 | if ((useDefault || !('stretching' in modSettings)) && stretchMatch) {
| |
| 523 | if (pointVal < 1) {
| |
| 524 | pointVal = 1; | |
| 525 | muteMessage = ', This isn\'t yoga, no streching please ._.'; | |
| 526 | } | |
| 527 | } | |
| 528 | ||
| 529 | if (pointVal > 0 && !(now - this.chatData[user][room].lastAction < ACTION_COOLDOWN)) {
| |
| 530 | var cmd = 'mute'; | |
| 531 | // defaults to the next punishment in config.punishVals instead of repeating the same action (so a second warn-worthy | |
| 532 | // offence would result in a mute instead of a warn, and the third an hourmute, etc) | |
| 533 | if (this.chatData[user][room].points >= pointVal && pointVal < 4) {
| |
| 534 | this.chatData[user][room].points++; | |
| 535 | cmd = config.punishvals[this.chatData[user][room].points] || cmd; | |
| 536 | } else { // if the action hasn't been done before (is worth more points) it will be the one picked
| |
| 537 | cmd = config.punishvals[pointVal] || cmd; | |
| 538 | this.chatData[user][room].points = pointVal; // next action will be one level higher than this one (in most cases) | |
| 539 | } | |
| 540 | if (config.privaterooms.indexOf(room) >= 0 && cmd === 'warn') cmd = 'mute'; // can't warn in private rooms | |
| 541 | // if the bot has % and not @, it will default to hourmuting as its highest level of punishment instead of roombanning | |
| 542 | if (this.chatData[user][room].points >= 4 && !this.hasRank(this.ranks[room] || ' ', '@&#~')) cmd = 'hourmute'; | |
| 543 | if (this.chatData[user].zeroTol > 4) { // if zero tolerance users break a rule they get an instant roomban or hourmute
| |
| 544 | muteMessage = ', Automated response: zero tolerance user'; | |
| 545 | cmd = this.hasRank(this.ranks[room] || ' ', '@&#~') ? 'roomban' : 'hourmute'; | |
| 546 | } | |
| 547 | if (this.chatData[user][room].points >= 2) this.chatData[user].zeroTol++; // getting muted or higher increases your zero tolerance level (warns do not) | |
| 548 | this.chatData[user][room].lastAction = now; | |
| 549 | if (this.chatData[user][room].points <= 2) this.say(connection, room, user + ', ' + warnMessage); | |
| 550 | if (this.chatData[user][room].points >= 3) this.say(connection, room, '/' + cmd + ' ' + user + muteMessage); | |
| 551 | } | |
| 552 | } */ | |
| 553 | }, | |
| 554 | cleanChatData: function() {
| |
| 555 | ||
| 556 | var chatData = this.chatData; | |
| 557 | for (var user in chatData) {
| |
| 558 | for (var room in chatData[user]) {
| |
| 559 | var roomData = chatData[user][room]; | |
| 560 | if (!Object.isObject(roomData)) continue; | |
| 561 | ||
| 562 | if (!roomData.times || !roomData.times.length) {
| |
| 563 | delete chatData[user][room]; | |
| 564 | continue; | |
| 565 | } | |
| 566 | var newTimes = []; | |
| 567 | var now = Date.now(); | |
| 568 | var times = roomData.times; | |
| 569 | for (var i = 0, len = times.length; i < len; i++) {
| |
| 570 | if (now - times[i] < 5 * 1000) newTimes.push(times[i]); | |
| 571 | } | |
| 572 | newTimes.sort(function(a, b) {
| |
| 573 | return a - b; | |
| 574 | }); | |
| 575 | roomData.times = newTimes; | |
| 576 | if (roomData.points > 0 && roomData.points < 4) roomData.points--; | |
| 577 | } | |
| 578 | } | |
| 579 | }, | |
| 580 | updateSeen: function(user, type, detail) {
| |
| 581 | if (type !== 'n' && config.rooms.indexOf(detail) === -1 || config.privaterooms.indexOf(toId(detail)) > -1) return; | |
| 582 | var now = Date.now(); | |
| 583 | if (!this.chatData[user]) this.chatData[user] = {
| |
| 584 | zeroTol: 0, | |
| 585 | lastSeen: '', | |
| 586 | seenAt: now | |
| 587 | }; | |
| 588 | if (!detail) return; | |
| 589 | var userData = this.chatData[user]; | |
| 590 | var msg = ''; | |
| 591 | switch (type) {
| |
| 592 | case 'j': | |
| 593 | case 'J': | |
| 594 | msg += 'joining '; | |
| 595 | break; | |
| 596 | case 'l': | |
| 597 | case 'L': | |
| 598 | msg += 'leaving '; | |
| 599 | break; | |
| 600 | case 'c': | |
| 601 | case 'c:': | |
| 602 | msg += 'chatting in '; | |
| 603 | break; | |
| 604 | case 'N': | |
| 605 | msg += 'changing nick to '; | |
| 606 | if (detail.charAt(0) !== ' ') detail = detail.substr(1); | |
| 607 | break; | |
| 608 | } | |
| 609 | msg += detail.trim() + '.'; | |
| 610 | userData.lastSeen = msg; | |
| 611 | userData.seenAt = now; | |
| 612 | }, | |
| 613 | getTimeAgo: function(time) {
| |
| 614 | time = ~~((Date.now() - time) / 1000); | |
| 615 | ||
| 616 | var seconds = time % 60; | |
| 617 | var times = []; | |
| 618 | if (seconds) times.push(seconds + (seconds === 1 ? ' second' : ' seconds')); | |
| 619 | if (time >= 60) {
| |
| 620 | time = ~~((time - seconds) / 60); | |
| 621 | var minutes = time % 60; | |
| 622 | if (minutes) times.unshift(minutes + (minutes === 1 ? ' minute' : ' minutes')); | |
| 623 | if (time >= 60) {
| |
| 624 | time = ~~((time - minutes) / 60); | |
| 625 | hours = time % 24; | |
| 626 | if (hours) times.unshift(hours + (hours === 1 ? ' hour' : ' hours')); | |
| 627 | if (time >= 24) {
| |
| 628 | days = ~~((time - hours) / 24); | |
| 629 | if (days) times.unshift(days + (days === 1 ? ' day' : ' days')); | |
| 630 | } | |
| 631 | } | |
| 632 | } | |
| 633 | if (!times.length) return '0 seconds'; | |
| 634 | return times.join(', ');
| |
| 635 | }, | |
| 636 | writeSettings: (function() {
| |
| 637 | var writing = false; | |
| 638 | var writePending = false; // whether or not a new write is pending | |
| 639 | var finishWriting = function() {
| |
| 640 | writing = false; | |
| 641 | if (writePending) {
| |
| 642 | writePending = false; | |
| 643 | this.writeSettings(); | |
| 644 | } | |
| 645 | }; | |
| 646 | return function() {
| |
| 647 | if (writing) {
| |
| 648 | writePending = true; | |
| 649 | return; | |
| 650 | } | |
| 651 | writing = true; | |
| 652 | var data = JSON.stringify(this.settings); | |
| 653 | fs.writeFile('settings.json.0', data, function() {
| |
| 654 | // rename is atomic on POSIX, but will throw an error on Windows | |
| 655 | fs.rename('settings.json.0', 'settings.json', function(err) {
| |
| 656 | if (err) {
| |
| 657 | // This should only happen on Windows. | |
| 658 | fs.writeFile('settings.json', data, finishWriting);
| |
| 659 | return; | |
| 660 | } | |
| 661 | finishWriting(); | |
| 662 | }); | |
| 663 | }); | |
| 664 | }; | |
| 665 | })(), | |
| 666 | writeMessages: (function() {
| |
| 667 | var writing = false; | |
| 668 | var writePending = false; // whether or not a new write is pending | |
| 669 | var finishWriting = function() {
| |
| 670 | writing = false; | |
| 671 | if (writePending) {
| |
| 672 | writePending = false; | |
| 673 | this.writeMessages(); | |
| 674 | } | |
| 675 | }; | |
| 676 | return function() {
| |
| 677 | if (writing) {
| |
| 678 | writePending = true; | |
| 679 | return; | |
| 680 | ||
| 681 | } | |
| 682 | writing = true; | |
| 683 | var data = JSON.stringify(this.messages); | |
| 684 | fs.writeFile('messages.json.0', data, function() {
| |
| 685 | // rename is atomic on POSIX, but will throw an error on Windows | |
| 686 | fs.rename('messages.json.0', 'messages.json', function(err) {
| |
| 687 | if (err) {
| |
| 688 | // This should only happen on Windows. | |
| 689 | fs.writeFile('messages.json', data, finishWriting);
| |
| 690 | return; | |
| 691 | } | |
| 692 | finishWriting(); | |
| 693 | }); | |
| 694 | }); | |
| 695 | }; | |
| 696 | })(), | |
| 697 | writeQuotes: (function() {
| |
| 698 | var writing = false; | |
| 699 | var writePending = false; // whether or not a new write is pending | |
| 700 | var finishWriting = function() {
| |
| 701 | writing = false; | |
| 702 | if (writePending) {
| |
| 703 | writePending = false; | |
| 704 | this.writeQuotes(); | |
| 705 | } | |
| 706 | }; | |
| 707 | return function() {
| |
| 708 | if (writing) {
| |
| 709 | writePending = true; | |
| 710 | return; | |
| 711 | ||
| 712 | } | |
| 713 | writing = true; | |
| 714 | var data = JSON.stringify(this.quotes); | |
| 715 | fs.writeFile('quotes.json.0', data, function() {
| |
| 716 | // rename is atomic on POSIX, but will throw an error on Windows | |
| 717 | fs.rename('quotes.json.0', 'quotes.json', function(err) {
| |
| 718 | if (err) {
| |
| 719 | // This should only happen on Windows. | |
| 720 | fs.writeFile('quotes.json', data, finishWriting);
| |
| 721 | return; | |
| 722 | } | |
| 723 | finishWriting(); | |
| 724 | }); | |
| 725 | }); | |
| 726 | }; | |
| 727 | })(), | |
| 728 | uncacheTree: function(root) {
| |
| 729 | var uncache = [require.resolve(root)]; | |
| 730 | do {
| |
| 731 | var newuncache = []; | |
| 732 | for (var i = 0; i < uncache.length; ++i) {
| |
| 733 | if (require.cache[uncache[i]]) {
| |
| 734 | newuncache.push.apply(newuncache, | |
| 735 | require.cache[uncache[i]].children.map(function(module) {
| |
| 736 | return module.filename; | |
| 737 | }) | |
| 738 | ); | |
| 739 | delete require.cache[uncache[i]]; | |
| 740 | } | |
| 741 | } | |
| 742 | uncache = newuncache; | |
| 743 | } while (uncache.length > 0); | |
| 744 | }, | |
| 745 | getDocMeta: function(id, callback) {
| |
| 746 | https.get('https://www.googleapis.com/drive/v2/files/' + id + '?key=' + config.googleapikey, function(res) {
| |
| 747 | var data = ''; | |
| 748 | res.on('data', function(part) {
| |
| 749 | data += part; | |
| 750 | }); | |
| 751 | res.on('end', function(end) {
| |
| 752 | var json = JSON.parse(data); | |
| 753 | if (json) {
| |
| 754 | callback(null, json); | |
| 755 | } else {
| |
| 756 | callback('Invalid response', data);
| |
| 757 | } | |
| 758 | }); | |
| 759 | }); | |
| 760 | }, | |
| 761 | getDocCsv: function(meta, callback) {
| |
| 762 | https.get('https://docs.google.com/spreadsheet/pub?key=' + meta.id + '&output=csv', function(res) {
| |
| 763 | var data = ''; | |
| 764 | res.on('data', function(part) {
| |
| 765 | data += part; | |
| 766 | }); | |
| 767 | res.on('end', function(end) {
| |
| 768 | callback(data); | |
| 769 | }); | |
| 770 | }); | |
| 771 | } | |
| 772 | }; |