· 6 years ago · Nov 13, 2019, 02:04 AM
1//<syntaxhighlight lang="javascript" style="display: none;">
2/**
3* This BotScript is open for everyone to use
4* Credit goes to Dorumin from Steven Universe Wiki for the original bot script
5* This one has no restrictions
6**/
7// Is after
8$.fn.isAfter = function(sel) {
9 return this.prevAll(sel).length !== 0;
10};
11// Reverse
12String.prototype.reverse = function(){
13 var toReturn = '';
14 for (var i = this['length'] -1 ; i > -1; i--) toReturn += this[i];
15 return toReturn;
16};
17// Shuffle
18function shuffle(array) {
19 var currentIndex = array.length;
20 var temporaryValue;
21 var randomIndex;
22 // While there remain elements to shuffle...
23 while (0 !== currentIndex) {
24 // Pick a remaining element...
25 randomIndex = Math.floor(Math.random() * currentIndex);
26 currentIndex -= 1;
27 // And swap it with the current element.
28 temporaryValue = array[currentIndex];
29 array[currentIndex] = array[randomIndex];
30 array[randomIndex] = temporaryValue;
31 }
32 return array;
33}
34// Don't leave
35window.onbeforeunload = function() {
36 if (leave || restart) {mainRoom.socket.send(new models.LogoutCommand().xport());return;}
37 return 'Man you must be out of your mind!';
38};
39// Regex Escape
40RegExp.escape = function(s) {
41 return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
42};
43// Plural
44function plural(num, singular, Plural) {
45 return (num == 1 || num == -1) ? singular : Plural;
46}
47// Levenshtein distance, for string comparison.
48var levDist = function(s, t) {
49 var d = []; //2d matrix
50 // Step 1
51 var n = s.length;
52 var m = t.length;
53 if (n == 0) return m;
54 if (m == 0) return n;
55 s = s.toLowerCase();
56 t = t.toLowerCase();
57 if (s == t) return 0;
58 //Create an array of arrays in javascript (a descending loop is quicker)
59 for (var i = n; i >= 0; i--) d[i] = [];
60 // Step 2
61 for (var i = n; i >= 0; i--) d[i][0] = i;
62 for (var j = m; j >= 0; j--) d[0][j] = j;
63 // Step 3
64 for (var i = 1; i <= n; i++) {
65 var s_i = s.charAt(i - 1);
66 // Step 4
67 for (var j = 1; j <= m; j++) {
68 //Check the jagged ld total so far
69 if (i == j && d[i][j] > 4) return n;
70 var t_j = t.charAt(j - 1);
71 var cost = (s_i == t_j) ? 0 : 1; // Step 5
72 //Calculate the minimum
73 var mi = d[i - 1][j] + 1;
74 var b = d[i][j - 1] + 1;
75 var c = d[i - 1][j - 1] + cost;
76 if (b < mi) mi = b;
77 if (c < mi) mi = c;
78 d[i][j] = mi; // Step 6
79 //Damerau transposition
80 if (i > 1 && j > 1 && s_i == t.charAt(j - 2) && s.charAt(i - 2) == t_j) {
81 d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost);
82 }
83 }
84 }
85 // Step 7
86 return d[n][m];
87};
88// Call Api
89function Api(method, data, callback) {
90 data.format = 'json';
91 $.ajax({
92 type: method,
93 data: data,
94 dataType: 'json',
95 url: wgScriptPath + '/api.php',
96 success: function(response) {
97 callback(response);
98 },
99 error: function(xhr, error) {
100 Droid.errors.push({
101 type: 'Timeout',
102 xhr: xhr,
103 error: error,
104 caller: callback.name,
105 timestamp: $.now()
106 });
107 }
108 });
109}
110Api.post = function(data, callback) {
111 Api('POST', data, callback);
112};
113Api.get = function(data, callback) {
114 Api('GET', data, callback);
115};
116// For custom inline-alerts
117function getInlineRegex(variable, Default, title) {
118 $.get('/api.php?action=query&format=json&prop=revisions&rvprop=content&titles=' + title, function(data) {
119 if (data.query.pages['-1']) {
120 window[variable] = Default;
121 } else {
122 window[variable] = RegExp.escape(data.query.pages[Object.keys(data.query.pages)[0]].revisions[0]['*']).replace(/\\\$(1|2|3)/g, '.*');
123 }
124 });
125}
126getInlineRegex('kickmsg', '.+ has been kicked by .+', 'MediaWiki:Chat-user-was-kicked');
127getInlineRegex('cbanmsg', '.+ has been banned by .+', 'MediaWiki:Chat-user-was-banned');
128getInlineRegex('quitmsg', '.+ has left the chat', 'MediaWiki:Chat-user-parted');
129getInlineRegex('joinmsg', '.+ has joined the chat', 'MediaWiki:Chat-user-joined');
130getInlineRegex('undomsg', '.+ has ended the Chat ban for .+', 'MediaWiki:Chat-user-was-unbanned');
131var kickcount = 0,
132 cbancount = 0,
133 quitcount = 0,
134 joincount = 0,
135 chatcount = 0,
136 restart = false,
137 leave = false,
138 postLog = false,
139 wasFound = false,
140 isLogging = false,
141 logText = '</pre>',
142 commandlogText = '</pre>',
143 mcmcount = 0,
144 cmdcount = 0,
145 version = 'v2.0',
146 curDay = new Date().getUTCDate(),
147 botStart = $.now(),
148 Droid = {};
149Droid.triggered = {};
150Droid.seenUpdCount = 0;
151Droid.seenCrtCount = 0;
152Droid.errors = [];
153Droid.excused = [];
154Droid.banned = [];
155Droid.caps = {};
156Droid.warned = [];
157Droid.banned = [];
158Droid.kick = function(usr) {
159 usr = usr.charAt(0).toUpperCase() + usr.slice(1);
160 setTimeout(mainRoom.kick({
161 name: usr
162 }), 400);
163};
164Droid.revoke = function(usr){
165 var i = Droid.excused.indexOf(usr);
166 if(i != -1) {
167 Droid.excused.splice(i, 1);
168 }
169 Droid.excused.filter(function(i) {
170 return i != usr;
171 });
172};
173Droid.ban = function(u, tme, r){
174 switch(tme){
175 case '2 hours' :
176 var bt = 7200;
177 break;
178 case '1 day' :
179 var bt = 86400;
180 break;
181 case '3 days':
182 var bt = 259200;
183 break;
184 case '1 week':
185 var bt = 604800;
186 break;
187 case '2 weeks':
188 var bt = 1209600;
189 break;
190 case '1 month':
191 var bt = 2592000;
192 break;
193 case '3 months':
194 var bt = 7776000;
195 break;
196 case '6 months':
197 var bt = 15552000;
198 break;
199 case '1 year':
200 var bt = 31536000;
201 break;
202 case 'infinite':
203 var bt = 31536000000;
204 break;
205 default: return;
206 }
207 mainRoom.socket.send(new models.BanCommand({
208 userToBan: u,
209 time: bt,
210 reason: r || ''
211 }).xport());
212};
213Droid.bannedsites = ['//matiyunu.wikia.com', '//community.wikia.com', '//electroboom.wikia.com'];
214Droid.reasons = [
215 {
216 site: '//matiyunu.wikia.com',
217 reason: 'What part of "cease services" is hard to understand? This bot is no longer serving this community'
218 },
219 {
220 site: '//community.wikia.com',
221 reason: 'Preventing abuse'
222 },
223 {
224 site: '//electroboom.wikia.com',
225 reason: 'Preventing abuse'
226 }
227];
228Droid.spam = function(usr) {
229 if (!wasFound) return;
230 if (Droid.spam[usr] === undefined) Droid.spam[usr] = 1;
231 else Droid.spam[usr]++;
232 if (Droid.spam[usr] > 7) {
233 send(usr + ", please don't spam!");
234 if (Droid.spam.wow[usr] === undefined) {
235 Droid.kick(usr);
236 Droid.spam.wow[usr] = 1;
237 } else {
238 Droid.modCmds.ban(wgUserName, usr + ' | 1 day | Repeatedly spamming');
239 Droid.spam.wow[usr] = undefined;
240 }
241 Droid.spam[usr] = 0;
242 return;
243 }
244 setTimeout(function() {
245 Droid.spam[usr]--;
246 }, 7000);
247};
248Droid.spam.wow = {};
249Droid.parseTime = function(secs) {
250 secs = Number(secs);
251 var toReturn = '';
252 if (isNaN(secs) || secs >= 31536000000) return 'infinity';
253 var obj = {
254 second: 1,
255 minute: 60,
256 hour: 3600,
257 day: 86400,
258 week: 604800,
259 month: 2592000,
260 year: 31536000
261 };
262 var arr = Object.keys(obj).sort(function(a, b) {
263 return obj[b] - obj[a];
264 });
265 $.each(arr, function(i, val) {
266 var d = obj[val];
267 if (d <= secs) {
268 var r = Math.floor(secs / d);
269 secs -= r * d;
270 toReturn += r + ' ' + val + (r != 1 ? 's ' : ' ');
271 }
272 });
273 return toReturn.trim();
274};
275// Swears
276var SWEARS = ["\\bd?a?fuc?ki?n?g?\\b", // fuck
277 "\\bw+\\s*t+\\s*f+\\b", // WTF
278 "\\bmotherfuck", "\\b(bull)?sh[i!]t\\b", "\\bsh[i!]tt", "\\bsh[i!]tp", "\\bb[i!]tch", "\\bdafuq\\b", "\\bwhore\\b", "\\bmofo\\b", "\\bfml\\b", "\\bgtfo\\b", "\\bstfu\\b", "\\bidf[kc]\\b", "\\bidgaf\\b", "\\bidef[kc]\\b", "\\blmfao\\b", "\\bjfc\\b", "\\bomfg", "\\bomf\\b", "\\bffs\\b", "\\bmilf\\b", "\\bretard[s!]\\b", "\\bretarded\\b"
279 ],
280 // Slurs
281 SLURS = ["\\bnigg", "\\bniglets?\\b", "\\bfags?\\b", "\\bfagg", "\\bspick?s?\\b", "\\bpussy", '\\bcunt'],
282 weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
283Droid.modCmds = {
284 block: function (n, t, c) {
285 if (mw.config.get('wgUserGroups').indexOf('sysop') === -1) {
286 send('I do not have enough permissions to block that user');
287 return;
288 }
289 if (mainRoom.model.users.findByName(n).attributes.groups.indexOf('sysop') === -1){
290 send('This is an administrative action. You need to have admin rights to use it.');
291 return;
292 }
293 if (!t) {
294 send('Usage: +block USER for > REASON | EXPIRY | block ip | cannot post | override');
295 send('\'block ip | cannot post | override\' part are just all options to block the user. They do not need to be used in the order you just saw nor do all 3 of them have to be used at the same time.');
296 return;
297 }
298 t = t.split(' | ');
299 if (t[0].split(' for > ')[1] && t[0].split(' for > ')[0] === mw.config.get('wgUserName') || !t[0].split(' for > ')[1] && t[0] === mw.config.get('wgUserName')) {
300 send('You cannot block me.');
301 return;
302 }
303 if (t[0].split(' for > ')[1] && t[0].split(' for > ')[0] === n || !t[0].split(' for > ')[1] && t[0].split(' for > ')[0] === n) {
304 send('You cannot block yourself');
305 return;
306 }
307 var config = {
308 action: 'block',
309 user: t[0].split(' for > ')[0],
310 reason: t[0].split(' for > ')[1] || 'No reason was given.',
311 expiry: t[1],
312 bot: true,
313 token: mw.user.tokens.get('editToken')
314 };
315 if (t.indexOf('block ip') !== -1) config.autoblock = 1;
316 if (t.indexOf('cannot post') === -1) config.allowusertalk = 1;
317 if (t.indexOf('override') !== -1) config.reblock = 1;
318 if (mainRoom.model.users.findByName(t[0].split(' for > ')[0])) {
319 Droid.kick(t[0].split(' for > ')[0]);
320 }
321 Api.post(config, function (d) {
322 if (!d.error) {
323 send('[[Special:Contributions/' + t[0].split(' for > ')[0] + '|' + t[0].split(' for > ')[0] + ']] has been successfully blocked!');
324 }
325 else {
326 send('Something went wrong while blocking [[Special:Contributions/' + t[0].split(' for > ')[0] + '|' + t[0].split(' for > ')[0] + ']]: ' + d.error.info);
327 }
328 });
329
330 },
331 unblock: function (n, t, c){
332 if (mw.config.get('wgUserGroups').indexOf('sysop') === -1) {
333 send('I do not have enough permissions to unblock that user');
334 return;
335 }
336 if (!t) {
337 send('Usage: +unblock USER | REASON');
338 return;
339 }
340 t = t.split(' | ');
341 Api.post({
342 action: 'unblock',
343 reason: t[1] || 'No reason given',
344 user: t[0],
345 bot: true,
346 token: mw.user.tokens.get('editToken')
347 }, function (d){
348 if (!d.error) {
349 send('[[Special:Contributions/' + t[0] + '|' + t[0] + ']] has been unblocked successfully!');
350 }
351 else {
352 send('An error occurred while blocking [[Special:Contributions/' + t[0] + '|' + t[0] + ']]: ' + d.error.info);
353 }
354 });
355 },
356 on: function(n, t, c){
357 if (localStorage.getItem('OBenabled') === 'enabled') {
358 send('Already up and running!');
359 } else {
360 localStorage.setItem('OBenabled', 'enabled');
361 send('Booting up!');
362 }
363 },
364 off: function(n, t, c) {
365 if (localStorage.getItem('OBenabled') === 'disabled') {
366 send('...');
367 } else {
368 localStorage.setItem('OBenabled', 'disabled');
369 send('Shutting down...');
370 }
371 },
372 enable: function(n, t, c) {
373 if (localStorage.getItem('disabled') === 'enabled') {
374 send('Swear checking is already enabled!');
375 } else {
376 localStorage.setItem('disabled', 'enabled');
377 send('Enabling swear checking!');
378 }
379 },
380 disable: function(n, t, c) {
381 if (localStorage.getItem('disabled') === 'disabled') {
382 send('Swear checking is already disabled.');
383 } else {
384 localStorage.setItem('disabled', 'disabled');
385 send('Swear checking disabled.');
386 }
387 },
388 news: function(n, t, c){
389 send(Droid.news);
390 },
391 runtime: function(n, t, c) {
392 var botEnd = $.now();
393 var msDiff = Math.floor(botEnd - botStart); // in ms
394 var secDiff = Math.floor(msDiff / 1000 % 60); // in s
395 var minDiff = Math.floor(msDiff / 60 / 1000 % 60); // in minutes
396 var hourDiff = Math.floor(msDiff / 3600 / 1000 % 24); // in hours
397 var dayDiff = Math.floor(msDiff / 86400 / 1000); // in days
398 send(mw.config.get('wgUserName') + ' ' + version + ' has been running for ' + dayDiff + ' days, ' + hourDiff + ' hours, ' + minDiff + ' minutes, and ' + secDiff + ' seconds.');
399 },
400 log: function(n, t, c) {
401 postLog = true;
402 send('Logging...');
403 submitLogs();
404 },
405 deny: function(n, t, c){
406 if (!t) {
407 send("Usage: +deny USER | REASON.");
408 return;
409 }
410 t = t.split(' | ');
411 if (localStorage.getItem('deny ' + t[0])){
412 send(t[0] + ' is already denied of my commands. Reason: ' + localStorage.getItem('deny ' + t[0]));
413 return;
414 }
415 localStorage.setItem('deny ' + t[0], t[1] || 'No reason was given.');
416 send(t[0] + ' is now banned from using my commands.');
417 },
418 allow: function(n, t, c){
419 if(!t) {
420 send('Usage: +allow USERNAME');
421 return;
422 }
423 if(!localStorage.getItem('deny ' + t)){
424 send(t + ' is not banned from using my commands.');
425 return;
426 }
427 localStorage.removeItem('deny ' + t);
428 send(t + ' can now use my commands.');
429 },
430 gone: 'kick',
431 eject: 'kick',
432 kick: function(n, t, c) {
433 if(!t) {
434 send('Usage: +kick USER NAME.');
435 return;
436 }
437 if(t === n) {
438 send('Why would you want to kick yourself lul.');
439 return;
440 }
441 if(t == mw.config.get('wgUserName')) {
442 send('No.');
443 return;
444 }
445 if(mainRoom.model.users.findByName(t)) {
446 Droid.kick(t);
447 }
448 else {
449 send(t + ' isn\'t on the chat. So kicking them is impossible.');
450 return;
451 }
452 },
453 banish: 'ban',
454 suspend: 'ban',
455 wham: function(n, t, c){
456 if (!t){
457 send('Keep in mind, this will ban the user from chat for infinity. Use the \'!unban\' command to unban the users. Usage: !wham REASON | USER 1 | USER 2 | USER 3 | Etc...');
458 return;
459 }
460 var users = t.split(' | ');
461 if (users.includes(mw.config.get('wgUserName') )|| users.includes(n)){
462 send('Haha. No.');
463 return;
464 }
465 for (var e = 1; e < users.length; e ++){
466 mainRoom.socket.send(new models.BanCommand({
467 userToBan: users[e],
468 time: 31536000000,
469 reason: 'Infinitely banned from chat using the wham command by [[User:' + n + '|' + n + ']]. Reason given: ' + users[0]
470 }).xport());
471 }
472 send('Ban(s) were successful.');
473 },
474 ban: function(n, t, c) {
475 if(!t) {
476 send('Usage: +ban USER NAME | TIME | REASON');
477 return;
478 }
479 var bre = t.split(' | ');
480 if(bre[0] === n) {
481 send('Why would you want to ban yourself lul.');
482 return;
483 }
484 if(bre[0] == mw.config.get('wgUserName')) {
485 send('No.');
486 return;
487 }
488 if(mainRoom.model.users.findByName(bre[0])) {
489 send('Banning ' + bre[0] + ' from chat...');
490 Droid.ban(bre[0], bre[1], bre[2]);
491 return;
492 }
493 else {
494 send(bre[0] + ' isn\'t on the chat. Not banning them.');
495 return;
496 }
497 send('Invalid expiry time.');
498 },
499 unban: function(n, t, c) {
500 if (!t){
501 send('Usage: +unban USER NAME | REASON');
502 }
503 var s = t.split(' | ');
504 send('Unbanning ' + s[0] + '...');
505 mainRoom.socket.send(new models.BanCommand({
506 userToBan: s[0],
507 time: 0,
508 reason: s[1] || ''
509 }).xport());
510 },
511 newusers: function(n, t, c) {
512 if (t.trim() == 'ban') {
513 Droid.bananaMode = 'ban';
514 } else if (/off|disable/.test(t)) {
515 Droid.bananaMode = false;
516 } else if (/on|enable/.test(t)) {
517 Droid.bananaMode = true;
518 } else {
519 Droid.bananaMode = !Droid.bananaMode;
520 }
521 switch (Droid.bananaMode) {
522 case true:
523 send('Kicking new users...');
524 break;
525 case false:
526 send('Leaving new users alone.');
527 break;
528 case 'ban':
529 send('Banning new users...');
530 }
531 }
532};
533
534Droid.cmds = {
535 ship : function (n, t, c){
536 var toShip = t.split(' | ');
537 if (!t || !toShip[0] || !toShip[1]){
538 send('Usage: !ship CHOICE A | CHOICE B');
539 return;
540 } else if (toShip[2]){
541 send('2 maximum kiddo.');
542 return;
543 }
544 send('(heart) Lovely. Ship name: ' + toShip[0].slice(Math.round(toShip[0].length / 2)).charAt(0).toUpperCase() + toShip[0].slice(Math.round(toShip.length / 2)).slice(1) + toShip[1].slice(Math.round(toShip.length / 2)));
545 },
546 pi: function(n, t, c){
547 send('3.141592653589793238462');
548 },
549 hello: function(n, t, c) {
550 n = t.trim() ? t.trim() : n;
551 if (n == 'Mario&LuigiBowser\'sInsideStory') {
552 send('Hello head coder!');
553 } else if (n == 'Chase McFly') {
554 send('Hello Chase!');
555 } else if (n == 'TheKorraFanatic') {
556 send('Hello Head-Buro.');
557 } else if (n == 'Messenger Deception') {
558 send('Hello Messy!');
559 } else if (n == 'Blue Tree Roots') {
560 send('Hello Blue Screen of Death!');
561 } else if (n === 'South Ferry'){
562 send('Hello there, ferry sailing south!');
563 } else {
564 send('Hello there ' + n + '!');
565 }
566 },
567 hi:'hello',
568 boyhood: function(n, t, c) {
569 send('How long did boyhood take to make?');
570 localStorage.setItem('tell Vaxxi', 'BOYHOOD TOOK 12 YEARS TO MAKE');
571 },
572 death: function(n, t, c) {
573 send('Who is dead?');
574 localStorage.setItem('tell Galacticdreamer', 'Jasper is dead.');
575 },
576 bye: function(n, t, c) {
577 send('Goodbye, ' + n + '. Don\'t be gone for long. :(');
578 },
579 dabs: 'dab',
580 dab: function(n, t, c) {
581 n = t.trim() ? t.trim() : n;
582 send('/me dabs to ' + n + '.');
583 },
584 emotes: function(n, t, c) {
585 send('You can view the emoticons [[MediaWiki:Emoticons|here]].');
586 },
587 stop: function(n, t, c) {
588 send('(stop)');
589 },
590 commands: function(n, t, c) {
591 send('You can view my commands [[Project:Chat/Bot Commands|here]].');
592 },
593 youtube: function(n, t, c){
594 var vd = t.replace(/https:\/\/youtu.be\/3MnrAw8Icfs\|https:\/\/www.youtube.com\/watch\?v=/g, '');
595 send('[yt="' + vd + '"]');
596 },
597 spingeville: function(n, t, c) {
598 send('[yt="2KAJ6sCbEiM"]');
599 },
600 random: function(n, t, c) {
601 var random = ["Spingeville", "YouTube Poop", "A Random Word lololo", "Test Me"];
602 for (var i = 0; i < t; i += 1) {
603 send(random[i]);
604 }
605 },
606 contributions: function(n, t, c) {
607 if(!t) {
608 send('You can view your contributions [[Special:Contributions/' + n + '|here]].');
609 return;
610 }
611 if(t === mw.config.get('wgUserName')) {
612 send('You can view my contributions [[Special:Contributions/' + mw.config.get('wgUserName') + '| here]]. (or you could\'ve clicked on my name on the side rail clicked "contributions".');
613 return;
614 }
615 if(mainRoom.model.users.findByName(t)) {
616 send('You can view ' + t + '\'s contributions [[Special:Contributions/' + t + '|here]] (Or you could\'ve just clicked on their name on the side rail and click their contributions).');
617 return;
618 }
619 send('You can view ' + t + '\'s contributions [[Special:Contributions/' + t + '|here]].');
620 },
621 rate: function(n, t, c){
622 if (!t){
623 send('Usage: !rate CHOICE');
624 return;
625 }
626 var rating = localStorage.getItem('rate ' + t) === null ? Math.floor(Math.random() * 11) : localStorage.getItem('rate ' + t);
627 if (t === mw.config.get('wgUserName')) {
628 rating = '10';
629 t = 'myself';
630 }
631 if (t === n) {
632 t = "you";
633 var stored = n;
634 }
635 send(n + ', I\'d give ' + t + ' a ' + rating +'/10.');
636 if (typeof stored !== "undefined") t = n;
637 if (t === mw.config.get('wgUserName')) return;
638 if (localStorage.getItem('rate ' + t) === null){
639 localStorage.setItem('rate ' + t, rating);
640 }
641 },
642 choose: function(n, t, c) {
643 if(!t){
644 send('Usage: !choose CHOICE A | CHOICE B | Etc...');
645 return;
646 }
647 var choice = t.split(' | ');
648 var ac = Math.floor(Math.random() * choice.length);
649 if (choice[1] === undefined){
650 send('Error: You have not specified a second choice.');
651 return;
652 }
653 send(n + ', I choose ' + choice[ac] + '!');
654 },
655 rps: function(n, t, c) {
656 if (!t){
657 send("Try again and choose 'rock', 'paper' or 'scissors'.");
658 return;
659 }
660 var s = Math.floor(Math.random() * 3)
661 if (['rock', 'paper', 'scissors'].indexOf(t.toLowerCase()) === -1) {
662 send("Invalid choice. This game is now void.");
663 } else {
664 send("I choose " + ["rock", "paper", "scissors"][s] + '!');
665 }
666 t = t.toLowerCase();
667 if (s == 0 && t == 'rock') {
668 send("Tied.");
669 } else if (s == 0 && t == 'paper') {
670 send("Good game.");
671 } else if (s == 0 && t == 'scissors') {
672 send("I win!");
673 } else if (s == 1 && t == 'rock') {
674 send("I win!");
675 } else if (s == 1 && t == 'paper') {
676 send("Tied.");
677 } else if (s == 1 && t == 'scissors') {
678 send("Good game.");
679 } else if (s == 2 && t == 'rock') {
680 send("Good game.");
681 } else if (s == 2 && t == 'paper') {
682 send("I win!");
683 } else if (s == 2 && t == 'scissors') {
684 send("Tied.");
685 }
686 },
687 baby: function(n, t, c) {
688 send('https://www.youtube.com/watch?v=kffacxfA7G4');
689 },
690 logs: function(n, t, c) {
691 var d = new Date();
692 var ttl = d.getUTCDate() + '_' + wgMonthNamesShort[d.getUTCMonth() + 1] + '_' + d.getUTCFullYear();
693 send('[[[Project:Chat/Logs|All logs]]] - [[[Project:Chat/Logs/' + ttl + '|Today]]]');
694 },
695 test: function(n, t, c) {
696 send('ʇsǝʇ¡');
697 },
698 info: function(n, t, c) {
699 send(mw.config.get('wgUserName') + ' ' + version + ': Commands are found [[Project:Chat/Bot Commands|here]]. To report errors or bugs, or to suggest new features or commands, contact [[w:c:gumballchatbase:Message Wall:Mario&LuigiBowser\'sInsideStory|Mario&LuigiBowser\'sInsideStory]]. Swear checking: ' + localStorage.getItem('disabled') + '. Commands: ' + localStorage.getItem('OBenabled') + '. Operator: ' + (Droid.operator || 'unspecified') + '.');
700 },
701 site: function(n, t, c) {
702 send('You are using [[w:c:homepage|Wikia.com]], a website dedicated to wiki farming.');
703 },
704 tou: function(n, t, c) {
705 send('Wikia\'s Terms of Use are located [[w:Terms of Use|here]].');
706 },
707 rules: function(n, t, c) {
708 send('You can find the chat rules [[Project:Regulations|here]].');
709 },
710 bot: function(n, t, c) {
711 send('http://www.bash.org/?33832');
712 },
713 fun: function(n, t, c) {
714 send('Fun you say? You may be looking for this: http://theuselessweb.com');
715 },
716 donut: function(n, t, c) {
717 send('[big]◯[/big]');
718 },
719 swag: function(n, t, c) {
720 send('The user above me has some serious swag.');
721 },
722 bomb: function(n, t, c){
723 t = t.trim();
724 if (!Number(t)) t = 50;
725 t = Number(t) > 50? 50 : Number(t);
726 var u = t.split(' | ');
727 var toBomb = [u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], u[0], ];
728 for (var b = u[1]; b < 50; b += 1) {
729 send(toBomb[b]);
730 }
731 },
732 nc: function(n, t, c) {
733 send('[[w:c:uncyclopedia:Nobody cares|Nobody cares]]');
734 },
735 np: function(n, t, c){
736 send('[img="i2.kym-cdn.com/photos/images/original/000/913/758/a12.jpg"]');
737 },
738 memes: function(n, t, c) {
739 send('It\'s a meme you dip.');
740 },
741 ping: function(n, t, c) {
742 send('Pong!');
743 Droid.ponged = true;
744 },
745 announce: function(n, t, c) {
746 !mainRoom.model.users.findByName(n).attributes.isModerator&&send('/announce ' + t);
747 },
748 google: function(n, t, c) {
749 send('https://www.google.com/#q=' + encodeURIComponent(t) + '&safe=strict');
750 },
751 coppa: function(n, t, c) {
752 send('http://community.wikia.com/wiki/User_blog:Semanticdrifter/Updates_to_COPPA');
753 },
754 speakre: function(n, t, c) {
755 send('!speakre');
756 },
757 speak: function(n, t, c) {
758 if (!t) {
759 send('I\'ve spoken. Happy now?');
760 return;
761 }
762 send(t);
763 },
764 avatar: function(n, t, c) {
765 t = t.trim();
766 if (!t) {
767 send('Usage: !avatar USER NAME');
768 return;
769 }
770 var usr = mainRoom.model.users.findByName(t);
771 if (usr) {
772 send(usr.attributes.avatarSrc.slice(0, -23));
773 } else {
774 $.get('/wiki/User:' + t, function(page) {
775 send($(page).find('.masthead-avatar .avatar').attr('src').replace('/scale-to-width-down/150', ''));
776 }).fail(function(page) {
777 page = page.responseText;
778 send($(page).find('.masthead-avatar .avatar').attr('src').replace(/\/revision\/.*|\/scale.*/, ''));
779 });
780 }
781 },
782 editcount: function(n, t, c){
783 if (!t){
784 send('Usage: editcount USERNAME');
785 return;
786 }
787 $.get('/wiki/Special:Contributions/' + t, function (ec) {
788 if ($(ec).find('.tally em').html() === '0'){
789 send(t + ' has never edited on this wiki.');
790 return;
791 } else if ($(ec).find('.tally em').html() === undefined){
792 send('The user account "' + t + '" does not exist.');
793 return;
794 }
795 send(t + ' has ' + $(ec).find('.tally em').html() + ' edits total.');
796 });
797 },
798 tag: function(n, t, c){
799 if (!t) {
800 send('Usage: !tag TAGNAME.');
801 return;
802 }
803 t = t.split(' ')[0] ? t.split(' ')[0] : t;
804 if (!localStorage.getItem('tag ' + t)){
805 send(n + ', tag name [b]' + t + '[/b] was not found. You can create this tag with !createtag.');
806 return;
807 }
808 send(localStorage.getItem('tag ' + t));
809 },
810 createtag: function(n, t, c){
811 if (!t) {
812 send('Usage: !createtag TAGNEAME CONTENTS');
813 return
814 }
815 var tagName = t.split(' ')[0];
816 var tagContents = t.split(' ').slice(1).join(' ');
817 if (localStorage.getItem('tag ' + tagName)){
818 send('That tag already exists. To edit this tag, use !edittag. To delete this tag, use !cleartag');
819 return;
820 }
821 localStorage.setItem('tag ' + tagName, tagContents);
822 send(n + ', tag created.');
823 },
824 edittag: function(n, t, c){
825 if (!t) {
826 send('Usage: !edittag TAGNAME CONTENTS');
827 return;
828 }
829 var tagName = t.split(' ')[0];
830 var tagContents = t.split(' ').slice(1).join(' ');
831 localStorage.setItem('tag ' + tagName, tagContents);
832 send(n + ', tag updated.');
833 },
834 cleartag: function(n, t, c){
835 if (!t) {
836 send('Usage: !cleartag TAGNAME');
837 return;
838 }
839 t = t.split(' ') ? t.split(' ')[0] : t;
840 if (!localStorage.getItem('tag ' + t)){
841 send(n + ', tag name [b]' + t + '[/b] was not found. You can create this tag with !createtag.');
842 return;
843 }
844 localStorage.removeItem('tag ' + t);
845 send(n + ', tag deleted.');
846 },
847 note: function(n, t, c) {
848 if (!t) {
849 send('Usage: !note NOTE');
850 return;
851 }
852 if (localStorage.getItem('note-for ' + n)){
853 send('You already have a note pending. Use !getnote to retrieve your note or !clearnote to delete your note.');
854 return;
855 }
856 localStorage.setItem('note-for ' + n, t);
857 send('Noted! If you want to retrieve your note, use !getnote');
858 },
859 getnote: function(n, t, c){
860 if (!localStorage.getItem('note-for ' + n)) {
861 send('You have no notes. Please use !note to set a note.');
862 return;
863 }
864 send(n + ', here is your note: ' + localStorage.getItem('note-for ' + n) + '.');
865 },
866 clearnote: function(n, t, c) {
867 if(!localStorage.getItem('note-for ' + n)) {
868 send('You have no notes pending. Use !note to set a note');
869 return;
870 }
871 localStorage.removeItem('note-for ' + n);
872 send(n + ', your note has been cleared.');
873 },
874 tell: function(n, t, c) {
875 var s = t.split(/ that:? /);
876 if (s.length == 1) {
877 var S = t.split(/\s+/),
878 P = [];
879 for (var i = 0; i < S.length; i++)
880 if (Droid.seen[S.slice(0, i).join(' ')])
881 P.push(S.slice(0, i).join(' '));
882 P = P.filter(Boolean);
883 if (P.length == 1) {
884 s = [P[0], t.slice(P[0].length)];
885 } else {
886 send('Usage: [code]!tell USER NAME that MESSAGE');
887 return;
888 }
889 } else {
890 s = [s[0], s.slice(1).join(' that ')];
891 }
892 s[0] = s[0].charAt(0).toUpperCase() + s[0].slice(1);
893 if (t === '') {
894 send('Usage: [code]!tell USER NAME that MESSAGE');
895 return;
896 }
897 if (s[0] == n) {
898 send('I\'m not sending yourself a message. Winners don\'t use drugs.');
899 return;
900 }
901 if (s[0] == mw.config.get('wgUserName')) {
902 send('How about no?');
903 return;
904 }
905 if (mainRoom.model.users.findByName(s[0])) {
906 send('They\'re already on chat. Tell them yourself you lazy bum.');
907 return;
908 }
909 if (!localStorage.getItem('tell ' + s[0])) {
910 localStorage.setItem('tell ' + s[0], 'Ah! ' + s[0] + '! ' + n + ' wanted me to tell you: ' + s[1] + '.');
911 send('Okay! I will tell ' + s[0] + ' that next time we meet.');
912 } else {
913 send(s[0] + ' already has a message pending. Please wait for them to speak and try again.');
914 }
915 },
916 gettell: function(n, t, c) {
917 t = t.trim();
918 t = t.charAt(0).toUpperCase() + t.slice(1);
919 if (!t) {
920 send('Usage: !gettell USER NAME');
921 return;
922 }
923 if (localStorage.getItem('tell ' + t)) {
924 send('on ' + t + (t.slice(-1) == 's' ? "'" : "'s") + ' inbox: ' + localStorage.getItem('tell ' + t).split('tell you: ')[1]);
925 } else {
926 send(t + ' has no messages pending!');
927 }
928 },
929 seen: function(n, t, c) {
930 t = t.trim();
931 t = t.charAt(0).toUpperCase() + t.slice(1);
932 if (t === '') {
933 send('Usage: !seen USER NAME');
934 return;
935 }
936 if (t == n) {
937 send('Heck I dunno, ask ' + n);
938 return;
939 }
940 if (t == mw.config.get('wgUserName')) {
941 send('No.');
942 return;
943 }
944 if (mainRoom.model.users.findByName(t) && t !== 'Sophiedp') {
945 send('They\'re in chat right now so... you just pinged them.');
946 return;
947 }
948 if (t == 'Jasper') {
949 send('Jasper is dead.');
950 return;
951 }
952 if (t == '2NE1') {
953 send('2NE1 is dead, like Jasper.');
954 return;
955 }
956 if (t == 'Rose') {
957 send('(satan)');
958 return;
959 }
960 if (t == 'My will to live') {
961 send('[big] (seekhelp)');
962 return;
963 }
964 if (t == 'My life') {
965 send('I have not seen My life. Did you mean your mom?');
966 return;
967 }
968 if (t == 'Chuck Norris') {
969 send('I have not seen Chuck Norris. Chuck Norris will see me first.');
970 return;
971 }
972 if (t == 'My mom') {
973 send('I have not seen My mom. Did you mean Mario?');
974 return;
975 }
976 if (t == 'Sophiedp' && mainRoom.model.users.findByName('Sophiedp')) {
977 send('Sophie never leaves.');
978 return;
979 }
980 var modsOn = mainRoom.model.users.models.filter(function(el) {
981 var a = el.attributes;
982 return a.isModerator && a.name != wgUserName;
983 }).length;
984 if (!modsOn && /last/i.test(t) && /mod/i.test(t) && localStorage.getItem('last-online-mod')) {
985 Droid.cmds.seen(n, localStorage.getItem('last-online-mod'), c);
986 return;
987 }
988 if (!Droid.seen) {
989 send('Seen database has not loaded yet.');
990 }
991 if (Droid.seen.hasOwnProperty(t)) {
992 var end = (new Date()).getTime();
993 var ms = end - Droid.seen[t].timeStamp; // in ms
994 var sec = Math.floor(ms / 1000 % 60); // in s
995 var min = Math.floor(ms / 60 / 1000 % 60); // in minutes
996 var hr = Math.floor(ms / 3600 / 1000 % 24); // in hours
997 var day = Math.floor(ms / 86400 / 1000); // in days
998 var days = day ? day + plural(day, ' day', ' days') + ', ' : '';
999 var hours = hr ? hr + plural(hr, ' hour', ' hours') + ', ' : '';
1000 var minutes = min ? min + plural(min, ' minute', ' minutes') + ', ' : '';
1001 var seconds = sec ? sec + plural(sec, ' second ago.', ' seconds ago.') : '';
1002 var msg = (n + ': I last saw ' + t + ' ' + days + hours + minutes + seconds).replace(/, (?!\d)/, '').replace(/, (?!.*, )/, ', and ');
1003 msg = / ago\.$/.test(msg) ? msg : msg.replace(/$/, ' ago.');
1004 send(msg);
1005 } else {
1006 var objKeys = Object.keys(Droid.seen);
1007 var levDistValues = {};
1008 for (var key in objKeys) {
1009 var similarity = levDist(t, objKeys[key]);
1010 levDistValues[objKeys[key]] = similarity;
1011 }
1012 var similarities = [];
1013 for (var name in levDistValues) similarities.push([name, levDistValues[name]]);
1014 similarities.sort(function(a, b) {
1015 return a[1] - b[1];
1016 });
1017 if (similarities[0][0].toLowerCase() == t.toLowerCase()) {
1018 Droid.cmds.seen(n, similarities[0][0], c);
1019 return;
1020 } else if (similarities[0][1] <= 6) {
1021 send('I have not seen ' + t + '. Did you mean ' + similarities[0][0] + '?');
1022 } else {
1023 send('I have not seen ' + t + '. Sorry.');
1024 }
1025 }
1026 },
1027 cleartell: function(n, t, c) {
1028 t = t.trim();
1029 t = t.charAt(0).toUpperCase() + t.slice(1);
1030 if (!t) {
1031 send('Usage: !cleartell USER NAME');
1032 return;
1033 }
1034 if (localStorage.getItem('tell ' + t)) {
1035 if (n != localStorage.getItem('tell ' + t).split(' wanted ')[0].split(/Ah! .*! /i)[1] && !mainRoom.model.users.findByName(n).attributes.isModerator) {
1036 send("You cannot clear that message, because you are not the author and you do not have moderator permissions.");
1037 return;
1038 }
1039 localStorage.removeItem('tell ' + t);
1040 send('Messages for ' + t + ' have been cleared!');
1041 } else {
1042 send(t + ' has no messages pending!');
1043 }
1044 },
1045 miss: function(n, t, c) {
1046 t = t.trim();
1047 t = t.charAt(0).toUpperCase() + t.slice(1);
1048 if (!t) {
1049 send('Usage: !miss USER NAME');
1050 return;
1051 }
1052 if (t == n) {
1053 send('how dang egoistic are you?');
1054 return;
1055 }
1056 if (t == mw.config.get('wgUserName')) {
1057 send('Aww thank you ;^>');
1058 return;
1059 }
1060 if (mainRoom.model.users.findByName(t)) {
1061 send('I\'m sure they miss you back.');
1062 return;
1063 }
1064 if (!localStorage.getItem('miss ' + t)) {
1065 localStorage.setItem('miss ' + t, n);
1066 send('Okay! I will tell ' + t + ' that you missed them next time we meet.');
1067 } else {
1068 var ls = localStorage.getItem('miss ' + t);
1069 var us = ls.split(', ');
1070 localStorage.setItem('miss ' + t, ls + ', ' + n);
1071 send('Okay! I will message ' + t + ' that you missed them, including the first ' + us.length + '. (Please tell Doru to create a central database.)');
1072 }
1073 },
1074 warn: function(n, t, c) {
1075 localStorage.setItem('warn ' + localStorage.getItem('lastKick'), localStorage.getItem('lastKick') + ': ' + t);
1076 send('Sure thing.');
1077 },
1078 reverse: function(n, t, c){
1079 t = t ? t : n;
1080 send(t.reverse());
1081 },
1082 learn: function(n, t, c) {
1083 send('When will you learn that your actions have consequences?!');
1084 },
1085 party: function(n, t, c) {
1086 send('You say a party? C\'mon let\'s party!');
1087 },
1088 smashorpass: function (n, t, c){
1089 d = ['I choose smash!', 'I choose pass!'];
1090 send(d[Math.floor(Math.random() * d.length)]);
1091 },
1092 pearlbomb: function(n, t, c) {
1093 t = t ? isNaN(Number(t)) ? 4 : Number(t) : 4
1094 if (!Number(t)) t = 50;
1095 t = Number(t) > 50 ? 50 : Number(t);
1096 var arr = shuffle(["http://i.imgur.com/meBGZf8g.png","http://i.imgur.com/VOZszxCg.jpg","http://i.imgur.com/E9AxOv0g.jpg","http://i.imgur.com/92W99TCg.png","http://i.imgur.com/LedX6CZg.jpg","http://i.imgur.com/i4vbWrU.png","http://i.imgur.com/iDa8Jec.png","http://i.imgur.com/i71WRULg.jpg","http://i.imgur.com/BnBEFrn.jpg","http://i.imgur.com/enJU9jGg.png","http://i.imgur.com/jG4JNit.png","http://i.imgur.com/gc7fV0x.png","http://i.imgur.com/tspqXL8g.png","http://i.imgur.com/tfQXhr9.jpg","http://i.imgur.com/XXsaEgDg.png","http://i.imgur.com/s3f7pMXg.jpg","http://i.imgur.com/oc2Yc0Sg.jpg","http://i.imgur.com/jjQJApyg.png","http://i.imgur.com/DaWptKp.png","http://i.imgur.com/UoOCYTTg.png","http://i.imgur.com/UvVG6Fu.png","http://i.imgur.com/csVxb8vg.png","http://i.imgur.com/lw6ZEopg.png","http://i.imgur.com/L5hYrbGg.png","http://i.imgur.com/Itx77AQg.jpg","http://i.imgur.com/VOMLsDAg.png","http://i.imgur.com/9TQxXZlg.png","http://i.imgur.com/J99xQvzg.jpg","http://i.imgur.com/Y75Ts2Zg.jpg","http://i.imgur.com/Yu2Tztmg.gif","http://i.imgur.com/Unurs4Fg.png","http://i.imgur.com/DHD1tCng.jpg","http://i.imgur.com/xPbzk2H.png","http://i.imgur.com/jmpzlePg.jpg","http://i.imgur.com/pE1NXBUg.jpg","http://i.imgur.com/le4O9cng.jpg","http://i.imgur.com/a4aLhBd.png","http://i.imgur.com/aKcC9xtg.png","http://i.imgur.com/CHfqikp.png","http://i.imgur.com/GsrrK5B.png","http://i.imgur.com/uBs2pPpg.jpg","http://i.imgur.com/r7SMuZrg.png","http://i.imgur.com/qTPPyGcg.png","http://i.imgur.com/SK4CxVfg.png","http://i.imgur.com/CVuvwut.png","http://i.imgur.com/6KE7tpT.png","http://i.imgur.com/Lat524ng.png","http://i.imgur.com/ryCAlN1g.png","http://i.imgur.com/eKQMGlLg.png","http://i.imgur.com/2oe6x39g.jpg","http://i.imgur.com/ZDXmp4Xg.png","http://i.imgur.com/T5vYInC.png","http://i.imgur.com/7hqACjK.png","http://i.imgur.com/zK3JG16.png","http://i.imgur.com/YL8n0Zz.png","http://i.imgur.com/Ik9G3bb.png","http://i.imgur.com/F5KGIYS.jpg","http://i.imgur.com/dVABtvAg.jpg","http://i.imgur.com/O0jROqH.png","http://i.imgur.com/CeqVI7C.png","http://i.imgur.com/8DTagDX.png","http://i.imgur.com/I1aPA6R.jpg","http://i.imgur.com/m266Pbpg.jpg","http://i.imgur.com/WLtoiTr.jpg","http://i.imgur.com/b2mK0S3g.jpg","http://i.imgur.com/KcSP2vPg.png","http://i.imgur.com/60ClMA7.png","http://i.imgur.com/RfGlr18.jpg","http://i.imgur.com/9JLonH1.jpg","http://i.imgur.com/37T6sHbg.png","http://i.imgur.com/PupunII.jpg","http://i.imgur.com/sJ8havf.png","http://i.imgur.com/YrhRpCI.jpg","http://i.imgur.com/F7kvLWKg.png","http://i.imgur.com/tjcJzMbg.png","http://i.imgur.com/bRWFby2g.jpg","http://i.imgur.com/Td6ijOZg.jpg","http://i.imgur.com/ZqczcGVg.jpg","http://i.imgur.com/kUo6o5V.gif","http://i.imgur.com/ZlWv4j2g.jpg","http://i.imgur.com/kteL83F.gif","http://i.imgur.com/SOze7If.gif","http://i.imgur.com/IM2bkKW.jpg","http://i.imgur.com/XQ1G0JTg.jpg","http://i.imgur.com/mg3cm3Wg.png","http://i.imgur.com/H1K7lkzg.jpg","http://i.imgur.com/iss3t8U.png","http://i.imgur.com/sq7bVftg.png","http://i.imgur.com/d6yJN2z.jpg","http://i.imgur.com/Cgl9Aet.jpg","http://i.imgur.com/aV0z9mCg.jpg","http://i.imgur.com/2MgNxrTg.jpg","http://i.imgur.com/cpdo5OSg.jpg","http://i.imgur.com/Ae5Jtbj.jpg","http://i.imgur.com/dIetLoXg.jpg","http://i.imgur.com/I6CrkdZg.jpg"]).slice(0, t);
1097 mainRoom.openPrivateChat(Array(n));
1098 mainRoom.model.privateUsers.bind('add', function(u) {
1099 setTimeout(function() {
1100 var sendPM = function(txt) {
1101 mainRoom.chats.privates[u.attributes.roomId].socket.send(new models.ChatEntry({
1102 roomId: this.roomId,
1103 name: mw.config.get('wgUserName'),
1104 text: txt
1105 }).xport());
1106 };
1107 /*sendPM*/ send('PearlBomb!');
1108 arr.forEach(function(img) {
1109 /*sendPM*/ send(img);
1110 });
1111 setTimeout(function() {
1112 delete mainRoom.chats.privates[u.attributes.roomId];
1113 document.getElementById('priv-user-' + n).outerHTML = '';
1114 document.getElementById('Chat_' + u.attributes.roomId).outerHTML = '';
1115 mainRoom.chats.privates[u.attributes.roomId].socket.socket.disconnect();
1116 for (var i in mainRoom.model.privateUsers.models) {
1117 if (mainRoom.model.privateUsers.models[i].attributes.name == n) mainRoom.model.privateUsers.models.splice(i, 1);
1118 }
1119 mainRoom.chats.main.setActive(true);
1120 }, 6000);
1121 mainRoom.model.privateUsers._callbacks.add = Array(mainRoom.model.privateUsers._callbacks.add[0]);
1122 }, 5000);
1123 });
1124 }
1125};
1126// Service commands.
1127Droid.srvcCmds = {
1128 restart: function(n, t, c) {
1129 restart = true;
1130 send("Logging...");
1131 submitLogs();
1132 },
1133 leave: function(n, t, c) {
1134 leave = true;
1135 submitLogs();
1136 send('I\'m so sorry...');
1137 },
1138 eval: function(n, t, c) {
1139 if(!t) return;
1140 try {
1141 eval(t);
1142 } catch(e) {
1143 send('[c="red"][b][big]' + e + '[/big][/b][/c]');
1144 }
1145 },
1146 test: function(n, t, c){
1147 try {
1148 send(eval(t));
1149 } catch (e) {
1150 send("Oops, your code has returned an error: " + e);
1151 }
1152 }
1153};
1154// Send function
1155var send = function(m) {
1156 mainRoom.socket.send(new models.ChatEntry({
1157 roomId: this.roomId,
1158 name: mw.config.get('wgUserName'),
1159 text: String(m)
1160 }).xport());
1161};
1162// Function that will run after each message is sent
1163BotCheck = function(chat) {
1164 /* Logging */
1165 // return if it was found before the bot entered, or if it its placed before the last mesage on !restart
1166 if ((chat.attributes.isInlineAlert || mainRoom.model.chats._byId[Number(localStorage.getItem('lastMsg'))]) && !wasFound) {
1167 wasFound = true;
1168 // Confirm the bot is up and runnning
1169 index = null;
1170 $.each(mainRoom.model.chats.models, function(i, model) {
1171 if (model.attributes.text == (mw.config.get('wgUserName') + ' ' + version + ' is online!'))
1172 index = true;
1173 });
1174 if (!index) {
1175 send(mw.config.get('wgUserName') + ' ' + version + ' is online!');
1176 setTimeout(function(){
1177 if (Droid.bannedsites.indexOf(window.location.origin.replace(window.location.protocol, '')) != -1) {
1178 Droid.reasons.map(function(r){
1179 if (window.location.origin.replace(window.location.protocol, '') == r.site){
1180 send("Use of Droid v2.0 has been denied on this site. Reason provided: " + r.reason + ".");
1181 }
1182 });
1183 }
1184 }, 3000);
1185 }
1186 return;
1187 }
1188 if (localStorage.getItem('Droid-operator'))
1189 Droid.operator = localStorage.getItem('Droid-operator');
1190 if (mainRoom.viewDiscussion.chatUL[0].childElementCount > 100) mainRoom.viewDiscussion.chatUL[0].children[0].outerHTML = '';
1191 // get variables
1192 var t = chat.attributes.text,
1193 te = mw.html.escape(t);
1194 var n = chat.attributes.name,
1195 ne = mw.html.escape(n);
1196 var isInlineAlert = chat.attributes.isInlineAlert == null ? false : true;
1197 var ns = n + 'Swr';
1198 cid = chat.cid;
1199 var msgType;
1200 // RegEx filtering
1201 if (/(mess|messenger|innocent|orange).*?(little|kitty|cat)|(mess|messenger).*?(is|was).*?(kitty|cat|orange.*?(kitty|cat))|sit down.*?(humble|be|bitch)|bitch.*?(be humble|sit down)|crime allowances/g.test(t.toLowerCase()) && localStorage.getItem('disabled') === 'enabled') {
1202 if (n === mw.config.get('wgUserName')) return;
1203 if (!Droid.triggered[n]){
1204 Droid.triggered[n] = 0;
1205 }
1206 if (Droid.triggered[n] < 3){
1207 Droid.triggered[n] ++;
1208 send("Kicking " + n + "...");
1209 Droid.kick(n);
1210 setTimeout(function(){
1211 localStorage.setItem("tell " + n, n + ", please don't say that again.");
1212 }, 3000);
1213 } else {
1214 Droid.triggered[n] = 0;
1215 send("Banning " + n + "...");
1216 Droid.ban(n, "1 day", "Automatically banned for matching forbidden phrases.");
1217 setTimeout(function(){
1218 localStorage.setItem("tell " + n, n + ", you were banned for matching a forbidden phrase. Please don't say it again.");
1219 }, 3000);
1220 }
1221 }
1222 if (t == 'Sophiedp killed chat! Lynch them!') {
1223 window.hasFailed = false;
1224 }
1225 // submit at the end of the day
1226 if (new Date().getUTCDate() != curDay) {
1227 curDay = new Date().getUTCDate();
1228 submitLogs(date.getUTCDate() + '_' + wgMonthNamesShort[date.getUTCMonth() + 1] + '_' + date.getUTCFullYear());
1229 }
1230 if (Droid.ponged && chat.attributes.text == 'Pong!' && chat.attributes.name == wgUserName) {
1231 delete Droid.ponged;
1232 var findMessage = function(regex) {
1233 var found = false;
1234 return mainRoom.model.chats.models.slice(0).reverse().filter(function(el) {
1235 if (found)
1236 return false;
1237 if (regex.test(el.attributes.text)) {
1238 found = true;
1239 return true;
1240 }
1241 })[0];
1242 },
1243 pad = function(str) {
1244 return ('0000' + str).replace(/...$/, '.$&').slice(-4);
1245 },
1246 pingMessage = findMessage(/[!\\\/@\$]ping/i),
1247 pongMessage = findMessage(/^Pong!$/),
1248 msDiff = String(pongMessage.attributes.timeStamp - pingMessage.attributes.timeStamp);
1249 send(pad(msDiff));
1250 }
1251 date = new Date();
1252 // get message type
1253 if (isInlineAlert) {
1254 if (new RegExp(joinmsg, 'mi').test(t)) {
1255 msgType = ' [JOIN] ';
1256 joincount++;
1257 } else if (new RegExp(quitmsg, 'mi').test(t)) {
1258 msgType = ' [QUIT] ';
1259 updateSeen(t.match(/\[\[Special:Contributions\/(.*?)\|.*?\]\]|\[\[Special:Contributions\/(.*?)\|.*?\]\]/)[1], $.now());
1260 quitcount++;
1261 } else if (new RegExp(undomsg, 'mi').test(t)) {
1262 msgType = ' [UNDO] ';
1263 } else if (new RegExp(kickmsg, 'mi').test(t)) {
1264 msgType = ' [KICK] ';
1265 localStorage.setItem('lastKick', t.trim().replace(/\[\[Special:Contributions\/.*?\||\]\] has been kicked by \[\[Special:Contributions\/.*\|.*\]\]/g, ''));
1266 updateSeen(t.match(/\[\[Special:Contributions\/(.*?)\|.*?\]\] has been kicked by/)[1], $.now());
1267 kickcount++;
1268 } else if (new RegExp(cbanmsg, 'mi').test(t)) {
1269 msgType = ' [CBAN] ';
1270 updateSeen(name, $.now());
1271 te = te.replace(/\(<a href="#" data-type="ban-undo" data-user=".+"\s*>undo<\/a>\)/, '');
1272 cbancount++;
1273 Api.get({
1274 action: 'query',
1275 list: 'logevents',
1276 lelimit: 1,
1277 letype: 'chatban',
1278 lepage: 'User:' + name,
1279 cb: $.now()
1280 }, function(d) {
1281 var chatBan = d.query.logevents[0];
1282 var reason = chatBan.comment;
1283 var expiry = Droid.parseTime(chatBan[4]);
1284 var user = chatBan.title.slice(5);
1285 var mod = chatBan.user;
1286 var msg = '[[User:' + user + '|' + user + ']] has been banned by [[User:' + mod + '|' + mod + ']] for ' + expiry + ': ' + reason + ' ([[Special:Block/' + user + '|Block ' + user + ']]).';
1287 if (user == Droid.operator) {
1288 mainRoom.socket.send(new models.BanCommand({
1289 userToBan: mod,
1290 time: 86400,
1291 reason: 'Banning ' + Droid.operator + '.'
1292 }).xport())
1293 }
1294 send(msg.replace(/\s0?\.?0 (?:hours|minutes?|seconds?)/g, ''));
1295 });
1296 } else {
1297 return;
1298 }
1299 te = te.replace(/^\(.*?\)|\(.*?\)$|\[\[User:.+?\||\[\[Special:Contributions\/.+?\||\]\]/g, '').trim();
1300 } else if (n === mw.config.get('wgUserName')) {
1301 msgType = ' [CBOT] ';
1302 } else {
1303 msgType = ' [CHAT] ';
1304 chatcount++;
1305 }
1306 te = te.trim();
1307 // get message time
1308 var msgDate = new Date();
1309 var msgTimestamp = (msgDate.getUTCHours() < 10 ? '0' : '') + msgDate.getUTCHours() + ':' + (msgDate.getUTCMinutes() < 10 ? '0' : '') + msgDate.getUTCMinutes() + ':' + (msgDate.getUTCSeconds() < 10 ? '0' : '') + msgDate.getUTCSeconds();
1310 // adds the values to the actual log
1311 if (msgType == ' [CHAT] ' || msgType == ' [CBOT] ') {
1312 te = te.replace(/\n/g, '\n ' + msgType);
1313 logText = logText.replace('</pre>', '[' + msgTimestamp + ']' + msgType + ne + ': ' + te + '\n</pre>');
1314 } else {
1315 logText = logText.replace('</pre>', '[' + msgTimestamp + ']' + msgType + te + '\n</pre>');
1316 }
1317 /* Swear/Rule-break checking */
1318 if (chat.attributes.name !== mw.config.get('wgUserName')) {
1319 if (localStorage.getItem('disabled') !== 'disabled' && !isInlineAlert) {
1320 // spamming
1321 Droid.spam(n);
1322 // kick for swears
1323 if (new RegExp(SLURS.join('|'), "mi").test(t) === true) {
1324 send(n + ', please don\'t use that language.');
1325 mainRoom.socket.send(new models.BanCommand({
1326 userToBan: n,
1327 time: 86400,
1328 reason: 'Slur'
1329 }).xport());
1330 }
1331 // ban for slurs
1332 else if (new RegExp(SWEARS.join('|'), "mi").test(t) === true) {
1333 send(n + ', please don\'t swear!');
1334 Droid.kick(n);
1335 } else if (t.match(/\n/) !== null) {
1336 if (t.match(/\n/g).length > 10) {
1337 send(n + ', please don\'t flood!');
1338 Droid.kick(n);
1339 }
1340 }
1341 }
1342 // Check everyone
1343 if (localStorage.getItem('note ' + n)) {
1344 send(localStorage.getItem('note ' + n));
1345 localStorage.removeItem('note ' + n);
1346 }
1347 if (localStorage.getItem('tell ' + n)) {
1348 send(localStorage.getItem('tell ' + n));
1349 localStorage.removeItem('tell ' + n);
1350 }
1351 if (localStorage.getItem('miss ' + n)) {
1352 send('Ah! ' + n + '! ' + localStorage.getItem('miss ' + n) + ' missed you!');
1353 localStorage.removeItem('miss ' + n);
1354 }
1355 /* Commands*/
1356 if (mainRoom.model.users.findByName(n) == null || Droid.bannedsites.indexOf(window.location.origin.replace(window.location.protocol, '')) != -1) return; // return if is inline-alert or if it is a site I have denied access to use the bot
1357 var cmd = t.slice(1).split(' ')[0];
1358 var ttext = t.split(' ').slice(1).join(' ');
1359 if ('+#'.split('').indexOf(t.charAt(0)) !== -1 && Droid.modCmds.hasOwnProperty(cmd) && mainRoom.model.users.findByName(n).attributes.isModerator) {
1360 commandlogText = commandlogText.replace('</pre>', '\n[MODERATOR COMMAND] Name: ' + cmd + '. User: ' + ne + '. Text: ' + (ttext || 'No text') + '\n</pre>');
1361 mcmcount++;
1362 if (typeof Droid.modCmds[cmd] === "function"){
1363 Droid.modCmds[cmd](n, ttext);
1364 }
1365 else if (typeof Droid.modCmds[cmd] === "string") {
1366 cmd = Droid.modCmds[cmd];
1367 Droid.modCmds[cmd](n, ttext);
1368 }
1369 }
1370 if ('!\\/$@'.split('').indexOf(t.charAt(0)) !== -1 && Droid.cmds.hasOwnProperty(cmd) && localStorage.getItem('OBenabled') == 'enabled') {
1371 if (localStorage.getItem('deny ' + n)) {
1372 send('(stop)[big][c="red"][b]Access denied![/b][/c][/big]');
1373 send(n + ', you cannot use my commands because you have been banned from using them. Reason given: ' + localStorage.getItem('deny ' + n) + '. Please contact a moderator to appeal this ban.');
1374 return;
1375 }
1376 commandlogText = commandlogText.replace('</pre>', '\n[NORMAL COMMAND] Name: ' + cmd + '. User: ' + ne + '. Text: ' + (ttext || 'No text.') + '\n</pre>');
1377 cmdcount++;
1378 if (typeof Droid.cmds[cmd] === "function"){
1379 Droid.cmds[cmd](n, ttext);
1380 }
1381 else if (typeof Droid.cmds[cmd] === "string") {
1382 cmd = Droid.cmds[cmd];
1383 Droid.cmds[cmd](n, ttext);
1384 }
1385 }
1386 if ('=%^'.split('').indexOf(t.charAt(0)) !== -1 && ['C.Syde65', 'Mario&LuigiBowser\'sInsideStory'].indexOf(n) !== -1 && Droid.srvcCmds.hasOwnProperty(cmd)) {
1387 Droid.srvcCmds[cmd](n, ttext);
1388 }
1389 }
1390};
1391// Inline-alert checking
1392mainRoom.model.users.bind('add', function(add) {
1393 var n = add.attributes.name;
1394 if (n == mw.config.get('wgUserName')) return;
1395 if (add.attributes.editCount == '0' && add.attributes.avatarSrc == "http://vignette4.wikia.nocookie.net/messaging/images/1/19/Avatar.jpg/revision/latest/scale-to-width-down/28?format=jpg") {
1396 mainRoom.socket.send(new models.BanCommand({
1397 userToBan: n,
1398 time: 31536000000,
1399 reason: 'Sockpuppetry'
1400 }).xport());
1401 }
1402 // Aidan pattern v0.1642481295
1403 if (/^Steven.*?(likes|loves|hates|does|kill|writes).*?07\d{3,}/i.test(n) || /^Steven(cung)?.*?07\d{4}/.test(n)) {
1404 mainRoom.socket.send(new models.BanCommand({
1405 userToBan: n,
1406 time: 31536000000,
1407 reason: 'Sockpuppetry'
1408 }).xport());
1409 }
1410 if (localStorage.getItem('note ' + n)) {
1411 send(localStorage.getItem('note ' + n));
1412 localStorage.removeItem('note ' + n);
1413 }
1414 if (localStorage.getItem('warn ' + n)) {
1415 send(localStorage.getItem('warn ' + n));
1416 localStorage.removeItem('warn ' + n);
1417 }
1418 if (localStorage.getItem('tell ' + n)) {
1419 send(localStorage.getItem('tell ' + n));
1420 localStorage.removeItem('tell ' + n);
1421 }
1422 if (localStorage.getItem('miss ' + n)) {
1423 send('Ah! ' + n + '! ' + localStorage.getItem('miss ' + n).replace(/, (?!.*, )/, ' and ') + ' missed you!');
1424 localStorage.removeItem('miss ' + n);
1425 }
1426 /*if (n == 'Robyn Grayson' && !Droid.hasWarnedImages) {
1427 $.get('/wiki/User:Robyn Grayson/DPL?action=render', function(page) {
1428 var dplEntries = $(page).find('.forum_title').reverse();
1429 if (dplEntries.length) {
1430 dplEntries.each(function() {
1431 if (Droid.hasWarnedImages) return;
1432 Api.get({
1433 action: 'query',
1434 prop: 'revisions',
1435 rvprop: 'timestamp',
1436 titles: $(this).text()
1437 }, function(d) {
1438 if (d.error || Droid.hasWarnedImages) return;
1439 if (Math.round(($.now() - new Date(d.query.pages[Object.keys(d.query.pages)[0]].revisions[0].timestamp).getTime()) / 1000) > 3600) {
1440 send('Robyn: [[User:Robyn Grayson/DPL|do the dang files]]');
1441 Droid.hasWarnedImages = true;
1442 setTimeout(function() {
1443 Droid.hasWarnedImages = false;
1444 }, 7200000);
1445 } else {
1446 Droid.hasWarnedImages = true;
1447 setTimeout(function() {
1448 Droid.hasWarnedImages = false;
1449 }, 300000);
1450 }
1451 });
1452 });
1453 }
1454 });
1455 }*/
1456});
1457
1458// quits
1459mainRoom.model.users.bind('remove', function(remove) {
1460 var n = remove.attributes.name;
1461 if (remove.attributes.isModerator) {
1462 localStorage.setItem('last-online-mod', n);
1463 }
1464 if (n == mw.config.get('wgUserName')) return;
1465 updateSeen(n, (new Date()).getTime());
1466});
1467// Function to submit the logs (uploadText) and then clears them
1468/*submitHogs = function(logDate) {
1469 if (wgPageName != 'Special:Chat') return;
1470 if (isLogging) {
1471 isLogging = false;
1472 return;
1473 }
1474 isLogging = true;
1475 var d = new Date(),
1476 ttl = logDate || d.getUTCDate() + '_' + wgMonthNamesShort[d.getUTCMonth() + 1] + '_' + d.getUTCFullYear(),
1477 uploadText = logText;
1478 logText = '</pre>';
1479 localStorage.setItem('lastMsg', mainRoom.model.chats.models[Object.keys(mainRoom.model.chats.models).length - 1].attributes.id);
1480 Api.get({
1481 'action': 'query',
1482 'prop': 'info|revisions',
1483 'intoken': 'edit',
1484 'titles': 'Project:Chat/Logs/' + ttl,
1485 'rvprop': 'content|timestamp|ids',
1486 'rvlimit': '1',
1487 'indexpageids': 'true',
1488 'cb': Date.now()
1489 }, function(response) {
1490 var page = response.query.pages[Object.keys(response.query.pages)[0]];
1491 var pageExists = response.query.pages["-1"] ? false : true;
1492 var pageContent = typeof(page.revisions) != "undefined" ? page.revisions[0]['*'] : '';
1493 var newPageContent = pageExists ? pageContent.replace('</pre>', uploadText) : '<pre class="ChatLog">\n' + uploadText + '\n[[Category:Wikia Chat logs|2016 04 23]]';
1494 if (newPageContent.indexOf('</pre>') == -1) {
1495 logText = uploadText.slice(0, -6) + logText;
1496 send('An error occurred. Reverting logs to a non-broken state...');
1497 Api.post({
1498 minor: 'yes',
1499 bot: 'yes',
1500 action: 'edit',
1501 title: 'Project:Chat/Logs/' + ttl,
1502 undo: page.revisions[0].revid,
1503 summary: 'Reverting chat logs to a non-broken state.',
1504 token: mw.user.tokens.get('editToken')
1505 }, function(r) {
1506 Droid.errors.push(r);
1507 });
1508 return;
1509 }
1510 if (pageContent.length > newPageContent.length) {
1511 send('[b][c="red"]Error while logging: ' + window.hasFailed ? 'Aborting...' : 'Retrying...');
1512 if (window.hasFailed) {
1513 restart = true;
1514 window.location.reload();
1515 return;
1516 }
1517 isLogging = false;
1518 window.hasFailed = true;
1519 submitLogs();
1520 return;
1521 }
1522 if (newPageContent == pageContent) {
1523 //send('Sophiedp killed chat! Lynch them!');
1524 isLogging = false;
1525 if (window.hasFailed) {
1526 restart = true;
1527 window.location.reload();
1528 return;
1529 }
1530 window.hasFailed = true;
1531 return;
1532 }
1533 Api.post({
1534 'minor': 'yes',
1535 'bot': 'yes',
1536 'summary': plural(Number(pageExists), 'Adding to', 'Creating') + ' chatlog: ' + kickcount + ' kicks and ' + cbancount + ' bans reported. ' + joincount + ' joins, ' + quitcount + ' leaves, and ' + chatcount + ' messages logged.',
1537 'action': 'edit',
1538 'title': 'Project:Chat/Logs/' + ttl,
1539 'starttimestamp': page.starttimestamp,
1540 'token': page.edittoken,
1541 'text': newPageContent
1542 }, function(response) {
1543 console.log(plural(Number(pageExists), 'Adding to', 'Creating') + ' chatlog: ' + kickcount + ' kicks and ' + cbancount + ' bans reported. ' + joincount + ' joins, ' + quitcount + ' leaves, and ' + chatcount + ' messages logged.');
1544 isLogging = false;
1545 if (postLog) {
1546 send(plural(Number(pageExists), 'Adding to', 'Creating') + ' [[Project:Chat/Logs/' + ttl + '|chatlog]] ' + kickcount + ' kicks and ' + cbancount + ' bans reported. ' + joincount + ' joins, ' + quitcount + ' leaves, and ' + chatcount + ' messages logged.');
1547 postLog = false;
1548 }
1549 if (restart || leave) {
1550 submitSeen();
1551 }
1552 kickcount = 0, cbancount = 0, quitcount = 0, joincount = 0, chatcount = 0;
1553 mainRoom.viewDiscussion.chatUL.append('<li class="inline-alert">Chat Logged.</li>');
1554 mainRoom.viewDiscussion.scrollToBottom();
1555 if (mainRoom.viewDiscussion.chatUL[0].childElementCount > 100) {
1556 mainRoom.viewDiscussion.chatUL[0].children[0].outerHTML = '';
1557 }
1558 });
1559 });
1560};*/
1561// Logs
1562var submitLogs = function(logDate) {
1563 if (window.noLogs) return;
1564 if (wgPageName != 'Special:Chat') return;
1565 if (isLogging) {
1566 isLogging = false;
1567 return;
1568 }
1569 isLogging = true;
1570 var d = new Date(),
1571 ttl = logDate || d.getUTCDate() + '_' + wgMonthNamesShort[d.getUTCMonth() + 1] + '_' + d.getUTCFullYear(),
1572 uploadText = logText;
1573 logText = '</pre>';
1574 localStorage.setItem('lastMsg', mainRoom.model.chats.models[Object.keys(mainRoom.model.chats.models).length - 1].attributes.id);
1575 Api.get({
1576 'action': 'query',
1577 'prop': 'info|revisions',
1578 'intoken': 'edit',
1579 'titles': 'Project:Chat/Logs/' + ttl,
1580 'rvprop': 'content|timestamp|ids',
1581 'rvlimit': '1',
1582 'indexpageids': 'true',
1583 'cb': Date.now()
1584 }, function(response) {
1585 var page = response.query.pages[Object.keys(response.query.pages)[0]];
1586 var pageExists = response.query.pages["-1"] ? false : true;
1587 var pageContent = typeof(page.revisions) != "undefined" ? page.revisions[0]['*'] : '';
1588 var newPageContent = pageExists ? pageContent.replace('</pre>', uploadText) : '<pre class="ChatLog">\n' + uploadText + '\n[[Category:Wikia Chat logs|2016 04 23]]';
1589 if (newPageContent.indexOf('</pre>') == -1) {
1590 logText = uploadText.slice(0, -6) + logText;
1591 send('An error occurred. Reverting logs to a non-broken state...');
1592 Api.post({
1593 minor: 'yes',
1594 bot: 'yes',
1595 action: 'edit',
1596 title: 'Project:Chat/Logs/' + ttl,
1597 undo: page.revisions[0].revid,
1598 summary: 'Reverting chat logs to a non-broken state.',
1599 token: mw.user.tokens.get('editToken')
1600 }, function(r) {
1601 Droid.errors.push(r);
1602 });
1603 return;
1604 }
1605 if (pageContent.length > newPageContent.length) {
1606 send('[b][c="red"]Error while logging: ' + window.hasFailed ? 'Aborting...' : 'Retrying...');
1607 if (window.hasFailed) {
1608 restart = true;
1609 window.location.reload();
1610 return;
1611 }
1612 isLogging = false;
1613 window.hasFailed = true;
1614 submitLogs();
1615 return;
1616 }
1617 if (newPageContent == pageContent) {
1618 //send('Sophiedp killed chat! Lynch them!');
1619 isLogging = false;
1620 if (window.hasFailed) {
1621 restart = true;
1622 window.location.reload();
1623 return;
1624 }
1625 window.hasFailed = true;
1626 return;
1627 }
1628 Api.post({
1629 'minor': 'yes',
1630 'bot': 'yes',
1631 'summary': plural(Number(pageExists), 'Adding to', 'Creating') + ' chatlog: ' + kickcount + ' kicks and ' + cbancount + ' bans reported. ' + joincount + ' joins, ' + quitcount + ' leaves, and ' + chatcount + ' messages logged.',
1632 'action': 'edit',
1633 'title': 'Project:Chat/Logs/' + ttl,
1634 'starttimestamp': page.starttimestamp,
1635 'token': page.edittoken,
1636 'text': newPageContent
1637 }, function(response) {
1638 console.log(plural(Number(pageExists), 'Adding to', 'Creating') + ' chatlog: ' + kickcount + ' kicks and ' + cbancount + ' bans reported. ' + joincount + ' joins, ' + quitcount + ' leaves, and ' + chatcount + ' messages logged.');
1639 isLogging = false;
1640 if (postLog) {
1641 send(plural(Number(pageExists), 'Adding to', 'Creating') + ' [[Project:Chat/Logs/' + ttl + '|chatlog]] ' + kickcount + ' kicks and ' + cbancount + ' bans reported. ' + joincount + ' joins, ' + quitcount + ' leaves, and ' + chatcount + ' messages logged.');
1642 postLog = false;
1643 }
1644 if (restart || leave) {
1645 submitSeen();
1646 logCommands();
1647 }
1648 kickcount = 0, cbancount = 0, quitcount = 0, joincount = 0, chatcount = 0;
1649 mainRoom.viewDiscussion.chatUL.append('<li class="inline-alert">Chat Logged.</li>');
1650 mainRoom.viewDiscussion.scrollToBottom();
1651 if (mainRoom.viewDiscussion.chatUL[0].childElementCount > 100) {
1652 mainRoom.viewDiscussion.chatUL[0].children[0].outerHTML = '';
1653 }
1654 });
1655 });
1656};
1657// Get unified Seen timestamps
1658Api.get({
1659 action: 'query',
1660 titles: 'Project:Chat/Seen',
1661 prop: 'revisions',
1662 rvprop: 'content|size|ids',
1663 cb: $.now()
1664}, function(d) {
1665 if (!d.error) {
1666 var r = d.query.pages[Object.keys(d.query.pages)[0]].revisions,
1667 p = r.sort(function(a,b) {
1668 return b.size-a.size || b.revid - a.revid;
1669 })[0];
1670 Droid.seenPage = p['*'];
1671 var lines = /<pre>([\s\S]*)<\/pre>/img.exec(Droid.seenPage)[1].trim().split(/\n/g);
1672 Droid.seen = {};
1673 $.each(lines, function(index, val) {
1674 var splt = val.split('|');
1675 Droid.seen[splt[0]] = {
1676 timeStamp: splt[1],
1677 changed: false
1678 };
1679 });
1680 } else {
1681 mainRoom.viewDiscussion.chatUL.append('<li class="inline-alert">Failed while getting unified seen timestamps.</li>');
1682 }
1683});
1684// Seen unification
1685updateSeen = function(usr, time) {
1686 if (!Droid.seen) return;
1687 if (Droid.seen.hasOwnProperty(usr)) {
1688 Droid.seenPage = Droid.seenPage.replace(new RegExp('^' + RegExp.escape(usr) + '\\|.*', 'm'), usr + '|' + time);
1689 if (!Droid.seen[usr].changed) Droid.seenUpdCount++;
1690 } else {
1691 Droid.seenPage = Droid.seenPage.replace('</pre>', usr + '|' + time + '\n</pre>');
1692 Droid.seenCrtCount++;
1693 }
1694 Droid.seen[usr] = {
1695 timeStamp: time,
1696 changed: true
1697 };
1698};
1699
1700function logCommands(){
1701 var date = new Date(),
1702 ttl = date.getUTCDate() + '_' + wgMonthNamesShort[date.getUTCMonth() + 1] + '_' + date.getUTCFullYear(),
1703 uploadText = logText;
1704 Api.get({
1705 action: 'query',
1706 prop: 'revisions',
1707 rvprop: 'content|size|ids',
1708 intoken: 'edit',
1709 titles: 'Project:Chat/Command Logs/' + ttl,
1710 cb: $.now()
1711 }, function(d){
1712 var pageExists = d.query.pages["-1"] ? false : true;
1713 if (pageExists) {
1714 var content = d.query.pages[Object.keys(d.query.pages)[0]].revisions[0]['*'];
1715 Api.post({
1716 action: 'edit',
1717 title: 'Project:Chat/Command Logs/' + ttl,
1718 text: content.replace('</pre>', commandlogText),
1719 summary: "Adding to command logs: " + cmdcount + " normal" + plural(cmdcount, " command", " commands") + " used and " + mcmcount + plural(mcmcount, " mod command", " mod commands") + " used.",
1720 bot: true,
1721 minor: true,
1722 token: mw.user.tokens.get('editToken')
1723 }, function(e){
1724 if (!e.error) {
1725 console.log("Adding to command logs. " + cmdcount + " normal" + plural(cmdcount, " command", " commands") + " used and " + mcmcount + plural(mcmcount, " mod command", " mod commands") + " used.");
1726 cmdcount = 0;
1727 mcmcount = 0;
1728 }
1729 else {
1730 send("An error occurred while submitting commands to command log.");
1731 console.log(e.error.info);
1732 }
1733 });
1734 } else {
1735 Api.post({
1736 action: 'edit',
1737 title: 'Project:Chat/Command Logs/' + ttl,
1738 text: "<pre class=\"CommandLog\">" + commandlogText + "\n[[Category:Command Logs]]",
1739 summary: "Creating command logs: " + cmdcount + " normal" + plural(cmdcount, " command", " commands") + " used and " + mcmcount + plural(mcmcount, " mod command", " mod commands") + " used.",
1740 bot: true,
1741 minor: true,
1742 token: mw.user.tokens.get('editToken')
1743 }, function(e){
1744 if (!e.error) {
1745 console.log("Creating command logs: " + cmdcount + " normal" + plural(cmdcount, " command", " commands") + " used and " + mcmcount + plural(mcmcount, " mod command", " mod commands") + " used.");
1746 cmdcount = 0;
1747 mcmcount = 0;
1748 }
1749 else {
1750 send("An error occured while adding commands to command log.");
1751 console.log(e.error.info);
1752 }
1753 });
1754 }
1755 });
1756}
1757setInterval(function(){
1758 logCommands();
1759}, 3600000);
1760// Updates the actual seen page
1761function submitSeen() {
1762 $.each(Droid.seen, function(key, value) {
1763 Droid.seen[key].changed = false;
1764 });
1765 Api.get({
1766 'action': 'query',
1767 'prop': 'info|revisions',
1768 'intoken': 'edit',
1769 'titles': 'Project:Chat/Seen',
1770 'rvprop': 'content',
1771 'rvlimit': '1',
1772 'indexpageids': 'true',
1773 'cb': $.now()
1774 }, function(d) {
1775 if (d.query.pages[Object.keys(d.query.pages)[0]].revisions[0]['*'].length > Droid.seenPage) return;
1776 Api.post({
1777 action: 'edit',
1778 title: 'Project:Chat/Seen',
1779 minor: 'yes',
1780 bot: 'yes',
1781 summary: 'Updating unified seen timestamps: ' + Droid.seenCrtCount + plural(Droid.seenCrtCount, ' line', ' lines') + ' added, and ' + Droid.seenUpdCount + plural(Droid.seenUpdCount, ' timestamp', ' timestamps') + ' updated.',
1782 token: mw.user.tokens.get('editToken'),
1783 text: Droid.seenPage
1784 }, function(p) {
1785 console.log('Updating unified seen timestamps: ' + Droid.seenCrtCount + ' lines added, and ' + Droid.seenUpdCount + ' timestamps updated.');
1786 Droid.seenCrtCount = 0;
1787 Droid.seenUpdCount = 0;
1788 if (restart) {
1789 send('Restarting...');
1790 window.location.reload();
1791 }
1792 if (leave) {
1793 send('I\'m so sorry...');
1794 window.open('/wiki/Special:WikiActivity', '_self');
1795 }
1796 });
1797 });
1798}
1799// Sets the interval for submitting the seen page
1800setInterval(function() {
1801 submitSeen();
1802}, 1800000);
1803// Sets the interval for submitting the logs
1804setInterval(function() {
1805 submitLogs();
1806}, window.logInterval || 600000);
1807// Appends the function to chat updates
1808if (mw.config.get('wgCanonicalSpecialPageName') == 'Chat') {
1809 mainRoom.model.chats.bind('afteradd', BotCheck);
1810}
1811// Submit commands from the bot window
1812$('textarea[name="message"]').keypress(function (e){
1813 if (e.which === 13) {
1814 if (!localStorage.getItem('Droid-operator')) {
1815 this.value = '';
1816 $.showCustomModal('Operator', 'You cannot send messages until you specify who you are. <br> <input cols="5" rows="3" id="operator-val" />', {
1817 id: 'checkOperator',
1818 width: 300,
1819 height: 180,
1820 buttons: [
1821 {
1822 id: 'Submit',
1823 defaultButton: true,
1824 message: 'Submit',
1825 handler: function (){
1826 var $op = $('#operator-val').val();
1827 if ($op === '') return;
1828 if (!mainRoom.model.users.findByName($op)) {
1829 $.showCustomModal('Error', '"' + $op + '" was not found on the chat. Check your spelling and make sure your operator account is on the chat.', {
1830 id: 'error-1',
1831 width: 330,
1832 height: 165,
1833 buttons: [
1834 {
1835 id: 'retry-1',
1836 message: 'Try again',
1837 handler: function () {
1838 $('#error-1').closeModal();
1839 },
1840 defaultButton: false
1841 }
1842 ]
1843 });
1844 return;
1845 }
1846 if ($op === mw.config.get('wgUserName')) {
1847 $.showCustomModal('Error', 'Made a mistake?', {
1848 id: 'mistake',
1849 width: 200,
1850 height: 140,
1851 buttons: [
1852 {
1853 id: 'retry-1',
1854 message: 'Try again',
1855 handler: function () {
1856 $('#mistake').closeModal();
1857 },
1858 defaultButton: false
1859 }
1860 ]
1861 });
1862 return;
1863 }
1864 if (!mainRoom.model.users.findByName($op).attributes.isModerator) {
1865 $.showCustomModal('Error', 'Operator must be a moderator.', {
1866 id: 'error-2',
1867 width: 270,
1868 height: 200,
1869 buttons: [
1870 {
1871 id: 'retry-2',
1872 message: 'Try again',
1873 handler: function () {
1874 $('#error-2').closeModal();
1875 },
1876 defaultButton: false
1877 }
1878 ]
1879 });
1880 return;
1881 }
1882 localStorage.setItem('Droid-operator', $op);
1883 $('#checkOperator').closeModal();
1884 $.showCustomModal('Success', 'Operator has successfully been specified!', {id: 'operatorSuccess'});
1885 setTimeout(function(){
1886 $('#operatorSuccess').closeModal();
1887 }, 1000);
1888 }
1889 },
1890 {
1891 id: 'cancel',
1892 defaultButton: false,
1893 message: 'Cancel',
1894 handler: function (){
1895 $('#checkOperator').closeModal();
1896 }
1897 }
1898 ]
1899 });
1900 return false;
1901 }
1902 var t = this.value,
1903 n = mw.config.get('wgUserName');
1904 var cmd = t.slice(1).split(' ')[0];
1905 var ttext = t.split(' ').slice(1).join(' ');
1906 // commands
1907 if (Droid.bannedsites.indexOf(window.location.origin.replace(window.location.protocol, '')) != -1) return;
1908 if ('!\\/@$'.split('').indexOf(t.charAt(0)) !== -1 && Droid.cmds.hasOwnProperty(cmd)){
1909 Droid.cmds[cmd](n, ttext);
1910 this.value = '';
1911 return false;
1912 }
1913 if ('+#'.split('').indexOf(t.charAt(0)) !== -1 && Droid.modCmds.hasOwnProperty(cmd)){
1914 Droid.modCmds[cmd](n, ttext);
1915 this.value = '';
1916 return false;
1917 }
1918 }
1919});
1920// Info button
1921$('.Rail .public').before($('<button class="chat-button info-button">Info</button>').click(function(){
1922 $.showCustomModal(mw.config.get('wgUserName') + ' ' + version, '-Swear checking: ' + localStorage.getItem('disabled') + '. <br/> -Commands: ' + localStorage.getItem('OBenabled') + '. <br/> -Known operator: ' + (localStorage.getItem('Droid-operator') || 'unspecified') + '. <br/> -Version release: September 3rd 2017.', {
1923 id: 'botInfo',
1924 width: 290,
1925 height: 210,
1926 buttons: [
1927 {
1928 id: 'Close',
1929 defaultButton: false,
1930 message: 'Close',
1931 handler: function (){
1932 $('#botInfo').closeModal();
1933 }
1934 }
1935 ]
1936 });
1937}));
1938// Automatically add to Project:Chat/Bot Commands
1939setTimeout(function (){
1940 var ncmds = [],
1941 mcmds = [];
1942 for (var nc in Droid.cmds){
1943 ncmds.push('*!' + nc);
1944 }
1945 for (var mc in Droid.modCmds){
1946 mcmds.push('*+' + mc);
1947 }
1948 Api.post({
1949 action: 'edit',
1950 title: 'Project:Chat/Bot Commands',
1951 text: 'These are bot commands for the chat bot.\n==Normal Commands==\n These commands can be used by all users. They can use one of the following command prefixes: <pre>! $ \\ / @</pre> The common prefix is ! so it will be used in the commands to show\n=== Commands themselves ===\n' + ncmds.join('\n') + '\n==Mod commands==\n These commands can only be used by chat moderators. They use one of the following command prefixes: <pre>+ #</pre> The common prefix is + so it will be used in the commands to show. \n===Commands themselves===\n' + mcmds.join('\n') + ' \n==Other Info==\nTo get help on how a certain command works, just use it. Some commands do not have to be used with a certain phrase.',
1952 summary: 'Updating the Bot Commands',
1953 bot: true,
1954 token: mw.user.tokens.get('editToken')
1955 }, function (d){
1956 if (!d.error){
1957 console.log('Commands are done adding to ' + window.location.origin + '/Project:Chat/Bot_Commands');
1958 } else {
1959 console.log('Error');
1960 }
1961 });
1962}, 15000);
1963//</syntaxhighlight>