· 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.news = "Emotebomb can now be logged on when and who set the last emotebomb off. To log the events of emotebomb, you can create the [[Project:Chat/Emotebomb]] page or edit my [[User:" + mw.config.get('wgUserName') + "/chat.js|chat.js]] and set a page you want emotebomb events to be logged. Example: [code] window.emotebombpage = \"PAGE\"; [/code].";
284Droid.modCmds = {
285 block: function (n, t, c) {
286 if (mw.config.get('wgUserGroups').indexOf('sysop') === -1) {
287 send('I do not have enough permissions to block that user');
288 return;
289 }
290 if (mainRoom.model.users.findByName(n).attributes.groups.indexOf('sysop') === -1){
291 send('This is an administrative action. You need to have admin rights to use it.');
292 return;
293 }
294 if (!t) {
295 send('Usage: +block USER for > REASON | EXPIRY | block ip | cannot post | override');
296 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.');
297 return;
298 }
299 t = t.split(' | ');
300 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')) {
301 send('You cannot block me.');
302 return;
303 }
304 if (t[0].split(' for > ')[1] && t[0].split(' for > ')[0] === n || !t[0].split(' for > ')[1] && t[0].split(' for > ')[0] === n) {
305 send('You cannot block yourself');
306 return;
307 }
308 var config = {
309 action: 'block',
310 user: t[0].split(' for > ')[0],
311 reason: t[0].split(' for > ')[1] || 'No reason was given.',
312 expiry: t[1],
313 bot: true,
314 token: mw.user.tokens.get('editToken')
315 };
316 if (t.indexOf('block ip') !== -1) config.autoblock = 1;
317 if (t.indexOf('cannot post') === -1) config.allowusertalk = 1;
318 if (t.indexOf('override') !== -1) config.reblock = 1;
319 if (mainRoom.model.users.findByName(t[0].split(' for > ')[0])) {
320 Droid.kick(t[0].split(' for > ')[0]);
321 }
322 Api.post(config, function (d) {
323 if (!d.error) {
324 send('[[Special:Contributions/' + t[0].split(' for > ')[0] + '|' + t[0].split(' for > ')[0] + ']] has been successfully blocked!');
325 }
326 else {
327 send('Something went wrong while blocking [[Special:Contributions/' + t[0].split(' for > ')[0] + '|' + t[0].split(' for > ')[0] + ']]: ' + d.error.info);
328 }
329 });
330
331 },
332 unblock: function (n, t, c){
333 if (mw.config.get('wgUserGroups').indexOf('sysop') === -1) {
334 send('I do not have enough permissions to unblock that user');
335 return;
336 }
337 if (!t) {
338 send('Usage: +unblock USER | REASON');
339 return;
340 }
341 t = t.split(' | ');
342 Api.post({
343 action: 'unblock',
344 reason: t[1] || 'No reason given',
345 user: t[0],
346 bot: true,
347 token: mw.user.tokens.get('editToken')
348 }, function (d){
349 if (!d.error) {
350 send('[[Special:Contributions/' + t[0] + '|' + t[0] + ']] has been unblocked successfully!');
351 }
352 else {
353 send('An error occurred while blocking [[Special:Contributions/' + t[0] + '|' + t[0] + ']]: ' + d.error.info);
354 }
355 });
356 },
357 on: function(n, t, c){
358 if (localStorage.getItem('OBenabled') === 'enabled') {
359 send('Already up and running!');
360 } else {
361 localStorage.setItem('OBenabled', 'enabled');
362 send('Booting up!');
363 }
364 },
365 off: function(n, t, c) {
366 if (localStorage.getItem('OBenabled') === 'disabled') {
367 send('...');
368 } else {
369 localStorage.setItem('OBenabled', 'disabled');
370 send('Shutting down...');
371 }
372 },
373 enable: function(n, t, c) {
374 if (localStorage.getItem('disabled') === 'enabled') {
375 send('Swear checking is already enabled!');
376 } else {
377 localStorage.setItem('disabled', 'enabled');
378 send('Enabling swear checking!');
379 }
380 },
381 disable: function(n, t, c) {
382 if (localStorage.getItem('disabled') === 'disabled') {
383 send('Swear checking is already disabled.');
384 } else {
385 localStorage.setItem('disabled', 'disabled');
386 send('Swear checking disabled.');
387 }
388 },
389 news: function(n, t, c){
390 send(Droid.news);
391 },
392 leave: function(n, t, c) {
393 leave = true;
394 submitLogs();
395 send('I\'m so sorry...');
396 window.open('/wiki/Special:WikiActivity', '_self');
397 },
398 runtime: function(n, t, c) {
399 var botEnd = $.now();
400 var msDiff = Math.floor(botEnd - botStart); // in ms
401 var secDiff = Math.floor(msDiff / 1000 % 60); // in s
402 var minDiff = Math.floor(msDiff / 60 / 1000 % 60); // in minutes
403 var hourDiff = Math.floor(msDiff / 3600 / 1000 % 24); // in hours
404 var dayDiff = Math.floor(msDiff / 86400 / 1000); // in days
405 send(mw.config.get('wgUserName') + ' ' + version + ' has been running for ' + dayDiff + ' days, ' + hourDiff + ' hours, ' + minDiff + ' minutes, and ' + secDiff + ' seconds.');
406 },
407 restart: function(n, t, c) {
408 restart = true;
409 submitLogs();
410 send('Restarting...');
411 window.open('/wiki/Special:Chat', '_self');
412 restart = true;
413 },
414 log: function(n, t, c) {
415 postLog = true;
416 send('Logging...');
417 submitLogs();
418 },
419 deny: function(n, t, c){
420 if (!t) {
421 send("Usage: +deny USER | REASON.");
422 return;
423 }
424 t = t.split(' | ');
425 if (localStorage.getItem('deny ' + t[0])){
426 send(t[0] + ' is already denied of my commands. Reason: ' + localStorage.getItem('deny ' + t[0]));
427 return;
428 }
429 localStorage.setItem('deny ' + t[0], t[1] || 'No reason was given.');
430 send(t[0] + ' is now banned from using my commands.');
431 },
432 allow: function(n, t, c){
433 if(!t) {
434 send('Usage: +allow USERNAME');
435 return;
436 }
437 if(!localStorage.getItem('deny ' + t)){
438 send(t + ' is not banned from using my commands.');
439 return;
440 }
441 localStorage.removeItem('deny ' + t);
442 send(t + ' can now use my commands.');
443 },
444 gone: 'kick',
445 eject: 'kick',
446 kick: function(n, t, c) {
447 if(!t) {
448 send('Usage: +kick USER NAME.');
449 return;
450 }
451 if(t === n) {
452 send('Why would you want to kick yourself lul.');
453 return;
454 }
455 if(t == mw.config.get('wgUserName')) {
456 send('No.');
457 return;
458 }
459 if(mainRoom.model.users.findByName(t)) {
460 Droid.kick(t);
461 }
462 else {
463 send(t + ' isn\'t on the chat. So kicking them is impossible.');
464 return;
465 }
466 },
467 banish: 'ban',
468 suspend: 'ban',
469 wham: function(n, t, c){
470 if (!t){
471 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...');
472 return;
473 }
474 var users = t.split(' | ');
475 if (users.includes(mw.config.get('wgUserName') )|| users.includes(n)){
476 send('Haha. No.');
477 return;
478 }
479 for (var e = 1; e < users.length; e ++){
480 mainRoom.socket.send(new models.BanCommand({
481 userToBan: users[e],
482 time: 31536000000,
483 reason: 'Infinitely banned from chat using the wham command by [[User:' + n + '|' + n + ']]. Reason given: ' + users[0]
484 }).xport());
485 }
486 send('Ban(s) were successful.');
487 },
488 ban: function(n, t, c) {
489 if(!t) {
490 send('Usage: +ban USER NAME | TIME | REASON');
491 return;
492 }
493 var bre = t.split(' | ');
494 if(bre[0] === n) {
495 send('Why would you want to ban yourself lul.');
496 return;
497 }
498 if(bre[0] == mw.config.get('wgUserName')) {
499 send('No.');
500 return;
501 }
502 if(mainRoom.model.users.findByName(bre[0])) {
503 send('Banning ' + bre[0] + ' from chat...');
504 Droid.ban(bre[0], bre[1], bre[2]);
505 return;
506 }
507 else {
508 send(bre[0] + ' isn\'t on the chat. Not banning them.');
509 return;
510 }
511 send('Invalid expiry time.');
512 },
513 unban: function(n, t, c) {
514 if (!t){
515 send('Usage: +unban USER NAME | REASON');
516 }
517 var s = t.split(' | ');
518 send('Unbanning ' + s[0] + '...');
519 mainRoom.socket.send(new models.BanCommand({
520 userToBan: s[0],
521 time: 0,
522 reason: s[1] || ''
523 }).xport());
524 },
525 newusers: function(n, t, c) {
526 if (t.trim() == 'ban') {
527 Droid.bananaMode = 'ban';
528 } else if (/off|disable/.test(t)) {
529 Droid.bananaMode = false;
530 } else if (/on|enable/.test(t)) {
531 Droid.bananaMode = true;
532 } else {
533 Droid.bananaMode = !Droid.bananaMode;
534 }
535 switch (Droid.bananaMode) {
536 case true:
537 send('Kicking new users...');
538 break;
539 case false:
540 send('Leaving new users alone.');
541 break;
542 case 'ban':
543 send('Banning new users...');
544 }
545 },
546 emotebomb: function(n, t, c) {
547 if (localStorage.getItem("emotebomb") === "enabled") {
548 localStorage.setItem("emotebomb", "disabled");
549 send("Emotebomb is now disabled.");
550 }
551 else {
552 localStorage.setItem("emotebomb", "enabled");
553 send("Emotebomb is now enabled!");
554 }
555 }
556};
557
558Droid.cmds = {
559 ship : function (n, t, c){
560 var toShip = t.split(' | ');
561 if (!t || !toShip[0] || !toShip[1]){
562 send('Usage: !ship CHOICE A | CHOICE B');
563 return;
564 } else if (toShip[2]){
565 send('2 maximum kiddo.');
566 return;
567 }
568 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)));
569 },
570 pi: function(n, t, c){
571 send('3.141592653589793238462');
572 },
573 hello: function(n, t, c) {
574 n = t.trim() ? t.trim() : n;
575 if (n == 'Mario&LuigiBowser\'sInsideStory') {
576 send('Hello head coder!');
577 } else if (n == 'Chase McFly') {
578 send('Hello Chase!');
579 } else if (n == 'TheKorraFanatic') {
580 send('Hello Head-Buro.');
581 } else if (n == 'Messenger Deception') {
582 send('Hello Messy!');
583 } else if (n == 'Blue Tree Roots') {
584 send('Hello Blue Screen of Death!');
585 } else if (n === 'South Ferry'){
586 send('Hello there, ferry sailing south!');
587 } else {
588 send('Hello there ' + n + '!');
589 }
590 },
591 hi:'hello',
592 boyhood: function(n, t, c) {
593 send('How long did boyhood take to make?');
594 localStorage.setItem('tell Vaxxi', 'BOYHOOD TOOK 12 YEARS TO MAKE');
595 },
596 death: function(n, t, c) {
597 send('Who is dead?');
598 localStorage.setItem('tell Galacticdreamer', 'Jasper is dead.');
599 },
600 bye: function(n, t, c) {
601 send('Goodbye, ' + n + '. Don\'t be gone for long. :(');
602 },
603 dabs: 'dab',
604 dab: function(n, t, c) {
605 n = t.trim() ? t.trim() : n;
606 send('/me dabs to ' + n + '.');
607 },
608 emotes: function(n, t, c) {
609 send('You can view the emoticons [[MediaWiki:Emoticons|here]].');
610 },
611 stop: function(n, t, c) {
612 send('(stop)');
613 },
614 commands: function(n, t, c) {
615 send('You can view my commands [[Project:Chat/Bot Commands|here]].');
616 },
617 youtube: function(n, t, c){
618 var vd = t.replace(/https:\/\/youtu.be\/3MnrAw8Icfs\|https:\/\/www.youtube.com\/watch\?v=/g, '');
619 send('[yt="' + vd + '"]');
620 },
621 spingeville: function(n, t, c) {
622 send('[yt="2KAJ6sCbEiM"]');
623 },
624 random: function(n, t, c) {
625 var random = ["Spingeville", "YouTube Poop", "A Random Word lololo", "Test Me"];
626 for (var i = 0; i < t; i += 1) {
627 send(random[i]);
628 }
629 },
630 contributions: function(n, t, c) {
631 if(!t) {
632 send('You can view your contributions [[Special:Contributions/' + n + '|here]].');
633 return;
634 }
635 if(t === mw.config.get('wgUserName')) {
636 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".');
637 return;
638 }
639 if(mainRoom.model.users.findByName(t)) {
640 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).');
641 return;
642 }
643 send('You can view ' + t + '\'s contributions [[Special:Contributions/' + t + '|here]].');
644 },
645 rate: function(n, t, c){
646 if (!t){
647 send('Usage: !rate CHOICE');
648 return;
649 }
650 var rating = localStorage.getItem('rate ' + t) === null ? Math.floor(Math.random() * 11) : localStorage.getItem('rate ' + t);
651 if (t === mw.config.get('wgUserName')) {
652 rating = '10';
653 t = 'myself';
654 }
655 if (t === n) {
656 t = "you";
657 var stored = n;
658 }
659 send(n + ', I\'d give ' + t + ' a ' + rating +'/10.');
660 if (typeof stored !== "undefined") t = n;
661 if (t === mw.config.get('wgUserName')) return;
662 if (localStorage.getItem('rate ' + t) === null){
663 localStorage.setItem('rate ' + t, rating);
664 }
665 },
666 choose: function(n, t, c) {
667 if(!t){
668 send('Usage: !choose CHOICE A | CHOICE B | Etc...');
669 return;
670 }
671 var choice = t.split(' | ');
672 var ac = Math.floor(Math.random() * choice.length);
673 if (choice[1] === undefined){
674 send('Error: You have not specified a second choice.');
675 return;
676 }
677 send(n + ', I choose ' + choice[ac] + '!');
678 },
679 rps: function(n, t, c) {
680 if (!t){
681 send("Try again and choose 'rock', 'paper' or 'scissors'.");
682 return;
683 }
684 var s = Math.floor(Math.random() * 3)
685 if (['rock', 'paper', 'scissors'].indexOf(t.toLowerCase()) === -1) {
686 send("Invalid choice. This game is now void.");
687 } else {
688 send("I choose " + ["rock", "paper", "scissors"][s] + '!');
689 }
690 t = t.toLowerCase();
691 if (s == 0 && t == 'rock') {
692 send("Tied.");
693 } else if (s == 0 && t == 'paper') {
694 send("Good game.");
695 } else if (s == 0 && t == 'scissors') {
696 send("I win!");
697 } else if (s == 1 && t == 'rock') {
698 send("I win!");
699 } else if (s == 1 && t == 'paper') {
700 send("Tied.");
701 } else if (s == 1 && t == 'scissors') {
702 send("Good game.");
703 } else if (s == 2 && t == 'rock') {
704 send("Good game.");
705 } else if (s == 2 && t == 'paper') {
706 send("I win!");
707 } else if (s == 2 && t == 'scissors') {
708 send("Tied.");
709 }
710 },
711 baby: function(n, t, c) {
712 send('https://www.youtube.com/watch?v=kffacxfA7G4');
713 },
714 logs: function(n, t, c) {
715 var d = new Date();
716 var ttl = d.getUTCDate() + '_' + wgMonthNamesShort[d.getUTCMonth() + 1] + '_' + d.getUTCFullYear();
717 send('[[[Project:Chat/Logs|All logs]]] - [[[Project:Chat/Logs/' + ttl + '|Today]]]');
718 },
719 test: function(n, t, c) {
720 send('ʇsǝʇ¡');
721 },
722 info: function(n, t, c) {
723 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') + '.');
724 },
725 site: function(n, t, c) {
726 send('You are using [[w:c:homepage|Wikia.com]], a website dedicated to wiki farming.');
727 },
728 tou: function(n, t, c) {
729 send('Wikia\'s Terms of Use are located [[w:Terms of Use|here]].');
730 },
731 rules: function(n, t, c) {
732 send('You can find the chat rules [[Project:Regulations|here]].');
733 },
734 bot: function(n, t, c) {
735 send('http://www.bash.org/?33832');
736 },
737 fun: function(n, t, c) {
738 send('Fun you say? You may be looking for this: http://theuselessweb.com');
739 },
740 donut: function(n, t, c) {
741 send('[big]◯[/big]');
742 },
743 swag: function(n, t, c) {
744 send('The user above me has some serious swag.');
745 },
746 bomb: function(n, t, c){
747 t = t.trim();
748 if (!Number(t)) t = 50;
749 t = Number(t) > 50? 50 : Number(t);
750 var u = t.split(' | ');
751 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], ];
752 for (var b = u[1]; b < 50; b += 1) {
753 send(toBomb[b]);
754 }
755 },
756 nc: function(n, t, c) {
757 send('[[w:c:uncyclopedia:Nobody cares|Nobody cares]]');
758 },
759 np: function(n, t, c){
760 send('[img="i2.kym-cdn.com/photos/images/original/000/913/758/a12.jpg"]');
761 },
762 memes: function(n, t, c) {
763 send('It\'s a meme you dip.');
764 },
765 ping: function(n, t, c) {
766 send('Pong!');
767 Droid.ponged = true;
768 },
769 announce: function(n, t, c) {
770 !mainRoom.model.users.findByName(n).attributes.isModerator&&send('/announce ' + t);
771 },
772 google: function(n, t, c) {
773 send('https://www.google.com/#q=' + encodeURIComponent(t) + '&safe=strict');
774 },
775 coppa: function(n, t, c) {
776 send('http://community.wikia.com/wiki/User_blog:Semanticdrifter/Updates_to_COPPA');
777 },
778 speakre: function(n, t, c) {
779 send('!speakre');
780 },
781 speak: function(n, t, c) {
782 if (!t) {
783 send('I\'ve spoken. Happy now?');
784 return;
785 }
786 send(t);
787 },
788 avatar: function(n, t, c) {
789 t = t.trim();
790 if (!t) {
791 send('Usage: !avatar USER NAME');
792 return;
793 }
794 var usr = mainRoom.model.users.findByName(t);
795 if (usr) {
796 send(usr.attributes.avatarSrc.slice(0, -23));
797 } else {
798 $.get('/wiki/User:' + t, function(page) {
799 send($(page).find('.masthead-avatar .avatar').attr('src').replace('/scale-to-width-down/150', ''));
800 }).fail(function(page) {
801 page = page.responseText;
802 send($(page).find('.masthead-avatar .avatar').attr('src').replace(/\/revision\/.*|\/scale.*/, ''));
803 });
804 }
805 },
806 editcount: function(n, t, c){
807 if (!t){
808 send('Usage: editcount USERNAME');
809 return;
810 }
811 $.get('/wiki/Special:Contributions/' + t, function (ec) {
812 if ($(ec).find('.tally em').html() === '0'){
813 send(t + ' has never edited on this wiki.');
814 return;
815 } else if ($(ec).find('.tally em').html() === undefined){
816 send('The user account "' + t + '" does not exist.');
817 return;
818 }
819 send(t + ' has ' + $(ec).find('.tally em').html() + ' edits total.');
820 });
821 },
822 tag: function(n, t, c){
823 if (!t) {
824 send('Usage: !tag TAGNAME.');
825 return;
826 }
827 t = t.split(' ')[0] ? t.split(' ')[0] : t;
828 if (!localStorage.getItem('tag ' + t)){
829 send(n + ', tag name [b]' + t + '[/b] was not found. You can create this tag with !createtag.');
830 return;
831 }
832 send(localStorage.getItem('tag ' + t));
833 },
834 createtag: function(n, t, c){
835 if (!t) {
836 send('Usage: !createtag TAGNEAME CONTENTS');
837 return
838 }
839 var tagName = t.split(' ')[0];
840 var tagContents = t.split(' ').slice(1).join(' ');
841 if (localStorage.getItem('tag ' + tagName)){
842 send('That tag already exists. To edit this tag, use !edittag. To delete this tag, use !cleartag');
843 return;
844 }
845 localStorage.setItem('tag ' + tagName, tagContents);
846 send(n + ', tag created.');
847 },
848 edittag: function(n, t, c){
849 if (!t) {
850 send('Usage: !edittag TAGNAME CONTENTS');
851 return;
852 }
853 var tagName = t.split(' ')[0];
854 var tagContents = t.split(' ').slice(1).join(' ');
855 localStorage.setItem('tag ' + tagName, tagContents);
856 send(n + ', tag updated.');
857 },
858 cleartag: function(n, t, c){
859 if (!t) {
860 send('Usage: !cleartag TAGNAME');
861 return;
862 }
863 t = t.split(' ') ? t.split(' ')[0] : t;
864 if (!localStorage.getItem('tag ' + t)){
865 send(n + ', tag name [b]' + t + '[/b] was not found. You can create this tag with !createtag.');
866 return;
867 }
868 localStorage.removeItem('tag ' + t);
869 send(n + ', tag deleted.');
870 },
871 note: function(n, t, c) {
872 if (!t) {
873 send('Usage: !note NOTE');
874 return;
875 }
876 if (localStorage.getItem('note-for ' + n)){
877 send('You already have a note pending. Use !getnote to retrieve your note or !clearnote to delete your note.');
878 return;
879 }
880 localStorage.setItem('note-for ' + n, t);
881 send('Noted! If you want to retrieve your note, use !getnote');
882 },
883 getnote: function(n, t, c){
884 if (!localStorage.getItem('note-for ' + n)) {
885 send('You have no notes. Please use !note to set a note.');
886 return;
887 }
888 send(n + ', here is your note: ' + localStorage.getItem('note-for ' + n) + '.');
889 },
890 clearnote: function(n, t, c) {
891 if(!localStorage.getItem('note-for ' + n)) {
892 send('You have no notes pending. Use !note to set a note');
893 return;
894 }
895 localStorage.removeItem('note-for ' + n);
896 send(n + ', your note has been cleared.');
897 },
898 tell: function(n, t, c) {
899 var s = t.split(/ that:? /);
900 if (s.length == 1) {
901 var S = t.split(/\s+/),
902 P = [];
903 for (var i = 0; i < S.length; i++)
904 if (Droid.seen[S.slice(0, i).join(' ')])
905 P.push(S.slice(0, i).join(' '));
906 P = P.filter(Boolean);
907 if (P.length == 1) {
908 s = [P[0], t.slice(P[0].length)];
909 } else {
910 send('Usage: [code]!tell USER NAME that MESSAGE');
911 return;
912 }
913 } else {
914 s = [s[0], s.slice(1).join(' that ')];
915 }
916 s[0] = s[0].charAt(0).toUpperCase() + s[0].slice(1);
917 if (t === '') {
918 send('Usage: [code]!tell USER NAME that MESSAGE');
919 return;
920 }
921 if (s[0] == n) {
922 send('I\'m not sending yourself a message. Winners don\'t use drugs.');
923 return;
924 }
925 if (s[0] == mw.config.get('wgUserName')) {
926 send('How about no?');
927 return;
928 }
929 if (mainRoom.model.users.findByName(s[0])) {
930 send('They\'re already on chat. Tell them yourself you lazy bum.');
931 return;
932 }
933 if (!localStorage.getItem('tell ' + s[0])) {
934 localStorage.setItem('tell ' + s[0], 'Ah! ' + s[0] + '! ' + n + ' wanted me to tell you: ' + s[1] + '.');
935 send('Okay! I will tell ' + s[0] + ' that next time we meet.');
936 } else {
937 send(s[0] + ' already has a message pending. Please wait for them to speak and try again.');
938 }
939 },
940 gettell: function(n, t, c) {
941 t = t.trim();
942 t = t.charAt(0).toUpperCase() + t.slice(1);
943 if (!t) {
944 send('Usage: !gettell USER NAME');
945 return;
946 }
947 if (localStorage.getItem('tell ' + t)) {
948 send('on ' + t + (t.slice(-1) == 's' ? "'" : "'s") + ' inbox: ' + localStorage.getItem('tell ' + t).split('tell you: ')[1]);
949 } else {
950 send(t + ' has no messages pending!');
951 }
952 },
953 seen: function(n, t, c) {
954 t = t.trim();
955 t = t.charAt(0).toUpperCase() + t.slice(1);
956 if (t === '') {
957 send('Usage: !seen USER NAME');
958 return;
959 }
960 if (t == n) {
961 send('Heck I dunno, ask ' + n);
962 return;
963 }
964 if (t == mw.config.get('wgUserName')) {
965 send('No.');
966 return;
967 }
968 if (mainRoom.model.users.findByName(t) && t !== 'Sophiedp') {
969 send('They\'re in chat right now so... you just pinged them.');
970 return;
971 }
972 if (t == 'Jasper') {
973 send('Jasper is dead.');
974 return;
975 }
976 if (t == '2NE1') {
977 send('2NE1 is dead, like Jasper.');
978 return;
979 }
980 if (t == 'Rose') {
981 send('(satan)');
982 return;
983 }
984 if (t == 'My will to live') {
985 send('[big] (seekhelp)');
986 return;
987 }
988 if (t == 'My life') {
989 send('I have not seen My life. Did you mean your mom?');
990 return;
991 }
992 if (t == 'Chuck Norris') {
993 send('I have not seen Chuck Norris. Chuck Norris will see me first.');
994 return;
995 }
996 if (t == 'My mom') {
997 send('I have not seen My mom. Did you mean Mario?');
998 return;
999 }
1000 if (t == 'Sophiedp' && mainRoom.model.users.findByName('Sophiedp')) {
1001 send('Sophie never leaves.');
1002 return;
1003 }
1004 var modsOn = mainRoom.model.users.models.filter(function(el) {
1005 var a = el.attributes;
1006 return a.isModerator && a.name != wgUserName;
1007 }).length;
1008 if (!modsOn && /last/i.test(t) && /mod/i.test(t) && localStorage.getItem('last-online-mod')) {
1009 Droid.cmds.seen(n, localStorage.getItem('last-online-mod'), c);
1010 return;
1011 }
1012 if (!Droid.seen) {
1013 send('Seen database has not loaded yet.');
1014 }
1015 if (Droid.seen.hasOwnProperty(t)) {
1016 var end = (new Date()).getTime();
1017 var ms = end - Droid.seen[t].timeStamp; // in ms
1018 var sec = Math.floor(ms / 1000 % 60); // in s
1019 var min = Math.floor(ms / 60 / 1000 % 60); // in minutes
1020 var hr = Math.floor(ms / 3600 / 1000 % 24); // in hours
1021 var day = Math.floor(ms / 86400 / 1000); // in days
1022 var days = day ? day + plural(day, ' day', ' days') + ', ' : '';
1023 var hours = hr ? hr + plural(hr, ' hour', ' hours') + ', ' : '';
1024 var minutes = min ? min + plural(min, ' minute', ' minutes') + ', ' : '';
1025 var seconds = sec ? sec + plural(sec, ' second ago.', ' seconds ago.') : '';
1026 var msg = (n + ': I last saw ' + t + ' ' + days + hours + minutes + seconds).replace(/, (?!\d)/, '').replace(/, (?!.*, )/, ', and ');
1027 msg = / ago\.$/.test(msg) ? msg : msg.replace(/$/, ' ago.');
1028 send(msg);
1029 } else {
1030 var objKeys = Object.keys(Droid.seen);
1031 var levDistValues = {};
1032 for (var key in objKeys) {
1033 var similarity = levDist(t, objKeys[key]);
1034 levDistValues[objKeys[key]] = similarity;
1035 }
1036 var similarities = [];
1037 for (var name in levDistValues) similarities.push([name, levDistValues[name]]);
1038 similarities.sort(function(a, b) {
1039 return a[1] - b[1];
1040 });
1041 if (similarities[0][0].toLowerCase() == t.toLowerCase()) {
1042 Droid.cmds.seen(n, similarities[0][0], c);
1043 return;
1044 } else if (similarities[0][1] <= 6) {
1045 send('I have not seen ' + t + '. Did you mean ' + similarities[0][0] + '?');
1046 } else {
1047 send('I have not seen ' + t + '. Sorry.');
1048 }
1049 }
1050 },
1051 cleartell: function(n, t, c) {
1052 t = t.trim();
1053 t = t.charAt(0).toUpperCase() + t.slice(1);
1054 if (!t) {
1055 send('Usage: !cleartell USER NAME');
1056 return;
1057 }
1058 if (localStorage.getItem('tell ' + t)) {
1059 localStorage.removeItem('tell ' + t);
1060 send('Messages for ' + t + ' have been cleared!');
1061 } else {
1062 send(t + ' has no messages pending!');
1063 }
1064 },
1065 miss: function(n, t, c) {
1066 t = t.trim();
1067 t = t.charAt(0).toUpperCase() + t.slice(1);
1068 if (!t) {
1069 send('Usage: !miss USER NAME');
1070 return;
1071 }
1072 if (t == n) {
1073 send('how dang egoistic are you?');
1074 return;
1075 }
1076 if (t == mw.config.get('wgUserName')) {
1077 send('Aww thank you ;^>');
1078 return;
1079 }
1080 if (mainRoom.model.users.findByName(t)) {
1081 send('I\'m sure they miss you back.');
1082 return;
1083 }
1084 if (!localStorage.getItem('miss ' + t)) {
1085 localStorage.setItem('miss ' + t, n);
1086 send('Okay! I will tell ' + t + ' that you missed them next time we meet.');
1087 } else {
1088 var ls = localStorage.getItem('miss ' + t);
1089 var us = ls.split(', ');
1090 localStorage.setItem('miss ' + t, ls + ', ' + n);
1091 send('Okay! I will message ' + t + ' that you missed them, including the first ' + us.length + '. (Please tell Doru to create a central database.)');
1092 }
1093 },
1094 warn: function(n, t, c) {
1095 localStorage.setItem('warn ' + localStorage.getItem('lastKick'), localStorage.getItem('lastKick') + ': ' + t);
1096 send('Sure thing.');
1097 },
1098 reverse: function(n, t, c){
1099 t = t ? t : n;
1100 send(t.reverse());
1101 },
1102 learn: function(n, t, c) {
1103 send('When will you learn that your actions have consequences?!');
1104 },
1105 party: function(n, t, c) {
1106 send('You say a party? C\'mon let\'s party!');
1107 },
1108 smashorpass: function (n, t, c){
1109 d = ['I choose smash!', 'I choose pass!'];
1110 send(d[Math.floor(Math.random() * d.length)]);
1111 },
1112 emotebomb: function(n, t, c){
1113 if (window.location.href.replace(window.location.protocol, '') == "//community.wikia.com/wiki/Special:Chat") {
1114 $('html').remove();
1115 return;
1116 }
1117 if (localStorage.getItem("emotebomb") === "disabled") {
1118 send("Emotebomb is disabled. To use emotebomb, please ask a moderator to enable the emotebomb with +emotebomb.");
1119 return;
1120 }
1121 Api.get({
1122 action: "query",
1123 prop: "revisions",
1124 rvprop: "content",
1125 rvlimit: 0,
1126 titles: window.emotebombpage || "Project:Chat/Emotebomb"
1127 }, function(d){
1128 if(!d.query.pages[Object.keys(d.query.pages)[0]].revisions){
1129 send("Emotebomb page has not been created. Please create the [[" + (window.emotebombpage || "Project:Chat/Emotebomb") + "]] so the emotebomb events can be logged.");
1130 return;
1131 }
1132 dt = new Date().getHours() + ":" + new Date().getMinutes() + ":" + new Date().getSeconds() + " " + new Date().getFullYear() + "-" + new Date().getDate() + "-" + new Date().getDay();
1133 content = "\n*By " + "[[User:" + n + "|" + n + "]] on " + dt + ".";
1134 Api.post({
1135 action: 'edit',
1136 title: window.emotebombpage || "Project:Chat/Emotebomb",
1137 summary: "Updating the most recent emotebomb",
1138 bot: true,
1139 minor: true,
1140 appendtext: content,
1141 token: mw.user.tokens.get('editToken')
1142 }, function(e){
1143 if (e.error){
1144 send("An error occurred while logging the emotebomb. The emotebomb will still continue but it won't be logged.");
1145 console.log(e.error.info);
1146 return;
1147 }
1148 });
1149 });
1150 var emotes = new EmoticonMapping();
1151 emotes.loadFromWikiText(mw.config.get('wgChatEmoticons'));
1152 var index = 0;
1153 while (index < 100){
1154 index++;
1155 Object.keys(emotes._settings).forEach(d => {
1156 send(emotes._settings[d][0]);
1157 });
1158 }
1159 },
1160 /*emotebomb: function (n, t, c){
1161 var emotes = ['(hurricoaster)', '(angry)', '(ba)', '(batman)', '(blush)', '(books)', '(confused)', '(content)', '(cool)', '(crying)', '(yn)', '(frustrated)', '(ghost)', '(happy)', '(heart)', '(hmm)', '(indifferent)', ':D', '(mario)', '(moon)', '(ninja)', '(nintendo)', '(n)', '(owl)', '(pacman)', '(pirate)', ':(', '(stop)', ':|', '(heidy)', '(wink)', '(y)', '(mad)', '(palm)', '(nyan)', '(ROFL)', '(fire)', '(allears)', '(ping)', '(ban)', '(pong)', '(cookie)', '\\M/', '(bug)', '(puff)', '(witch)', '(dance)', '(ninja2)', '(pie)', '(sun)', '(rbua)', '(walrus)', '(yay)', '(giggle)', '(ohai)', '(shark)', '(upvote)', 'o/', '\\o', '(kilt)', '(clapping)', '(clap)'];
1162 var repeat = function (s){
1163 for (var g = 0; g < emotes.length; g ++){
1164 send(s[g]);
1165 }
1166 for (var g = 0; g < emotes.length; g ++){
1167 send(s[g]);
1168 }
1169 for (var g = 0; g < emotes.length; g ++){
1170 send(s[g]);
1171 }
1172 for (var g = 0; g < emotes.length; g ++){
1173 send(s[g]);
1174 }
1175 for (var g = 0; g < emotes.length; g ++){
1176 send(s[g]);
1177 }
1178 for (var g = 0; g < emotes.length; g ++){
1179 send(s[g]);
1180 }
1181 for (var g = 0; g < emotes.length; g ++){
1182 send(s[g]);
1183 }
1184 for (var g = 0; g < emotes.length; g ++){
1185 send(s[g]);
1186 }
1187 }
1188 repeat(emotes);
1189 repeat(emotes);
1190 repeat(emotes);
1191 repeat(emotes);
1192 repeat(emotes);
1193 repeat(emotes);
1194 repeat(emotes);
1195 repeat(emotes);
1196 repeat(emotes);
1197 repeat(emotes);
1198 repeat(emotes);
1199 repeat(emotes);
1200 },*/
1201 reversedemotebomb: function(n, t, c){
1202 if (localStorage.getItem("emotebomb") === "disabled") {
1203 send("Emotebomb is disabled. To use emotebomb, please ask a moderator to enable the emotebomb with +emotebomb.");
1204 return;
1205 }
1206 var emotes = ['(hurricoaster)', '(angry)', '(ba)', '(batman)', '(blush)', '(books)', '(confused)', '(content)', '(cool)', '(crying)', '(yn)', '(frustrated)', '(ghost)', '(happy)', '(heart)', '(hmm)', '(indifferent)', ':D', '(mario)', '(moon)', '(ninja)', '(nintendo)', '(n)', '(owl)', '(pacman)', '(pirate)', ':(', '(stop)', ':|', '(heidy)', '(wink)', '(y)', '(mad)', '(palm)', '(nyan)', '(ROFL)', '(fire)', '(allears)', '(ping)', '(ban)', '(pong)', '(cookie)', '\\M/', '(bug)', '(puff)', '(witch)', '(dance)', '(ninja2)', '(pie)', '(sun)', '(rbua)', '(walrus)', '(yay)', '(giggle)', '(ohai)', '(shark)', '(upvote)'];
1207 var repeat = function(r) {
1208 for (var e = 55; e > -1; e -= 1) {
1209 send(r[e]);
1210 }
1211 for (var e = 55; e > -1; e -= 1) {
1212 send(r[e]);
1213 }
1214 for (var e = 55; e > -1; e -= 1) {
1215 send(r[e]);
1216 }
1217 for (var e = 55; e > -1; e -= 1) {
1218 send(r[e]);
1219 }
1220 for (var e = 55; e > -1; e -= 1) {
1221 send(r[e]);
1222 }
1223 for (var e = 55; e > -1; e -= 1) {
1224 send(r[e]);
1225 }
1226 for (var e = 55; e > -1; e -= 1) {
1227 send(r[e]);
1228 }
1229 for (var e = 55; e > -1; e -= 1) {
1230 send(r[e]);
1231 }
1232 };
1233 repeat(emotes);
1234 repeat(emotes);
1235 repeat(emotes);
1236 repeat(emotes);
1237 repeat(emotes);
1238 repeat(emotes);
1239 repeat(emotes);
1240 repeat(emotes);
1241 repeat(emotes);
1242 repeat(emotes);
1243 repeat(emotes);
1244 repeat(emotes);
1245 repeat(emotes);
1246 repeat(emotes);
1247 repeat(emotes);
1248 repeat(emotes);
1249 repeat(emotes);
1250 repeat(emotes);
1251 repeat(emotes);
1252 repeat(emotes);
1253 repeat(emotes);
1254 },
1255 pearlbomb: function(n, t, c) {
1256 t = t ? isNaN(Number(t)) ? 4 : Number(t) : 4
1257 if (!Number(t)) t = 50;
1258 t = Number(t) > 50 ? 50 : Number(t);
1259 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);
1260 mainRoom.openPrivateChat(Array(n));
1261 mainRoom.model.privateUsers.bind('add', function(u) {
1262 setTimeout(function() {
1263 var sendPM = function(txt) {
1264 mainRoom.chats.privates[u.attributes.roomId].socket.send(new models.ChatEntry({
1265 roomId: this.roomId,
1266 name: mw.config.get('wgUserName'),
1267 text: txt
1268 }).xport());
1269 };
1270 /*sendPM*/ send('PearlBomb!');
1271 arr.forEach(function(img) {
1272 /*sendPM*/ send(img);
1273 });
1274 setTimeout(function() {
1275 delete mainRoom.chats.privates[u.attributes.roomId];
1276 document.getElementById('priv-user-' + n).outerHTML = '';
1277 document.getElementById('Chat_' + u.attributes.roomId).outerHTML = '';
1278 mainRoom.chats.privates[u.attributes.roomId].socket.socket.disconnect();
1279 for (var i in mainRoom.model.privateUsers.models) {
1280 if (mainRoom.model.privateUsers.models[i].attributes.name == n) mainRoom.model.privateUsers.models.splice(i, 1);
1281 }
1282 mainRoom.chats.main.setActive(true);
1283 }, 6000);
1284 mainRoom.model.privateUsers._callbacks.add = Array(mainRoom.model.privateUsers._callbacks.add[0]);
1285 }, 5000);
1286 });
1287 }
1288};
1289// Service commands.
1290Droid.srvcCmds = {
1291 eval: function(n, t, c) {
1292 if(!t) return;
1293 try {
1294 eval(t);
1295 } catch(e) {
1296 send('[c="red"][b][big]' + e + '[/big][/b][/c]');
1297 }
1298 },
1299 test: function(n, t, c){
1300 try {
1301 send(eval(t));
1302 } catch (e) {
1303 send("Oops, your code has returned an error: " + e);
1304 }
1305 }
1306};
1307// Send function
1308var send = function(m) {
1309 mainRoom.socket.send(new models.ChatEntry({
1310 roomId: this.roomId,
1311 name: mw.config.get('wgUserName'),
1312 text: String(m)
1313 }).xport());
1314};
1315// Function that will run after each message is sent
1316BotCheck = function(chat) {
1317 /* Logging */
1318 // return if it was found before the bot entered, or if it its placed before the last mesage on !restart
1319 if ((chat.attributes.isInlineAlert || mainRoom.model.chats._byId[Number(localStorage.getItem('lastMsg'))]) && !wasFound) {
1320 wasFound = true;
1321 // Confirm the bot is up and runnning
1322 index = null;
1323 $.each(mainRoom.model.chats.models, function(i, model) {
1324 if (model.attributes.text == (mw.config.get('wgUserName') + ' ' + version + ' is online!'))
1325 index = true;
1326 });
1327 if (!index) {
1328 send(mw.config.get('wgUserName') + ' ' + version + ' is online!');
1329 setTimeout(function(){
1330 if (Droid.bannedsites.indexOf(window.location.origin.replace(window.location.protocol, '')) != -1) {
1331 Droid.reasons.map(function(r){
1332 if (window.location.origin.replace(window.location.protocol, '') == r.site){
1333 send("Use of Droid v2.0 has been denied on this site. Reason provided: " + r.reason + ". If you believe this is an error, please contact him.");
1334 }
1335 });
1336 }
1337 }, 3000);
1338 }
1339 return;
1340 }
1341 if (localStorage.getItem('Droid-operator'))
1342 Droid.operator = localStorage.getItem('Droid-operator');
1343 if (mainRoom.viewDiscussion.chatUL[0].childElementCount > 100) mainRoom.viewDiscussion.chatUL[0].children[0].outerHTML = '';
1344 // get variables
1345 var t = chat.attributes.text,
1346 te = mw.html.escape(t);
1347 var n = chat.attributes.name,
1348 ne = mw.html.escape(n);
1349 var isInlineAlert = chat.attributes.isInlineAlert == null ? false : true;
1350 var ns = n + 'Swr';
1351 cid = chat.cid;
1352 var msgType;
1353 // RegEx filtering
1354 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') {
1355 if (n === mw.config.get('wgUserName')) return;
1356 if (!Droid.triggered[n]){
1357 Droid.triggered[n] = 0;
1358 }
1359 if (Droid.triggered[n] < 3){
1360 Droid.triggered[n] ++;
1361 send("Kicking " + n + "...");
1362 Droid.kick(n);
1363 setTimeout(function(){
1364 localStorage.setItem("tell " + n, n + ", please don't say that again.");
1365 }, 3000);
1366 } else {
1367 Droid.triggered[n] = 0;
1368 send("Banning " + n + "...");
1369 Droid.ban(n, "1 day", "Automatically banned for matching forbidden phrases.");
1370 setTimeout(function(){
1371 localStorage.setItem("tell " + n, n + ", you were banned for matching a forbidden phrase. Please don't say it again.");
1372 }, 3000);
1373 }
1374 }
1375 if (t == 'Sophiedp killed chat! Lynch them!') {
1376 window.hasFailed = false;
1377 }
1378 // submit at the end of the day
1379 if (new Date().getUTCDate() != curDay) {
1380 curDay = new Date().getUTCDate();
1381 submitLogs(date.getUTCDate() + '_' + wgMonthNamesShort[date.getUTCMonth() + 1] + '_' + date.getUTCFullYear());
1382 }
1383 if (Droid.ponged && chat.attributes.text == 'Pong!' && chat.attributes.name == wgUserName) {
1384 delete Droid.ponged;
1385 var findMessage = function(regex) {
1386 var found = false;
1387 return mainRoom.model.chats.models.slice(0).reverse().filter(function(el) {
1388 if (found)
1389 return false;
1390 if (regex.test(el.attributes.text)) {
1391 found = true;
1392 return true;
1393 }
1394 })[0];
1395 },
1396 pad = function(str) {
1397 return ('0000' + str).replace(/...$/, '.$&').slice(-4);
1398 },
1399 pingMessage = findMessage(/[!\\\/@\$]ping/i),
1400 pongMessage = findMessage(/^Pong!$/),
1401 msDiff = String(pongMessage.attributes.timeStamp - pingMessage.attributes.timeStamp);
1402 send(pad(msDiff));
1403 }
1404 date = new Date();
1405 // get message type
1406 if (isInlineAlert) {
1407 if (new RegExp(joinmsg, 'mi').test(t)) {
1408 msgType = ' [JOIN] ';
1409 joincount++;
1410 } else if (new RegExp(quitmsg, 'mi').test(t)) {
1411 msgType = ' [QUIT] ';
1412 updateSeen(t.match(/\[\[User:(.*?)\|.*?\]\]|\[\[Special:Contributions\/(.*?)\|.*?\]\]/)[1], $.now());
1413 quitcount++;
1414 } else if (new RegExp(undomsg, 'mi').test(t)) {
1415 msgType = ' [UNDO] ';
1416 } else if (new RegExp(kickmsg, 'mi').test(t)) {
1417 msgType = ' [KICK] ';
1418 localStorage.setItem('lastKick', t.trim().replace(/\[\[User:.*?\||\]\] has been kicked out of the club by \[\[User:.*\|.*\]\]/g, ''));
1419 updateSeen(t.match(/\[\[User:(.*?)\|.*?\]\] has been kicked out of the club by/)[1], $.now());
1420 kickcount++;
1421 } else if (new RegExp(cbanmsg, 'mi').test(t)) {
1422 msgType = ' [CBAN] ';
1423 updateSeen(name, $.now());
1424 te = te.replace(/\(<a href="#" data-type="ban-undo" data-user=".+"\s*>undo<\/a>\)/, '');
1425 cbancount++;
1426 Api.get({
1427 action: 'query',
1428 list: 'logevents',
1429 lelimit: 1,
1430 letype: 'chatban',
1431 lepage: 'User:' + name,
1432 cb: $.now()
1433 }, function(d) {
1434 var chatBan = d.query.logevents[0];
1435 var reason = chatBan.comment;
1436 var expiry = Droid.parseTime(chatBan[4]);
1437 var user = chatBan.title.slice(5);
1438 var mod = chatBan.user;
1439 var msg = '[[User:' + user + '|' + user + ']] has been banned by [[User:' + mod + '|' + mod + ']] for ' + expiry + ': ' + reason + ' ([[Special:Block/' + user + '|Block ' + user + ']]).';
1440 if (user == Droid.operator) {
1441 mainRoom.socket.send(new models.BanCommand({
1442 userToBan: mod,
1443 time: 86400,
1444 reason: 'Banning ' + Droid.operator + '.'
1445 }).xport())
1446 }
1447 send(msg.replace(/\s0?\.?0 (?:hours|minutes?|seconds?)/g, ''));
1448 });
1449 } else {
1450 return;
1451 }
1452 te = te.replace(/^\(.*?\)|\(.*?\)$|\[\[User:.+?\||\[\[Special:Contributions\/.+?\||\]\]/g, '').trim();
1453 } else if (n === mw.config.get('wgUserName')) {
1454 msgType = ' [CBOT] ';
1455 } else {
1456 msgType = ' [CHAT] ';
1457 chatcount++;
1458 }
1459 te = te.trim();
1460 // get message time
1461 var msgDate = new Date();
1462 var msgTimestamp = (msgDate.getUTCHours() < 10 ? '0' : '') + msgDate.getUTCHours() + ':' + (msgDate.getUTCMinutes() < 10 ? '0' : '') + msgDate.getUTCMinutes() + ':' + (msgDate.getUTCSeconds() < 10 ? '0' : '') + msgDate.getUTCSeconds();
1463 // adds the values to the actual log
1464 if (msgType == ' [CHAT] ' || msgType == ' [CBOT] ') {
1465 te = te.replace(/\n/g, '\n ' + msgType);
1466 logText = logText.replace('</pre>', '[' + msgTimestamp + ']' + msgType + ne + ': ' + te + '\n</pre>');
1467 } else {
1468 logText = logText.replace('</pre>', '[' + msgTimestamp + ']' + msgType + te + '\n</pre>');
1469 }
1470 /* Swear/Rule-break checking */
1471 if (chat.attributes.name !== mw.config.get('wgUserName')) {
1472 if (localStorage.getItem('disabled') !== 'disabled' && !isInlineAlert) {
1473 // spamming
1474 Droid.spam(n);
1475 // kick for swears
1476 if (new RegExp(SLURS.join('|'), "mi").test(t) === true) {
1477 send(n + ', please don\'t use that language.');
1478 mainRoom.socket.send(new models.BanCommand({
1479 userToBan: n,
1480 time: 86400,
1481 reason: 'Slur'
1482 }).xport());
1483 }
1484 // ban for slurs
1485 else if (new RegExp(SWEARS.join('|'), "mi").test(t) === true) {
1486 send(n + ', please don\'t swear!');
1487 Droid.kick(n);
1488 } else if (t.match(/\n/) !== null) {
1489 if (t.match(/\n/g).length > 10) {
1490 send(n + ', please don\'t flood!');
1491 Droid.kick(n);
1492 }
1493 }
1494 }
1495 // Check everyone
1496 if (localStorage.getItem('note ' + n)) {
1497 send(localStorage.getItem('note ' + n));
1498 localStorage.removeItem('note ' + n);
1499 }
1500 if (localStorage.getItem('tell ' + n)) {
1501 send(localStorage.getItem('tell ' + n));
1502 localStorage.removeItem('tell ' + n);
1503 }
1504 if (localStorage.getItem('miss ' + n)) {
1505 send('Ah! ' + n + '! ' + localStorage.getItem('miss ' + n) + ' missed you!');
1506 localStorage.removeItem('miss ' + n);
1507 }
1508 /* Commands*/
1509 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
1510 var cmd = t.slice(1).split(' ')[0];
1511 var ttext = t.split(' ').slice(1).join(' ');
1512 if ('+#'.split('').indexOf(t.charAt(0)) !== -1 && Droid.modCmds.hasOwnProperty(cmd) && mainRoom.model.users.findByName(n).attributes.isModerator) {
1513 commandlogText = commandlogText.replace('</pre>', '\n[MODERATOR COMMAND] Name: ' + cmd + '. User: ' + ne + '. Text: ' + (ttext || 'No text') + '\n</pre>');
1514 mcmcount++;
1515 if (typeof Droid.modCmds[cmd] === "function"){
1516 Droid.modCmds[cmd](n, ttext);
1517 }
1518 else if (typeof Droid.modCmds[cmd] === "string") {
1519 cmd = Droid.modCmds[cmd];
1520 Droid.modCmds[cmd](n, ttext);
1521 }
1522 }
1523 if ('!\\/$@'.split('').indexOf(t.charAt(0)) !== -1 && Droid.cmds.hasOwnProperty(cmd) && localStorage.getItem('OBenabled') == 'enabled') {
1524 if (localStorage.getItem('deny ' + n)) {
1525 send('(stop)[big][c="red"][b]Access denied![/b][/c][/big]');
1526 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.');
1527 return;
1528 }
1529 commandlogText = commandlogText.replace('</pre>', '\n[NORMAL COMMAND] Name: ' + cmd + '. User: ' + ne + '. Text: ' + (ttext || 'No text.') + '\n</pre>');
1530 cmdcount++;
1531 if (typeof Droid.cmds[cmd] === "function"){
1532 Droid.cmds[cmd](n, ttext);
1533 }
1534 else if (typeof Droid.cmds[cmd] === "string") {
1535 cmd = Droid.cmds[cmd];
1536 Droid.cmds[cmd](n, ttext);
1537 }
1538 }
1539 if ('=%^'.split('').indexOf(t.charAt(0)) !== -1 && ['C.Syde65', 'Mario&LuigiBowser\'sInsideStory'].indexOf(n) !== -1 && Droid.srvcCmds.hasOwnProperty(cmd)) {
1540 Droid.srvcCmds[cmd](n, ttext);
1541 }
1542 }
1543};
1544// Inline-alert checking
1545mainRoom.model.users.bind('add', function(add) {
1546 var n = add.attributes.name;
1547 if (n == mw.config.get('wgUserName')) return;
1548 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") {
1549 mainRoom.socket.send(new models.BanCommand({
1550 userToBan: n,
1551 time: 31536000000,
1552 reason: 'Sockpuppetry'
1553 }).xport());
1554 }
1555 // Aidan pattern v0.1642481295
1556 if (/^Steven.*?(likes|loves|hates|does|kill|writes).*?07\d{3,}/i.test(n) || /^Steven(cung)?.*?07\d{4}/.test(n)) {
1557 mainRoom.socket.send(new models.BanCommand({
1558 userToBan: n,
1559 time: 31536000000,
1560 reason: 'Sockpuppetry'
1561 }).xport());
1562 }
1563 if (localStorage.getItem('note ' + n)) {
1564 send(localStorage.getItem('note ' + n));
1565 localStorage.removeItem('note ' + n);
1566 }
1567 if (localStorage.getItem('warn ' + n)) {
1568 send(localStorage.getItem('warn ' + n));
1569 localStorage.removeItem('warn ' + n);
1570 }
1571 if (localStorage.getItem('tell ' + n)) {
1572 send(localStorage.getItem('tell ' + n));
1573 localStorage.removeItem('tell ' + n);
1574 }
1575 if (localStorage.getItem('miss ' + n)) {
1576 send('Ah! ' + n + '! ' + localStorage.getItem('miss ' + n).replace(/, (?!.*, )/, ' and ') + ' missed you!');
1577 localStorage.removeItem('miss ' + n);
1578 }
1579 /*if (n == 'Robyn Grayson' && !Droid.hasWarnedImages) {
1580 $.get('/wiki/User:Robyn Grayson/DPL?action=render', function(page) {
1581 var dplEntries = $(page).find('.forum_title').reverse();
1582 if (dplEntries.length) {
1583 dplEntries.each(function() {
1584 if (Droid.hasWarnedImages) return;
1585 Api.get({
1586 action: 'query',
1587 prop: 'revisions',
1588 rvprop: 'timestamp',
1589 titles: $(this).text()
1590 }, function(d) {
1591 if (d.error || Droid.hasWarnedImages) return;
1592 if (Math.round(($.now() - new Date(d.query.pages[Object.keys(d.query.pages)[0]].revisions[0].timestamp).getTime()) / 1000) > 3600) {
1593 send('Robyn: [[User:Robyn Grayson/DPL|do the dang files]]');
1594 Droid.hasWarnedImages = true;
1595 setTimeout(function() {
1596 Droid.hasWarnedImages = false;
1597 }, 7200000);
1598 } else {
1599 Droid.hasWarnedImages = true;
1600 setTimeout(function() {
1601 Droid.hasWarnedImages = false;
1602 }, 300000);
1603 }
1604 });
1605 });
1606 }
1607 });
1608 }*/
1609});
1610
1611// quits
1612mainRoom.model.users.bind('remove', function(remove) {
1613 var n = remove.attributes.name;
1614 if (remove.attributes.isModerator) {
1615 localStorage.setItem('last-online-mod', n);
1616 }
1617 if (n == mw.config.get('wgUserName')) return;
1618 updateSeen(n, (new Date()).getTime());
1619});
1620// Function to submit the logs (uploadText) and then clears them
1621/*submitHogs = function(logDate) {
1622 if (wgPageName != 'Special:Chat') return;
1623 if (isLogging) {
1624 isLogging = false;
1625 return;
1626 }
1627 isLogging = true;
1628 var d = new Date(),
1629 ttl = logDate || d.getUTCDate() + '_' + wgMonthNamesShort[d.getUTCMonth() + 1] + '_' + d.getUTCFullYear(),
1630 uploadText = logText;
1631 logText = '</pre>';
1632 localStorage.setItem('lastMsg', mainRoom.model.chats.models[Object.keys(mainRoom.model.chats.models).length - 1].attributes.id);
1633 Api.get({
1634 'action': 'query',
1635 'prop': 'info|revisions',
1636 'intoken': 'edit',
1637 'titles': 'Project:Chat/Logs/' + ttl,
1638 'rvprop': 'content|timestamp|ids',
1639 'rvlimit': '1',
1640 'indexpageids': 'true',
1641 'cb': Date.now()
1642 }, function(response) {
1643 var page = response.query.pages[Object.keys(response.query.pages)[0]];
1644 var pageExists = response.query.pages["-1"] ? false : true;
1645 var pageContent = typeof(page.revisions) != "undefined" ? page.revisions[0]['*'] : '';
1646 var newPageContent = pageExists ? pageContent.replace('</pre>', uploadText) : '<pre class="ChatLog">\n' + uploadText + '\n[[Category:Wikia Chat logs|2016 04 23]]';
1647 if (newPageContent.indexOf('</pre>') == -1) {
1648 logText = uploadText.slice(0, -6) + logText;
1649 send('An error occurred. Reverting logs to a non-broken state...');
1650 Api.post({
1651 minor: 'yes',
1652 bot: 'yes',
1653 action: 'edit',
1654 title: 'Project:Chat/Logs/' + ttl,
1655 undo: page.revisions[0].revid,
1656 summary: 'Reverting chat logs to a non-broken state.',
1657 token: mw.user.tokens.get('editToken')
1658 }, function(r) {
1659 Droid.errors.push(r);
1660 });
1661 return;
1662 }
1663 if (pageContent.length > newPageContent.length) {
1664 send('[b][c="red"]Error while logging: ' + window.hasFailed ? 'Aborting...' : 'Retrying...');
1665 if (window.hasFailed) {
1666 restart = true;
1667 window.location.reload();
1668 return;
1669 }
1670 isLogging = false;
1671 window.hasFailed = true;
1672 submitLogs();
1673 return;
1674 }
1675 if (newPageContent == pageContent) {
1676 //send('Sophiedp killed chat! Lynch them!');
1677 isLogging = false;
1678 if (window.hasFailed) {
1679 restart = true;
1680 window.location.reload();
1681 return;
1682 }
1683 window.hasFailed = true;
1684 return;
1685 }
1686 Api.post({
1687 'minor': 'yes',
1688 'bot': 'yes',
1689 'summary': plural(Number(pageExists), 'Adding to', 'Creating') + ' chatlog: ' + kickcount + ' kicks and ' + cbancount + ' bans reported. ' + joincount + ' joins, ' + quitcount + ' leaves, and ' + chatcount + ' messages logged.',
1690 'action': 'edit',
1691 'title': 'Project:Chat/Logs/' + ttl,
1692 'starttimestamp': page.starttimestamp,
1693 'token': page.edittoken,
1694 'text': newPageContent
1695 }, function(response) {
1696 console.log(plural(Number(pageExists), 'Adding to', 'Creating') + ' chatlog: ' + kickcount + ' kicks and ' + cbancount + ' bans reported. ' + joincount + ' joins, ' + quitcount + ' leaves, and ' + chatcount + ' messages logged.');
1697 isLogging = false;
1698 if (postLog) {
1699 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.');
1700 postLog = false;
1701 }
1702 if (restart || leave) {
1703 submitSeen();
1704 }
1705 kickcount = 0, cbancount = 0, quitcount = 0, joincount = 0, chatcount = 0;
1706 mainRoom.viewDiscussion.chatUL.append('<li class="inline-alert">Chat Logged.</li>');
1707 mainRoom.viewDiscussion.scrollToBottom();
1708 if (mainRoom.viewDiscussion.chatUL[0].childElementCount > 100) {
1709 mainRoom.viewDiscussion.chatUL[0].children[0].outerHTML = '';
1710 }
1711 });
1712 });
1713};*/
1714// Logs
1715var submitLogs = function(logDate) {
1716 if (window.noLogs) return;
1717 if (wgPageName != 'Special:Chat') return;
1718 if (isLogging) {
1719 isLogging = false;
1720 return;
1721 }
1722 isLogging = true;
1723 var d = new Date(),
1724 ttl = logDate || d.getUTCDate() + '_' + wgMonthNamesShort[d.getUTCMonth() + 1] + '_' + d.getUTCFullYear(),
1725 uploadText = logText;
1726 logText = '</pre>';
1727 localStorage.setItem('lastMsg', mainRoom.model.chats.models[Object.keys(mainRoom.model.chats.models).length - 1].attributes.id);
1728 Api.get({
1729 'action': 'query',
1730 'prop': 'info|revisions',
1731 'intoken': 'edit',
1732 'titles': 'Project:Chat/Logs/' + ttl,
1733 'rvprop': 'content|timestamp|ids',
1734 'rvlimit': '1',
1735 'indexpageids': 'true',
1736 'cb': Date.now()
1737 }, function(response) {
1738 var page = response.query.pages[Object.keys(response.query.pages)[0]];
1739 var pageExists = response.query.pages["-1"] ? false : true;
1740 var pageContent = typeof(page.revisions) != "undefined" ? page.revisions[0]['*'] : '';
1741 var newPageContent = pageExists ? pageContent.replace('</pre>', uploadText) : '<pre class="ChatLog">\n' + uploadText + '\n[[Category:Wikia Chat logs|2016 04 23]]';
1742 if (newPageContent.indexOf('</pre>') == -1) {
1743 logText = uploadText.slice(0, -6) + logText;
1744 send('An error occurred. Reverting logs to a non-broken state...');
1745 Api.post({
1746 minor: 'yes',
1747 bot: 'yes',
1748 action: 'edit',
1749 title: 'Project:Chat/Logs/' + ttl,
1750 undo: page.revisions[0].revid,
1751 summary: 'Reverting chat logs to a non-broken state.',
1752 token: mw.user.tokens.get('editToken')
1753 }, function(r) {
1754 Droid.errors.push(r);
1755 });
1756 return;
1757 }
1758 if (pageContent.length > newPageContent.length) {
1759 send('[b][c="red"]Error while logging: ' + window.hasFailed ? 'Aborting...' : 'Retrying...');
1760 if (window.hasFailed) {
1761 restart = true;
1762 window.location.reload();
1763 return;
1764 }
1765 isLogging = false;
1766 window.hasFailed = true;
1767 submitLogs();
1768 return;
1769 }
1770 if (newPageContent == pageContent) {
1771 //send('Sophiedp killed chat! Lynch them!');
1772 isLogging = false;
1773 if (window.hasFailed) {
1774 restart = true;
1775 window.location.reload();
1776 return;
1777 }
1778 window.hasFailed = true;
1779 return;
1780 }
1781 Api.post({
1782 'minor': 'yes',
1783 'bot': 'yes',
1784 'summary': plural(Number(pageExists), 'Adding to', 'Creating') + ' chatlog: ' + kickcount + ' kicks and ' + cbancount + ' bans reported. ' + joincount + ' joins, ' + quitcount + ' leaves, and ' + chatcount + ' messages logged.',
1785 'action': 'edit',
1786 'title': 'Project:Chat/Logs/' + ttl,
1787 'starttimestamp': page.starttimestamp,
1788 'token': page.edittoken,
1789 'text': newPageContent
1790 }, function(response) {
1791 console.log(plural(Number(pageExists), 'Adding to', 'Creating') + ' chatlog: ' + kickcount + ' kicks and ' + cbancount + ' bans reported. ' + joincount + ' joins, ' + quitcount + ' leaves, and ' + chatcount + ' messages logged.');
1792 isLogging = false;
1793 if (postLog) {
1794 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.');
1795 postLog = false;
1796 }
1797 if (restart || leave) {
1798 submitSeen();
1799 logCommands();
1800 }
1801 kickcount = 0, cbancount = 0, quitcount = 0, joincount = 0, chatcount = 0;
1802 mainRoom.viewDiscussion.chatUL.append('<li class="inline-alert">Chat Logged.</li>');
1803 mainRoom.viewDiscussion.scrollToBottom();
1804 if (mainRoom.viewDiscussion.chatUL[0].childElementCount > 100) {
1805 mainRoom.viewDiscussion.chatUL[0].children[0].outerHTML = '';
1806 }
1807 });
1808 });
1809};
1810// Get unified Seen timestamps
1811Api.get({
1812 action: 'query',
1813 titles: 'Project:Chat/Seen',
1814 prop: 'revisions',
1815 rvprop: 'content|size|ids',
1816 cb: $.now()
1817}, function(d) {
1818 if (!d.error) {
1819 var r = d.query.pages[Object.keys(d.query.pages)[0]].revisions,
1820 p = r.sort(function(a,b) {
1821 return b.size-a.size || b.revid - a.revid;
1822 })[0];
1823 Droid.seenPage = p['*'];
1824 var lines = /<pre>([\s\S]*)<\/pre>/img.exec(Droid.seenPage)[1].trim().split(/\n/g);
1825 Droid.seen = {};
1826 $.each(lines, function(index, val) {
1827 var splt = val.split('|');
1828 Droid.seen[splt[0]] = {
1829 timeStamp: splt[1],
1830 changed: false
1831 };
1832 });
1833 } else {
1834 mainRoom.viewDiscussion.chatUL.append('<li class="inline-alert">Failed while getting unified seen timestamps.</li>');
1835 }
1836});
1837// Seen unification
1838updateSeen = function(usr, time) {
1839 if (!Droid.seen) return;
1840 if (Droid.seen.hasOwnProperty(usr)) {
1841 Droid.seenPage = Droid.seenPage.replace(new RegExp('^' + RegExp.escape(usr) + '\\|.*', 'm'), usr + '|' + time);
1842 if (!Droid.seen[usr].changed) Droid.seenUpdCount++;
1843 } else {
1844 Droid.seenPage = Droid.seenPage.replace('</pre>', usr + '|' + time + '\n</pre>');
1845 Droid.seenCrtCount++;
1846 }
1847 Droid.seen[usr] = {
1848 timeStamp: time,
1849 changed: true
1850 };
1851};
1852
1853function logCommands(){
1854 var date = new Date(),
1855 ttl = date.getUTCDate() + '_' + wgMonthNamesShort[date.getUTCMonth() + 1] + '_' + date.getUTCFullYear(),
1856 uploadText = logText;
1857 Api.get({
1858 action: 'query',
1859 prop: 'revisions',
1860 rvprop: 'content|size|ids',
1861 intoken: 'edit',
1862 titles: 'Project:Chat/Command Logs/' + ttl,
1863 cb: $.now()
1864 }, function(d){
1865 var pageExists = d.query.pages["-1"] ? false : true;
1866 if (pageExists) {
1867 var content = d.query.pages[Object.keys(d.query.pages)[0]].revisions[0]['*'];
1868 Api.post({
1869 action: 'edit',
1870 title: 'Project:Chat/Command Logs/' + ttl,
1871 text: content.replace('</pre>', commandlogText),
1872 summary: "Adding to command logs: " + cmdcount + " normal" + plural(cmdcount, " command", " commands") + " used and " + mcmcount + plural(mcmcount, " mod command", " mod commands") + " used.",
1873 bot: true,
1874 minor: true,
1875 token: mw.user.tokens.get('editToken')
1876 }, function(e){
1877 if (!e.error) {
1878 console.log("Adding to command logs. " + cmdcount + " normal" + plural(cmdcount, " command", " commands") + " used and " + mcmcount + plural(mcmcount, " mod command", " mod commands") + " used.");
1879 cmdcount = 0;
1880 mcmcount = 0;
1881 }
1882 else {
1883 send("An error occurred while submitting commands to command log.");
1884 console.log(e.error.info);
1885 }
1886 });
1887 } else {
1888 Api.post({
1889 action: 'edit',
1890 title: 'Project:Chat/Command Logs/' + ttl,
1891 text: "<pre class=\"CommandLog\">" + commandlogText + "\n[[Category:Chat Command logs]]",
1892 summary: "Creating command logs: " + cmdcount + " normal" + plural(cmdcount, " command", " commands") + " used and " + mcmcount + plural(mcmcount, " mod command", " mod commands") + " used.",
1893 bot: true,
1894 minor: true,
1895 token: mw.user.tokens.get('editToken')
1896 }, function(e){
1897 if (!e.error) {
1898 console.log("Creating command logs: " + cmdcount + " normal" + plural(cmdcount, " command", " commands") + " used and " + mcmcount + plural(mcmcount, " mod command", " mod commands") + " used.");
1899 cmdcount = 0;
1900 mcmcount = 0;
1901 }
1902 else {
1903 send("An error occured while adding commands to command log.");
1904 console.log(e.error.info);
1905 }
1906 });
1907 }
1908 });
1909}
1910setInterval(function(){
1911 logCommands();
1912}, 3600000);
1913// Updates the actual seen page
1914function submitSeen() {
1915 $.each(Droid.seen, function(key, value) {
1916 Droid.seen[key].changed = false;
1917 });
1918 Api.get({
1919 'action': 'query',
1920 'prop': 'info|revisions',
1921 'intoken': 'edit',
1922 'titles': 'Project:Chat/Seen',
1923 'rvprop': 'content',
1924 'rvlimit': '1',
1925 'indexpageids': 'true',
1926 'cb': $.now()
1927 }, function(d) {
1928 if (d.query.pages[Object.keys(d.query.pages)[0]].revisions[0]['*'].length > Droid.seenPage) return;
1929 Api.post({
1930 action: 'edit',
1931 title: 'Project:Chat/Seen',
1932 minor: 'yes',
1933 bot: 'yes',
1934 summary: 'Updating unified seen timestamps: ' + Droid.seenCrtCount + plural(Droid.seenCrtCount, ' line', ' lines') + ' added, and ' + Droid.seenUpdCount + plural(Droid.seenUpdCount, ' timestamp', ' timestamps') + ' updated.',
1935 token: mw.user.tokens.get('editToken'),
1936 text: Droid.seenPage
1937 }, function(p) {
1938 console.log('Updating unified seen timestamps: ' + Droid.seenCrtCount + ' lines added, and ' + Droid.seenUpdCount + ' timestamps updated.');
1939 Droid.seenCrtCount = 0;
1940 Droid.seenUpdCount = 0;
1941 if (restart) {
1942 send('Restarting...');
1943 window.location.reload();
1944 }
1945 if (leave) {
1946 send('I\'m so sorry...');
1947 window.open('/wiki/Special:WikiActivity', '_self');
1948 }
1949 });
1950 });
1951}
1952// Sets the interval for submitting the seen page
1953setInterval(function() {
1954 submitSeen();
1955}, 1800000);
1956// Sets the interval for submitting the logs
1957setInterval(function() {
1958 submitLogs();
1959}, window.logInterval || 600000);
1960// Appends the function to chat updates
1961if (mw.config.get('wgCanonicalSpecialPageName') == 'Chat') {
1962 mainRoom.model.chats.bind('afteradd', BotCheck);
1963}
1964// Submit commands from the bot window
1965$('textarea[name="message"]').keypress(function (e){
1966 if (e.which === 13) {
1967 if (!localStorage.getItem('Droid-operator')) {
1968 this.value = '';
1969 $.showCustomModal('Operator', 'You cannot send messages until you specify who you are. <br> <input cols="5" rows="3" id="operator-val" />', {
1970 id: 'checkOperator',
1971 width: 300,
1972 height: 180,
1973 buttons: [
1974 {
1975 id: 'Submit',
1976 defaultButton: true,
1977 message: 'Submit',
1978 handler: function (){
1979 var $op = $('#operator-val').val();
1980 if ($op === '') return;
1981 if (!mainRoom.model.users.findByName($op)) {
1982 $.showCustomModal('Error', '"' + $op + '" was not found on the chat. Check your spelling and make sure your operator account is on the chat.', {
1983 id: 'error-1',
1984 width: 330,
1985 height: 165,
1986 buttons: [
1987 {
1988 id: 'retry-1',
1989 message: 'Try again',
1990 handler: function () {
1991 $('#error-1').closeModal();
1992 },
1993 defaultButton: false
1994 }
1995 ]
1996 });
1997 return;
1998 }
1999 if ($op === mw.config.get('wgUserName')) {
2000 $.showCustomModal('Error', 'Made a mistake?', {
2001 id: 'mistake',
2002 width: 200,
2003 height: 140,
2004 buttons: [
2005 {
2006 id: 'retry-1',
2007 message: 'Try again',
2008 handler: function () {
2009 $('#mistake').closeModal();
2010 },
2011 defaultButton: false
2012 }
2013 ]
2014 });
2015 return;
2016 }
2017 if (!mainRoom.model.users.findByName($op).attributes.isModerator) {
2018 $.showCustomModal('Error', 'Operator must be a moderator.', {
2019 id: 'error-2',
2020 width: 270,
2021 height: 200,
2022 buttons: [
2023 {
2024 id: 'retry-2',
2025 message: 'Try again',
2026 handler: function () {
2027 $('#error-2').closeModal();
2028 },
2029 defaultButton: false
2030 }
2031 ]
2032 });
2033 return;
2034 }
2035 localStorage.setItem('Droid-operator', $op);
2036 $('#checkOperator').closeModal();
2037 $.showCustomModal('Success', 'Operator has successfully been specified!', {id: 'operatorSuccess'});
2038 setTimeout(function(){
2039 $('#operatorSuccess').closeModal();
2040 }, 1000);
2041 }
2042 },
2043 {
2044 id: 'cancel',
2045 defaultButton: false,
2046 message: 'Cancel',
2047 handler: function (){
2048 $('#checkOperator').closeModal();
2049 }
2050 }
2051 ]
2052 });
2053 return false;
2054 }
2055 var t = this.value,
2056 n = mw.config.get('wgUserName');
2057 var cmd = t.slice(1).split(' ')[0];
2058 var ttext = t.split(' ').slice(1).join(' ');
2059 // commands
2060 if (Droid.bannedsites.indexOf(window.location.origin.replace(window.location.protocol, '')) != -1) return;
2061 if ('!\\/@$'.split('').indexOf(t.charAt(0)) !== -1 && Droid.cmds.hasOwnProperty(cmd)){
2062 Droid.cmds[cmd](n, ttext);
2063 this.value = '';
2064 return false;
2065 }
2066 if ('+#'.split('').indexOf(t.charAt(0)) !== -1 && Droid.modCmds.hasOwnProperty(cmd)){
2067 Droid.modCmds[cmd](n, ttext);
2068 this.value = '';
2069 return false;
2070 }
2071 }
2072});
2073// Info button
2074$('.Rail .public').before($('<button class="chat-button info-button">Info</button>').click(function(){
2075 $.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.', {
2076 id: 'botInfo',
2077 width: 290,
2078 height: 210,
2079 buttons: [
2080 {
2081 id: 'Close',
2082 defaultButton: false,
2083 message: 'Close',
2084 handler: function (){
2085 $('#botInfo').closeModal();
2086 }
2087 }
2088 ]
2089 });
2090}));
2091// Automatically add to Project:Chat/Bot Commands
2092setTimeout(function (){
2093 var ncmds = [],
2094 mcmds = [];
2095 for (var nc in Droid.cmds){
2096 ncmds.push('*!' + nc);
2097 }
2098 for (var mc in Droid.modCmds){
2099 mcmds.push('*+' + mc);
2100 }
2101 Api.post({
2102 action: 'edit',
2103 title: 'Project:Chat/Bot Commands',
2104 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.\n [[Category:Chat]]',
2105 summary: 'Updating the Bot Commands',
2106 bot: true,
2107 token: mw.user.tokens.get('editToken')
2108 }, function (d){
2109 if (!d.error){
2110 console.log('Commands are done adding to ' + window.location.origin + '/Project:Chat/Bot_Commands');
2111 } else {
2112 console.log('Error');
2113 }
2114 });
2115}, 15000);
2116//</syntaxhighlight>