· 8 years ago · Dec 23, 2017, 08:18 PM
1"use strict";
2// load discordie object
3const discordie = require("discordie");
4const twitch = require('twitch-get-stream')('jm6wh6ctwjg97ljlffp8ds062uzkd7');
5const fs=require("fs"), ini=require("ini");
6// create the discord client obj
7const client = new discordie({autoReconnect:true});
8const events = discordie.Events;
9// Constants
10const BLACKBIRD="311409240327585802";
11const GENERAL="304082726019923978";
12
13// Classes
14
15class User {
16 constructor(name, discriminator){
17 this.name=name;
18 this.discriminator=discriminator;
19 this.swears=0;
20 this.slaps=0;
21 this.zeal=0;
22 this.toilet=0;
23
24 this.actions=0;
25 this.questions=0;
26 this.exclamations=0;
27 this.elvia=0;
28
29 this.lines=0;
30 this.secretWord=0;
31 this.secretWordAdd=0;
32
33 this.todayActions=0;
34 this.todayViolence=0;
35 this.todayWarnings=0;
36 this.totalWarnings=0;
37
38 this.todayWasWarned=false;
39 }
40}
41
42// Images
43
44var waifus=[
45 "bunny.jpg",
46 "cat.jpg",
47 "cat2.jpg",
48 "cat3.jpg",
49 "chicken.jpg",
50 "chipmunk.jpg",
51 "dogs.png",
52 "mouse.jpg",
53 "squirrel.png"
54];
55
56var cats=[
57 "cat1.jpg",
58 "cat2.jpg",
59 "cat3.jpg",
60 "cat4.jpg",
61 "cat5.jpg",
62 "cat6.jpg",
63 "cat7.jpg",
64 "cat8.jpg",
65 "cat9.jpg",
66]
67
68// Banned words, and stuff like that
69var banned=[
70 /*["whore", "Potty mouth!", "SKITTY"],
71 ["slut", "Potty mouth!", "SKITTY"],
72 ["cunt", "Potty mouth!", "SKITTY"],
73 ["nigger", "wow r00d", "SKITTY"],
74 ["fuck", "Potty mouth!", "SKITTY"],
75 ["fck", "Stop evading the censor!", "SKITTY"],
76 ["fuk", "Stop evading the censor!", "SKITTY"],
77 ["fuq", "Stop evading the censor!", "SKITTY"],
78 ["pussbag", "Potty mouth!", "DELCATTY"],
79 ["phuck", "Stop evading the censor!", "SKITTY"],
80 ["jacking off", "Get a room!", "SKITTY"],
81 ["elvia", "Bad!", "GUMMY'S FACE"],*/
82 //["eric", "O3O", "GUMMY'S FACE"] plase don't un-comment this one, i was causing false positive problems.
83 //["gummy x dragonite", "xnx", "wut"],
84 //["dragonite x gummy", "xnx", "no"]
85]
86
87var violentVerbs=[
88 "kicks",
89 "slaps",
90 "hits",
91 "smacks",
92 "destroys",
93 "kills",
94 "rapes",
95 "punches",
96 "whacks",
97]
98
99var hotDateResponses=[
100 "1999, when Lavos burns the world.",
101 "7.5 billion AD, when the Sun engulfs the Earth",
102]
103
104var lastDateResponses=[
105 "10^98 AD, or whenever the heat death of the universe is currently forecasted to happen",
106]
107
108// These get cleared every once in a while
109var deletionQueue=[];
110var deletionQueueLong=[];
111
112// Load up the stats
113var stats=ini.parse(fs.readFileSync('stats.ini', 'utf-8'));
114var statsGeneral=ini.parse(fs.readFileSync('misc.ini', 'utf-8'));
115var userTable={};
116var totalBotCommands=0;
117var gummyCommandsLast5Minutes=0;
118var totalCensoredLines=0;
119utilityCreateUserTable();
120utilityLoadBotStats();
121
122// assume the stream is online until proven otherwise, that way it doesn't keep
123// notifying everyone if it crashes or restarts due to changes
124var streamState=true;
125var streamHasNotifiedDate=null;
126
127// There are some things that need doing on a regular basis
128var timer15 = setInterval(function(){
129 twitchGetIsLive(null);
130 twitchSendStatusMessage();
131 censorClearDeletionQueue();
132 botCanSpeak=true;
133}, 15000);
134
135var timer60 = setInterval(function(){
136 //censorClearDeletionQueueLong();
137 utilitySaveStats();
138 utilitySaveBotStats();
139 botCanSendUserCommands=true;
140}, 60000);
141
142var timer5min = setInterval(function(){
143 botCanYellAtCandy=true;
144 for (var user in userTable){
145 userTable[user].todayWasWarned=false;
146 }
147 var now=new Date();
148 if (now.getHours()==4&&now.getMinutes()<10){
149 for (var string in userTable){
150 var user=userTable[string];
151 user.todayActions=0;
152 user.todayViolence=0;
153 user.todayWarnings=0;
154 if (now.getDay()==0){
155 user.totalWarnings--;
156 if (user.totalWarnings<0){
157 user.totalWarnings=0;
158 }
159 }
160 }
161 }
162 gummyCommandsLast5Minutes--;
163 if (gummyCommandsLast5Minutes<0){
164 gummyCommandsLast5Minutes=0;
165 }
166 fetchPinnedAuto(client.Channels.get(GENERAL));
167}, 300000);
168
169// extra stuff
170
171var myName="SuperSkarm";
172var myNick="Skarm";
173var botCanSendUserCommands=true;
174var botCanYellAtCandy=true;
175var botCanSpeak=true;
176var lastTenReactions=[];
177
178var DRAGONITE=null;
179
180// I still don't actually know what this is for?
181client.connect({
182token: "MzE5MjkxMDg2NTcwOTEzODA2.DA-zPQ._NYnKlrxK1jM6py2M9AXIxdX5wo"
183});
184
185// What happens when you first connect
186client.Dispatcher.on(events.GATEWAY_READY, e => {
187 console.log("Connected as " + client.User.username+" ("+myNick+"). Yippee!");
188 client.User.setGame("Type \"e!help\" !");
189 twitchGetIsLive(null);
190 twitchGetLastStreamDate();
191 censorLoadList();
192 DRAGONITE=client.Users.get("137336478291329024");
193});
194
195client.Dispatcher.on(events.MESSAGE_DELETE, e=> {
196 var string="";
197 if (e.message!=null){
198 if (e.message.channel!=client.Channels.get("344295609194250250")&&e.message.author!=client.User&&!e.message.author.bot){
199 if (e.message==null){
200 string="<message not cached>";
201 } else {
202 string=e.message.content+" by "+e.message.author.username;
203 }
204 fs.appendFile("deleted.txt", "Deleted: "+string+"\r\n", (err) => {
205 if (err){
206 throw err;
207 }
208 //client.Channels.get("344295609194250250").sendMessage(string+" was written to deleted.txt.");
209 });
210 }
211 }
212});
213
214client.Dispatcher.on(events.MESSAGE_REACTION_ADD, e=> {
215 if (e.emoji.name=="Upvote"){
216 if (e.message!=null&&e.message.channel_id==BLACKBIRD){
217 // This is horrible and i should feel horrible about writing it
218 if (lastTenReactions.length>=10){
219 lastTenReactions.shift();
220 }
221 lastTenReactions.push(e.message);
222 var count=0;
223 for (var i=0; i<lastTenReactions.length; i++){
224 if (lastTenReactions[i]==e.message){
225 count++;
226 }
227 }
228
229 if (count==3&&!e.message.pinned){
230 e.message.pin();
231 fetchPinnedSelf(e.message.channel);
232 }
233 }
234 }
235});
236
237client.Dispatcher.on(events.MESSAGE_UPDATE, e=> {
238 if (e.message!=null){
239 censor(e.message);
240 }
241});
242
243client.Dispatcher.on(events.MESSAGE_CREATE, e=> {
244 // don't do anything in PMs?
245 if (e.message.isPrivate){
246 return false;
247 }
248 var message=e.message.content.toLowerCase();
249 censor(e.message);
250 //utilitySaveLine(message);
251 // Help
252 if (!e.message.deleted){
253 if (message=="e!help"){
254 helpHelpHelp(e);
255 totalBotCommands++;
256 } else if (message=="e!help says"){
257 helpSays(e);
258 totalBotCommands++;
259 } else if (message=="e!help twitch"){
260 helpTwitch(e);
261 totalBotCommands++;
262 } else if (message=="e!help lol"){
263 helpLol(e);
264 totalBotCommands++;
265 } else if (message=="e!help misc"){
266 helpMisc(e);
267 totalBotCommands++;
268 /*} else if (message=="e!help pictures"){
269 helpPictures(e);
270 totalBotCommands++;*/
271 } else if (message=="e!help credits"){
272 helpCredits(e);
273 totalBotCommands++;
274 } else if (message=="e!help reactions"){
275 helpReactions(e);
276 totalBotCommands++;
277 } else if (message=="e!help mods"){
278 helpMods(e); // please
279 totalBotCommands++;
280 // Utilities
281 } else if (message=="e!size"){
282 utiliyLineCount(e);
283 totalBotCommands++;
284 } else if (message=="e!all"){
285 //utilityDumpServer(e);
286 e.message.channel.sendMessage("This has been turned off to preserve sanity. If you really need to use it, go bother Dragontie#7992 to turn it back on.");
287 //totalBotCommands++;
288 } else if (message=="e!stats"){
289 totalBotCommands++;
290 utilityStats(e);
291 } else if (message=="e!ping"){
292 totalBotCommands++;
293 utilityPing(e);
294 } else if (message.startsWith("e!hug")){
295 totalBotCommands++;
296 utilityHug(e);
297 } else if (message.startsWith("e!sandwich")){
298 totalBotCommands++;
299 utilitySandwich(e);
300 } else if (message.startsWith("e!bot")){
301 totalBotCommands++;
302 utilityBotStats(e);
303 } else if (message.startsWith("e!pinned")){
304 utilityPinned(e);
305 } else if (message.startsWith("e!game ")){
306 utilityGame(e);
307 // Quote
308 } else if (message.startsWith("e!says-add ")){
309 totalBotCommands++;
310 add(e.message);
311 } else if (message=="e!test"){
312 e.message.channel.sendMessage(e.message.author.username+" can submit messages: "+userHasKickingBoots(e.message.author, e.message.channel));
313 totalBotCommands++;
314 // Twitch
315 } else if (message=="e!live"){
316 twitchGetIsLive(e.message.channel);
317 totalBotCommands++;
318 // Pictures
319 /*} else if (message=="e!waifu"){
320 waifuSend(e.message.channel);
321 totalBotCommands++;
322 } else if (message=="e!cat"){
323 catSend(e.message.channel);
324 totalBotCommands++;*/
325 }
326 // Censor functions
327 else if (message.startsWith("e!censor")){
328 censorCommandSet(e.message);
329 }
330 // Lol
331 if (botCanSendUserCommands){
332 if (message=="e!will"){
333 annoyWill(e.message.channel);
334 totalBotCommands++;
335 botCanSendUserCommands=false;
336 } else if (message=="e!gummy"){
337 e.message.channel.sendMessage("Stop abusing the gummy commands à ² _à ² ");
338 totalBotCommands++;
339 botCanSendUserCommands=false;
340 gummyCommandsLast5Minutes++;
341 } else if (message=="e!gummy-b"){
342 e.message.channel.sendMessage("Stop abusing the gummy commands à ² _à ² ");
343 totalBotCommands++;
344 botCanSendUserCommands=false;
345 gummyCommandsLast5Minutes++;
346 } else if (message=="e!gummy-c"){
347 //if (gummyCommandsLast5Minutes<2){
348 //} else {
349 e.message.channel.sendMessage("Stop abusing the gummy commands à ² _à ² ");
350 //}
351 totalBotCommands++;
352 botCanSendUserCommands=false;
353 gummyCommandsLast5Minutes++;
354 } else if (message=="e!dragonite"){
355 e.message.channel.sendMessage("Go play outside, Dragonite.");
356 totalBotCommands++;
357 botCanSendUserCommands=false;
358 } else if (message=="e!dragonite-b"){
359 e.message.channel.sendMessage("Literally everybody but Dragonite is a baka.");
360 totalBotCommands++;
361 botCanSendUserCommands=false;
362 } else if (message=="e!ida"){
363 e.message.channel.sendMessage("She bloody hates sheep.");
364 totalBotCommands++;
365 botCanSendUserCommands=false;
366 } else if (message=="e!deci"){
367 annoyDeci(e.message.channel);
368 totalBotCommands++;
369 botCanSendUserCommands=false;
370 } else if (message=="e!candy"){
371 annoyCandyman(e.message.channel);
372 totalBotCommands++;
373 } else if (message=="e!candy-b"){
374 e.message.channel.sendMessage("#ThingsThatCandySaysThatPeopleShouldn'tTakeSeriously");
375 totalBotCommands++;
376 botCanSendUserCommands=false;
377 } else if (message=="e!rainy"){
378 e.message.channel.sendMessage("STOP SHOUTING!!!!!!!!!");
379 totalBotCommands++;
380 }
381
382 else if (message=="e!treason"){
383 //e.message.channel.sendMessage("à ² _à ² ");
384 e.message.channel.sendMessage("God damn it, Squid.");
385 totalBotCommands++;
386 botCanSendUserCommands=false;
387 }
388
389 else if (message=="e!back"){
390 e.message.channel.sendMessage("\"Back\" count: "+statsGeneral.everything.back);
391 totalBotCommands++;
392 botCanSendUserCommands=false;
393 }
394 }
395 // Literally everything else
396 statsWillOfD(e.message);
397 STATS(e.message);
398 if (!utilityMessageWasWrittenByMe(e.message)){
399 REACT(e.message);
400 } else if (messageAuthorEquals(e.message, "304073163669766158")){
401 if (Math.random()*100<25){
402 add(e.message);
403 }
404 }
405 }
406});
407
408/*
409 ********************
410 * Quotes *
411 ********************
412 */
413
414function add(message){
415 var msg=message.content.toLowerCase().replace("e!says-add ", "").replace(/\r?\n|\r/, " ");
416 for (var i=0; i<banned.length; i++){
417 if (msg.includes(banned[i][0].toLowerCase())){
418 message.channel.sendMessage("Please do not add profanity to the quote log. Thank.");
419 return false;
420 }
421 }
422 saveLine(message, "line.txt", msg);
423}
424
425// Checks to see if the user is allowed to submit messages to the bot
426function userHasKickingBoots(author, channel){
427 return author.can(discordie.Permissions.General.KICK_MEMBERS, channel);
428}
429
430// Send a random line
431function sendRandomLine(message){
432 sendRandomFileLine("line.txt", message.channel);
433}
434
435// Saves a line to the line file
436function saveLine(message, filename, string){
437 if (userHasKickingBoots(message.author, message.channel)){
438 fs.appendFile(filename, string+"\r\n", (err) => {
439 if (err){
440 throw err;
441 }
442 console.log(string+" was written to "+filename+".");
443 });
444 message.channel.sendMessage("Added!");
445 } else {
446 message.channel.sendMessage(message.author.username+": you don't have permission to add quotes. Sorry.");
447 }
448}
449
450// Pulls a random line from the text file
451function sendRandomFileLine(filename, channel){
452 var lines;
453 fs.readFile(filename, function(err, data){
454 if(err){
455 channel.sendMessage("No quotes for that user!");
456 } else {
457 lines = data.toString().split('\n');
458 var line="";
459 do {
460 line=lines[Math.floor(Math.random()*lines.length)];
461 } while (line=="");
462 channel.sendMessage(line);
463 }
464 })
465}
466
467/*
468 ********************
469 * Twitch Stuff *
470 ********************
471 */
472
473// Checks if Zeal is online. If he's gone online, it sends an announcement.
474function twitchSendStatusMessage(){
475 if (streamState){
476 if (streamHasNotifiedDate==null||twitch12HoursElapsed(new Date(), streamHasNotifiedDate)){
477 streamHasNotifiedDate=new Date();
478 fs.writeFile("./stuff/streamDate.txt", streamHasNotifiedDate);
479 var channel=client.Channels.get("305488106050813954");
480 if (channel!=null){
481 channel.sendMessage("@everyone Zeal has gone online! \n https://www.twitch.tv/kingofzeal");
482 }
483 }
484 }
485}
486
487function twitch12HoursElapsed(newDate, oldDate){
488 var seconds=(newDate-oldDate)/1000;
489 var minutes=seconds/60;
490 var hours=minutes/60;
491 return (hours>12);
492}
493
494// I'm sure there's a better way to do this.
495function twitchGetIsLive(channel){
496 twitch.get('kingofzeal').then(function(streams) {
497 if (channel!=null){
498 channel.sendMessage("Zeal is live!\n https://www.twitch.tv/kingofzeal");
499 }
500 streamState=true;
501 }).catch(function(error) {
502 if (channel!=null){
503 channel.sendMessage("Zeal is not live /:");
504 }
505 streamState=false;
506 });
507 // can't simply return a value here because this is an asyncrhonous function ლ(à ² ç›Šà ² áƒš)
508}
509
510function twitchGetLastStreamDate(){
511 fs.readFile("./stuff/streamDate.txt", function(err, data){
512 if(err){
513
514 } else {
515 var date = data.toString().trim();
516 if (date===""){
517 console.log("Date file is . . . empty?");
518 streamHasNotifiedDate=null;
519 } else {
520 streamHasNotifiedDate=new Date(date);
521 }
522 }
523 })
524}
525
526/*
527 ********************
528 * Lol Stuff *
529 ********************
530 */
531
532// Stuff he says.
533function annoyDragonite(channel){
534 var responses=["You rang?"];
535 // add more responses down here
536 channel.sendMessage(responses[Math.floor(Math.random()*responses.length)]);
537}
538
539// Stats printout.
540function annoyWill(channel){
541 var lol=stats.WillOfD.lol;
542 var xd=stats.WillOfD.xd;
543 var w=stats.WillOfD.w;
544 var messages=stats.WillOfD.messages;
545 if (messages==0){
546 channel.sendMessage("\\*\\*\\*Will has not recorded any messages yet.\\*\\*\\*");
547 } else {
548 channel.sendMessage("```Percentage of WillOfD's messages that contain \"lol:\""+(100*lol/messages).toFixed(2)+"%\n"+
549 "Percentage of WillOfD's messages that contain \"XD:\" "+(100*xd/messages).toFixed(2)+"%\n"+
550 "Percentage of WillOfD's messages that contain \"^w^:\" "+(100*w/messages).toFixed(2)+"%\n\n"+
551 "WillOfD's total messages: "+messages+"```");
552 }
553}
554
555// Various salts.
556function annoyDeci(channel){
557 var responses=["2 Na + Cl(2) → 2 NaCl",
558 "NaOH (aq) + HCl (aq) → NaCl(aq) + H(2)O (l)"];
559 channel.sendMessage(responses[Math.floor(Math.random()*responses.length)]);
560}
561
562// Watch your fucking language.
563function annoyCandyman(channel){
564 channel.sendMessage("Watch your SKITTYing language à ² _à ² ");
565}
566
567/*
568 ********************
569 * Stats *
570 ********************
571 */
572
573// Because I swear she says this in every single message (sometimes both).
574function statsWillOfD(message){
575 if (messageAuthorEquals(message, "113084295958044672")){
576 var text=message.content.toLowerCase();
577 if (text.includes("lol")){
578 stats.WillOfD.lol++;
579 }
580 if (text.includes("xd")){
581 stats.WillOfD.xd++;
582 }
583 if (text.includes("^w^")){
584 stats.WillOfD.w++;
585 }
586 stats.WillOfD.messages++;
587 fs.writeFileSync('stats.ini', ini.stringify(stats));
588 }
589}
590
591function saveStatsGeneral(){
592 fs.writeFileSync("misc.ini", ini.stringify(statsGeneral));
593}
594
595function STATS(message){
596 var string=message.content.toLowerCase();
597 var usernameString=authorString(message.author);
598 var user;
599 if (usernameString in userTable){
600 user=userTable[usernameString];
601 } else {
602 user=new User(message.author.username);
603 userTable[usernameString]=user;
604 }
605 user.lines++;
606
607 if (string.includes("slap")&&utilityIsAction(string)){
608 user.slaps++;
609 }
610 if (string.includes("eyan")||string.includes("zeal")){
611 user.zeal++;
612 }
613 if (string.includes("toilet")){
614 user.toilet++;
615 }
616 if (utilityIsAction(string)){
617 user.actions++;
618 }
619 if (string.endsWith("?")){
620 user.questions++;
621 }
622 if (string.endsWith("!")){
623 user.exclamations++;
624 }
625 if (string.toLowerCase().includes("elvia")){
626 user.elvia++;
627 }
628
629 if (utilityIsAction(string)){
630 user.todayActions++;
631 for (var i=0; i<violentVerbs.length; i++){
632 if (string.includes(violentVerbs[i])){
633 user.todayViolence++;
634 if (!user.todayWasWarned&&user.todayWarnings<2){
635 // can send a warning?
636 if (user.todayActions>10&&user.todayViolence/user.todayActions>0.06){
637 user.todayWasWarned=true;
638 user.todayWarnings++;
639 user.totalWarnings++;
640 // alert
641 DRAGONITE.openDM().then(function(dm){
642 dm.sendMessage(message.author.username+" is being a wee bit violent. Have a word with them, maybe?");
643 dm.sendMessage("Message: ```"+string+"```");
644 });
645 // Alert
646 client.Channels.get("344295609194250250").sendMessage(message.author.username+" is being a wee bit violent. Have a word with them, maybe?\n"+
647 "\tOffending message: ```"+string+"```");
648 }
649 }
650 }
651 }
652 }
653 if (botCanSendUserCommands){
654 if (string.includes("is back")||string.includes("has returned")||string.includes("m back")){
655 statsGeneral.everything.back++;
656 botCanSendUserCommands=false;
657 saveStatsGeneral();
658 }
659 }
660}
661
662function utilityBotStats(e){
663 var uptime=process.uptime();
664 var uptimeDays=Math.floor(uptime/(60*60*24));
665 var uptimeHours=Math.floor((uptime%(60*60*24))/3600);
666 var uptimeMinutes=Math.floor((uptime%3600)/60);
667 var uptimeSeconds=Math.floor(uptime%60);
668 var memory=process.memoryUsage();
669
670 var string="";
671 string="Users, probably: "+Object.keys(userTable).length+"\n";
672 string=string+"Memory usage, probably: "+memory.rss/(1024*1024)+" MB\n";
673 string=string+"Uptime, probably: "+uptimeDays+" days, "+uptimeHours+" hours, "+uptimeMinutes+" minutes, "+uptimeSeconds+" seconds\n";
674 string=string+"Commands recieved since we started caring: "+totalBotCommands+"\n";
675 string=string+"Lines censored since we started caring: "+totalCensoredLines+"\n";
676 string=string+"Heap usage: shove it up your @$$, Magus"
677
678
679 e.message.channel.sendMessage("Bot stats, and stuff:\n```"+string+"```");
680}
681
682/*
683 ********************
684 * Reactions *
685 ********************
686 */
687
688function REACT(message){
689 var botReactionBlacklist=[
690 ]
691 for (var i=0; i<botReactionBlacklist.length; i++){
692 if (messageAuthorEquals(message, botReactionBlacklist[i])){
693 return false;
694 }
695 }
696 /*
697 * Specific reactions
698 */
699 // getting a date
700 if (!utilityIsAction(message.content)){
701 if (message.content.includes("hot date")&&Math.random()<0.25){
702 message.channel.sendMessage(hotDateResponses[Math.floor(Math.random()*hotDateResponses.length)]);
703 } else if (message.content.includes("last date")&&Math.random()<0.25){
704 message.channel.sendMessage(lastDateResponses[Math.floor(Math.random()*lastDateResponses.length)]);
705 } else if (message.content.includes("get a date")&&Math.random()<0.75){
706 var mm=Math.floor(Math.random()*11)+1;
707 var dd=Math.floor(Math.random()*27)+1;
708 var yy=Math.floor(Math.random()*2500)+1;
709 message.channel.sendMessage(mm+"/"+dd+"/"+yy)
710 }
711 }
712 // Free hugs
713 if (utilityIsAction(message.content)&&!utilityMessageWasWrittenByMe(message)){
714 var newString=replaceAll(message.content, "_", "");
715 newString=replaceAll(newString, "*", "");
716 newString=replaceAll(newString, "@", "");
717 if (newString.startsWith("hugs")){
718 if (Math.random()*100<60){
719 var target=newString.replace("hugs ", "");
720 message.channel.sendMessage("_hugs "+target+", also_");
721 return true;
722 }
723 }
724 } else if (message.content.toLowerCase().endsWith("i need a hug")){
725 message.channel.sendMessage("_hugs "+message.author.nickMention+"_");
726 return true;
727 } else if (message.content.toLowerCase().endsWith("hug me")){
728 message.channel.sendMessage("_hugs "+message.author.nickMention+"_");
729 return true;
730 }
731 // cookies
732 if (message.content.toLowerCase().includes("cookie")&&!utilityMessageWasWrittenByMe(message)){
733 if (Math.random()*100<10){
734 message.channel.sendMessage("_steals cookies_");
735 console.log("Cookies have been stolen from "+message.author.username+".");
736 return true;
737 }
738 }
739 // sandwich
740 if (message.content.toLowerCase().includes("sandwich")&&!utilityMessageWasWrittenByMe(message)){
741 if (Math.random()*100<10){
742 message.channel.sendMessage("_steals sandwich_");
743 console.log("Sandwich has been stolen from "+message.author.username+".");
744 return true;
745 }
746 } else if (message.content.toLowerCase().includes("sandvich")&&!utilityMessageWasWrittenByMe(message)){
747 if (Math.random()*100<10){
748 message.channel.sendMessage("_steals sandvich_");
749 console.log("Sandvich has been stolen from "+message.author.username+".");
750 return true;
751 }
752 // america
753 } else if (message.content.toLowerCase().includes("america")&&!utilityMessageWasWrittenByMe(message)){
754 if (Math.random()*100<10){
755 message.channel.sendMessage("SKITTY YEAH!");
756 console.log("Skitty yeah.");
757 return true;
758 }
759 }
760 // onii-chan
761 if (messageAuthorEquals(message, "191299047896776704")){
762 if (message.content.toLowerCase().includes("onii-chan")&&Math.random()*100<35){
763 message.channel.sendMessage("à ² _à ² ");
764 console.log("Pimaster has discovered the oniichan reaction.");
765 return true;
766 }
767 }
768 // PUNish[ment]
769 if (message.content.includes("PUNish")&&Math.random()*100<45){
770 message.channel.sendMessage("à ² _à ² ");
771 console.log("Punishment has been doled out.");
772 return true;
773 }
774 /*
775 * Generic reactions
776 */
777
778 var verbsPain=[
779 "slaps",
780 "stabs",
781 "kills",
782 "murders",
783 "beats",
784 "kicks",
785 "punches",
786 "pinches",
787 ]
788
789 var verbsUncomfortable=[
790 "pets",
791 "buys",
792 "sells",
793 ]
794
795 var verbsGratitude=[
796 "chooses",
797 ]
798
799 var verbsOhNo=[
800 "breaks",
801 ]
802
803 if (utilityIsAction(message.content)){
804 var words=replaceAll(message.content, "_", "").split(" ");
805 if (words.length>1){
806 if (words[1].toLowerCase()==myNick.toLowerCase()||(words.length>2&&words[2].toLowerCase()==myNick.toLowerCase())){
807 if (verbsPain.indexOf(words[0])>-1){
808 message.channel.sendMessage("Ow . . .").then(e => censorMessageDeletionQueueLong(e));;
809 botCanSendUserCommands=false;
810 return true;
811 }
812 if (verbsUncomfortable.indexOf(words[0])>-1){
813 message.channel.sendMessage("_beats "+message.author.nickMention+" over the head with a spatula_").then(e => censorMessageDeletionQueueLong(e));;
814 botCanSendUserCommands=false;
815 return true;
816 }
817 if (verbsGratitude.indexOf(words[0])>-1){
818 message.channel.sendMessage("_hugs "+message.author.nickMention+"_").then(e => censorMessageDeletionQueueLong(e));;
819 botCanSendUserCommands=false;
820 return true;
821 }
822 if (verbsOhNo.indexOf(words[0])>-1){
823 message.channel.sendMessage("ヽ( 。 ヮ゚)ノ").then(e => censorMessageDeletionQueueLong(e));
824 botCanSendUserCommands=false;
825 return true;
826 }
827 }
828 }
829 }
830
831 /*
832 * EyanSays
833 */
834 if ((message.content.toLowerCase().includes(" "+myNick.toLowerCase())||message.content.startsWith(myNick.toLowerCase()))&&(message.content.match(new RegExp(" ", "g"))||[]).length>2&&botCanSpeak){
835 botCanSpeak=false;
836 message.channel.sendTyping(); // this doesn't work and I have no idea why
837 setTimeout(function(){
838 sendRandomLine(message);
839 }, Math.random()*2000+1000);
840 return true;
841 }
842
843 return false;
844}
845
846/*
847 ********************
848 * Censor *
849 ********************
850 */
851
852// Basic censor. Built around string.includes. Not recommended for serious use.
853
854function censor(message){
855 if (message.channel!=client.Channels.get("311402910820859914")&& // meme chat
856 message.channel!=client.Channels.get("311398412610174976")&& // woe
857 message.author!=client.User){ // can't censor itself
858 censorText(message.content, message.channel, message.author, message, "");
859 }
860}
861
862// The actual censor
863function censorText(text, channel, author, message, redactMessage){
864 var newMessage=censorRemoveRegionalIndicators(text.toLowerCase());
865 var toDelete=-1;
866 var bannedCount=0;
867 for (var i=0; i<banned.length; i++){
868 if (newMessage.includes(banned[i][0])){
869 bannedCount+=(newMessage.match(new RegExp(banned[i][0], "g"))||[]).length;
870 if (redactMessage.length==0){
871 newMessage=replaceAll(newMessage, banned[i][0], banned[i][2]);
872 } else {
873 newMessage=redactMessage;
874 }
875 toDelete=i;
876 }
877 }
878 if (toDelete>-1){
879 if (newMessage.length>320){
880 newMessage=newMessage.slice(0, 320)+"...";
881 }
882 var canTextReplace=true;
883 var swearReplacementBlacklist=[
884 ["162952008712716288"]
885 ]
886 for (var i=0; i<swearReplacementBlacklist.length; i++){
887 if (authorEquals(author, swearReplacementBlacklist[i])){
888 canTextReplace=false;
889 }
890 }
891 if (bannedCount>(message.content.split(" ").length+1)*0.3){
892 canTextReplace=false;
893 }
894 if (canTextReplace){
895 channel.sendMessage(banned[toDelete][1]+"\n`"+author.username+": "+newMessage+"`").then(e => censorMessageDeletionQueueLong(e));
896 if (messageAuthorEquals(message, "247163799960944640")){
897 annoyCandyman(message.channel);
898 botCanYellAtCandy=false;
899 }
900 } else {
901 console.log("Was caught in the censor: "+author.username+": "+newMessage);
902 }
903 censorUpdateSwearTable(author);
904 totalCensoredLines++;
905 message.delete();
906 return true;
907 }
908 return false;
909}
910
911// Adds a message to the short-term deletion log.
912function censorMessageDeletionQueue(message){
913 deletionQueue.push(message);
914}
915
916// Clears the short-term deletion log.
917function censorClearDeletionQueue(){
918 for (var i=0; i<deletionQueue.length; i++){
919 deletionQueue[i].delete();
920 }
921 deletionQueue=[];
922}
923
924// Adds a message to the long-term deletion log.
925function censorMessageDeletionQueueLong(message){
926 deletionQueueLong.push(message);
927}
928
929// Clears the long-term deletion log.
930function censorClearDeletionQueueLong(){
931 for (var i=0; i<deletionQueueLong.length; i++){
932 deletionQueueLong[i].delete();
933 }
934 deletionQueueLong=[];
935}
936
937// Updates the swear table, and saves it
938
939function censorUpdateSwearTable(user){
940 var n=authorString(user);
941 if (!(n in userTable)){
942 userTable[n]=new User(user.username, user.discriminator);
943 userTable[n].swears=1;
944 } else {
945 userTable[n].swears++;
946 }
947 utilitySaveStats();
948}
949
950// Converts "regional indicator" letters to regular leters.
951function censorRemoveRegionalIndicators(text){
952 var newString="";
953 var continueNext=false;
954 for (var i=0; i<text.length; i++){
955 var character=text.charCodeAt(i);
956 if (character==55356){
957 continue;
958 }
959 if (continueNext){
960 continueNext=false;
961 continue;
962 }
963 if (character>=56806&&character<=56831){
964 character=character-(56806-97);
965 continueNext=true;
966 }
967 newString=newString+String.fromCharCode(character);
968 }
969 return newString;
970}
971
972function censorCommandSet(message){
973 if (userHasKickingBoots(message.author, message.channel)){
974 var command=message.content.replace("e!censor", "").split(" ");
975 if (command[0]===""||command[0]==="-help"){
976 message.channel.sendMessage("Note that only people with kicking boots can access these commands and they're best used in moderation channels only.\n\n"+
977 "```e!censor-add <phrase>,<instruction>,<replacement>\n"+
978 "e!censor-add-help\n"+
979 "e!censor-remove <phrase>\n"+
980 "e!censor-remove-help\n"+
981 "e!censor-all\n"+
982 "e!censor-all-help```");
983 } else if (command[0]==="-add"){
984 var input="";
985 for (var i=1; i<command.length; i++){
986 input=input+command[i];
987 if (i<command.length-1){
988 input=input+" ";
989 }
990 }
991 var csv=input.split(",");
992 if (csv.length<3){
993 message.channel.sendMessage("Incorrect usage; refer to `e!censor-help` for more details`");
994 return false;
995 }
996 console.log(csv);
997 var prospective=csv[0];
998 var exists=false;
999 var index=0;
1000 for (var i=0; i<banned.length; i++){
1001 if (banned[i][0].toLowerCase()===prospective.toLowerCase()){
1002 exists=true;
1003 index=i;
1004 break;
1005 }
1006 }
1007 if (exists){
1008 message.channel.sendMessage("That word or phrase already exists in the censor list. Updating it instead!");
1009 banned[index][0]=prospective;
1010 banned[index][1]=csv[1];
1011 banned[index][2]=csv[2];
1012 } else {
1013 index=banned.length;
1014 message.channel.sendMessage("Added that to the censor list!");
1015 banned.push(["", "", ""]);
1016 banned[index][0]=prospective;
1017 banned[index][1]=csv[1];
1018 banned[index][2]=csv[2];
1019 }
1020 censorSaveList();
1021 } else if (command[0]==="-add-help"){
1022 message.channel.sendMessage("```e!censor-add <phrase>,<instruction>,<replacement>```"+
1023 "Adds a message to the censor.\n"+
1024 " `<phrase>` is the text to ban. If it's already part of the censor it'll be updated instead.\n"+
1025 " `<instruction>` is the warning message sent, i.e. \"potty mouth!\"\n"+
1026 " `<replacement>` is the text the bad word is replaced with, i.e. \"SKITTY\"");
1027 } else if (command[0]==="-remove"){
1028 var input="";
1029 for (var i=1; i<command.length; i++){
1030 input=input+command[i];
1031 if (i<command.length-1){
1032 input=input+" ";
1033 }
1034 }
1035 var exists=false;
1036 var index=0;
1037 for (var i=0; i<banned.length; i++){
1038 if (banned[i][0].toLowerCase()===input.toLowerCase()){
1039 exists=true;
1040 index=i;
1041 break;
1042 }
1043 }
1044 if (exists){
1045 message.channel.sendMessage("Removed from the censor!");
1046 banned.splice(i, 1);
1047 censorSaveList();
1048 } else {
1049 message.channel.sendMessage("That isn't part of the censor!");
1050 }
1051 } else if (command[0]==="-remove-help"){
1052 message.channel.sendMessage("```e!censor-remove <phrase>```"+
1053 "Removes `phrase` from the censor.\n");
1054 } else if (command[0]==="-all"){
1055 //message.author.openDM().then(function(dm){
1056 client.Users.get(message.author.id).openDM().then(function(dm){
1057 var str="";
1058 for (var i=0; i<banned.length; i++){
1059 str=str+banned[i][0]+","+banned[i][1]+","+banned[i][2]+"\n";
1060 }
1061 dm.sendMessage("```Banned words in the server:\nWord,Instruction,Replacement\n"+str+"```");
1062 });
1063 message.channel.sendMessage("Sent you a thing (hopefully)!");
1064 } else if (command[0]==="-all-help"){
1065 message.channel.sendMessage("```e!censor-all```"+
1066 "Sends you a list of all the banned words as a PM (I'd spit them out here except the list can be quite long, and in any case the bot would censor itself anyway.)");
1067 }
1068 }
1069 return true;
1070}
1071
1072function censorSaveList(){
1073 var saveString="";
1074 for (var i=0; i<banned.length; i++){
1075 saveString=saveString+banned[i][0]+","+banned[i][1]+","+banned[i][2]+"\r\n";
1076 }
1077 fs.writeFile("swears.csv", saveString, function(err) {
1078 if(err) {
1079 return console.log(err);
1080 }
1081 });
1082}
1083
1084function censorLoadList(){
1085 var lines;
1086 fs.readFile("swears.csv", function(err, data){
1087 if(err){
1088 throw err;
1089 }
1090 lines = data.toString().split('\n');
1091 for (var i=0; i<lines.length; i++){
1092 var csv=lines[i].split(",");
1093 if (csv.length>=3){
1094 banned.push([csv[0], csv[1], csv[2]]);
1095 }
1096 }
1097 });
1098}
1099
1100/*
1101 ********************
1102 * Picture stuff *
1103 ********************
1104 */
1105
1106function waifuSend(channel){
1107 channel.uploadFile("waifus\\"+waifus[Math.floor(Math.random()*waifus.length)]);
1108}
1109
1110function catSend(channel){
1111 channel.uploadFile(".\\cats\\"+cats[Math.floor(Math.random()*cats.length)]);
1112}
1113
1114
1115/*
1116 ********************
1117 * Utilities *
1118 ********************
1119 */
1120
1121// Sets the currently playing game
1122function utilityGame(e){
1123 if (userHasKickingBoots(e.message.author, e.message.channel)){
1124 client.User.setGame(e.message.content.replace("e!game ", ""));
1125 e.message.channel.sendMessage("New game: "+e.message.content.replace("e!game ", ""));
1126 } else {
1127 e.message.channel.sendMessage("You don't have permission to do that, sorry.");
1128 }
1129}
1130
1131function utilitySaveLine(line){
1132 fs.appendFile("log.txt", line+"\r\n", (err) => {
1133 if (err){
1134 throw err;
1135 }
1136 });
1137}
1138
1139function utilityHug(e){
1140 var target=e.message.content.replace("e!hug ", "");
1141 if (target.startsWith("e!hug")){
1142 target=e.message.author.username;
1143 }
1144 e.message.channel.sendMessage("_hugs "+target+"_");
1145}
1146
1147function utilitySandwich(e){
1148 var target=e.message.content.toLowerCase().replace("e!sandwich ", "");
1149 if (target.startsWith("e!sandwich")){
1150 target=e.message.author.username;
1151 }
1152 e.message.channel.sendMessage("_gives a sandwich to "+target+"_");
1153}
1154
1155 // Loads in the stored values from the swear table.
1156
1157function utilityCreateUserTable(){
1158 var lines;
1159 fs.readFile("stats.csv", function(err, data){
1160 if(err){
1161 throw err;
1162 }
1163 lines = data.toString().split('\n');
1164 for (var i=0; i<lines.length; i++){
1165 if (lines[i].includes(",undefined")){
1166 } else {
1167 var spl=lines[i].split(",");
1168
1169 var user=new User(spl[0].split("#")[0], spl[0].split("#")[1]);
1170 userTable[spl[0]]=user;
1171 user.swears=Number(spl[1]);
1172 user.slaps=Number(spl[2]);
1173 user.zeal=Number(spl[3]);
1174 user.toilet=Number(spl[4]);
1175
1176 user.actions=Number(spl[5]);
1177 user.questions=Number(spl[6]);
1178 user.exclamations=Number(spl[7]);
1179
1180 user.lines=Number(spl[8]);
1181 user.secretWord=Number(spl[9]);
1182 user.secretWordAdd=Number(spl[10]);
1183
1184 if (spl.length>=12){
1185 user.elvia=Number(spl[11]);
1186 }
1187 if (spl.length>=13){
1188 user.todayActions=Number(spl[12]);
1189 user.todayViolence=Number(spl[13]);
1190 user.todayWarnings=Number(spl[14]);
1191 user.totalWarnings=Number(spl[15]);
1192 }
1193 }
1194 }
1195 });
1196}
1197
1198function utilitySaveBotStats(){
1199 var saveString=totalBotCommands+","+totalCensoredLines;
1200 fs.writeFile("botstats.csv", saveString, function(err) {
1201 if(err) {
1202 return console.log(err);
1203 }
1204 });
1205}
1206
1207function utilityLoadBotStats(){
1208 var line;
1209 fs.readFile("botstats.csv", function(err, data){
1210 if(err){
1211 throw err;
1212 }
1213 line=data.toString();
1214 var spl=line.split(",");
1215 switch (spl.length){
1216 case 2:
1217 totalBotCommands=Number(spl[0]);
1218 totalCensoredLines=Number(spl[1]);
1219 case 0:
1220 break;
1221 }
1222 });
1223}
1224
1225 // Saves all of the stats
1226
1227 function utilitySaveStats(){
1228 var saveString="";
1229 for (var n in userTable){
1230 var user=userTable[n];
1231 saveString=saveString+n+","+user.swears+
1232 ","+user.slaps+","+user.zeal+","+user.toilet+
1233 ","+user.actions+","+user.questions+","+user.exclamations+
1234 ","+user.lines+","+user.secretWord+","+user.secretWordAdd+
1235 ","+user.elvia+
1236
1237 ","+user.todayActions+","+user.todayViolence+","+user.todayWarnings+","+user.totalWarnings+
1238 "\r\n";
1239 }
1240 fs.writeFile("stats.csv", saveString, function(err) {
1241 if(err) {
1242 return console.log(err);
1243 }
1244 });
1245 }
1246
1247// Utility that prints out the number of lines in the bot's learned database.
1248function utiliyLineCount(e){
1249 var lines;
1250 fs.readFile("line.txt", function(err, data){
1251 if(err){
1252 e.message.channel.sendMessage("Something blew up. Oh noes! @Dragonite#7992");
1253 throw err;
1254 }
1255 lines = data.toString().split('\n');
1256 e.message.channel.sendMessage(lines.length+" lines in "+myNick+"'s quote log.");
1257 })
1258}
1259
1260// Prints out the high score table for the censor
1261function utilityStats(e){
1262 /*var statsString="SOME INANE STATS THAT DRAGONITE COLLECTS";
1263 var highscoreList=__createDefaultHighScoreList();
1264 statsString+=utilityAppendHR(); // Slaps
1265 highscoreList.sort(function(a, b){
1266 return b.slaps-a.slaps;
1267 });
1268 statsString+=highscoreList[0].name+" was rather slap happy, dishing out a solid backhand "+highscoreList[0].slaps+" times.\n";
1269 statsString+=highscoreList[1].name+" was "+utilityComparisonString(highscoreList[0].slaps, highscoreList[1].slaps)+", using the move "+highscoreList[1].slaps+" times.";
1270 statsString+=utilityAppendHR(); // Toilets
1271 highscoreList.sort(function(a, b){
1272 return b.toilet-a.toilet;
1273 });
1274 statsString+=highscoreList[0].name+" has a rather peculiar obsession with toilets, saying the word "+highscoreList[0].toilet+" times.\n";
1275 statsString+=highscoreList[1].name+" was "+utilityComparisonString(highscoreList[0].toilet, highscoreList[1].toilet)+", with "+highscoreList[1].toilet+" in total.";
1276 statsString+=utilityAppendHR(); // Zeal
1277 highscoreList.sort(function(a, b){
1278 return b.zeal-a.zeal;
1279 });
1280 statsString+=highscoreList[0].name+" was eager to proclaim their love for the King, saying his name a whopping "+highscoreList[0].zeal+" times.\n";
1281 statsString+=highscoreList[1].name+" was also "+utilityZealString()+", with "+highscoreList[1].zeal+" references to the King.";
1282 statsString+=utilityAppendHR(); // Actions
1283 highscoreList.sort(function(a, b){
1284 return b.actions-a.actions;
1285 });
1286 statsString+=highscoreList[0].name+" greatly enjoyed role playing, writing "+highscoreList[0].actions+" lines as actions.\n";
1287 statsString+=highscoreList[1].name+" was "+utilityComparisonString(highscoreList[0].actions, highscoreList[1].actions)+", with "+highscoreList[1].actions+" in total.";
1288 statsString+=utilityAppendHR(); // Questions
1289 highscoreList.sort(function(a, b){
1290 return b.questions-a.questions;
1291 });
1292 statsString+=highscoreList[0].name+" has an insatiable thirst for knowledge, "+highscoreList[0].questions+" questions in total.\n";
1293 statsString+=highscoreList[1].name+" was "+utilityComparisonString(highscoreList[0].questions, highscoreList[1].questions)+", with "+highscoreList[1].questions+" all told.";
1294 statsString+=utilityAppendHR(); // Exclamations
1295 highscoreList.sort(function(a, b){
1296 return b.exclamations-a.exclamations;
1297 });
1298 statsString+="People probably wish "+highscoreList[0].name+" would pipe down a bit, after hearing them shout "+highscoreList[0].exclamations+" times!\n";
1299 statsString+=highscoreList[1].name+" was "+utilityComparisonString(highscoreList[0].exclamations, highscoreList[1].exclamations)+", raising their voice on "+highscoreList[1].exclamations+" occasions.";
1300 statsString+=utilityAppendHR(); // Lines
1301 highscoreList.sort(function(a, b){
1302 return b.lines-a.lines;
1303 });
1304 statsString+=highscoreList[0].name+" talks a bit too much, writing "+highscoreList[0].lines+" total lines since joining the server.\n";
1305 statsString+=highscoreList[1].name+" was "+utilityComparisonString(highscoreList[0].lines, highscoreList[1].lines)+", with "+highscoreList[1].lines+" of the things.\n\n";
1306 statsString+="*Note that this only counts stats collected while Dragonite's computer was turnd on.";
1307 e.message.channel.sendMessage("```"+statsString+"```");*/
1308}
1309
1310function utilityComparisonString(a, b){
1311 var f=b/a;
1312 var responses;
1313 if (f>0.9){
1314 responses=["a close second", "right there", "vying for the honor", "right on their heels", "in close competition"];
1315 } else if (f>0.5){
1316 responses=["not far too behind", "making an effort", "up and coming", "within sight"];
1317 } else {
1318 responses=["nowhere in sight", "not trying very hard", "only mildly interested"];
1319 }
1320 return responses[Math.floor(Math.random()*responses.length)];
1321}
1322
1323function utilityZealString(){
1324 var responses=["enthralled by the royalty", "in awe"]
1325 return responses[Math.floor(Math.random()*responses.length)];
1326}
1327
1328// Dumps all of the people in the userTable without sorting it.
1329function __createDefaultHighScoreList(){
1330 var list=[];
1331 for (o in userTable){
1332 if (userTable[o].name.length>0){
1333 var user=userTable[o];
1334 if (user.name!="Tatsumaki"&&user.discriminator!=8792){
1335 list.push(userTable[o]);
1336 }
1337 }
1338 }
1339 return list;
1340}
1341
1342// append a long line of dashes
1343function utilityAppendHR(){
1344 return "\n-----------------\n";
1345}
1346
1347// Master wants to play ping pong.
1348function utilityPing(e){
1349 var now=Date.now();
1350 e.message.channel.sendMessage("o3o").then(e => utilityPingTimeElapsed(e, now));
1351 console.log("Pinged the bot, blah, blah.");
1352}
1353
1354// Is a message an action?
1355function utilityIsAction(string){
1356 var first=string.charAt(0);
1357 if (first!="*"&&first!="_"){
1358 return false;
1359 }
1360 return string.endsWith(first);
1361}
1362
1363// Follow-up for utilityPing
1364function utilityPingTimeElapsed(message, now){
1365 var n=Date.now()-now;
1366 message.edit(message.content+": `"+n+" ms`");
1367}
1368
1369// Mentions the bot?
1370function utilityMentionsMe(message){
1371 for (var i=0; i<message.mentions.length; i++){
1372 if (message.mentions[i].username==client.User.username&&message.mentions[i].discriminator==client.User.discriminator){
1373 return true;
1374 }
1375 }
1376 return false;
1377}
1378
1379function utilityMessageWasWrittenByMe(message){
1380 return message.author.username==client.User.username&&message.author.discriminator==client.User.discriminator;
1381}
1382
1383// Utility that dumps all of the messages in a server.
1384function utilityDumpServer(e){
1385 console.log("***"+e.message.channel.name+"***");
1386 fetchMessagesEx(e.message.channel, 10000);
1387}
1388
1389// fetch more messages just like Discord client does
1390function fetchMessagesEx(channel, left) {
1391 // message cache is sorted on insertion
1392 // channel.messages[0] will get oldest message
1393 var before = channel.messages[0];
1394 return channel.fetchMessages(Math.min(left, 100), before)
1395 .then(e => onFetch(e, channel, left));
1396}
1397
1398// What to do when you fetch a batch of messages.
1399function onFetch(e, channel, left) {
1400 if (!e.messages.length){
1401 return Promise.resolve();
1402 }
1403 left -= e.messages.length;
1404 console.log(`Received ${e.messages.length}, left: ${left}`);
1405 for (var i=0; i<e.messages.length; i++){
1406 var message=e.messages[i];
1407 /////////
1408 //STATS(message);
1409 /////////
1410 var str=message.author.username+":\t"+e.messages[i].content+"\r\n"
1411 fs.appendFile("channeldump.txt", str, (err) => {
1412 if (err){
1413 throw err;
1414 }
1415 });
1416 }
1417 if (left <= 0){
1418 return Promise.resolve();
1419 }
1420 return fetchMessagesEx(channel, left);
1421}
1422
1423function utilityPinned(e){
1424 fetchPinned(e.message.channel);
1425}
1426
1427function fetchPinned(channel){
1428 return channel.fetchPinned().then(e => onFetchPinned(e, channel));
1429}
1430
1431function onFetchPinned(e, channel){
1432 channel.sendMessage(e.messages.length+" pinned messages (in this channel)");
1433}
1434
1435function fetchPinnedSelf(channel){
1436 return channel.fetchPinned().then(e => onFetchPinnedSelf(e, channel));
1437}
1438
1439function onFetchPinnedSelf(e, channel){
1440 if (e.messages.length==50){
1441 channel.sendMessage("Hey! You've hit the pin limit for this channel! @SuperDragonite2172 , you'd better do something about that.");
1442 }
1443}
1444
1445function fetchPinnedAuto(channel){
1446 return channel.fetchPinned().then(e => onFetchPinnedAuto(e, channel));
1447}
1448
1449function onFetchPinnedAuto(e, channel){
1450 if (e.messages.length==50){
1451 channel.sendMessage("Hey! You've hit the pin limit for this channel! @SuperDragonite2172 , you'd better do something about that.");
1452 }
1453}
1454
1455// Checks to see if a message was written by a certain perosn.
1456function messageAuthorEquals(message, id){
1457 return authorEquals(message.author, id);
1458}
1459
1460function authorEquals(author, id){
1461 return author.id==id;
1462}
1463
1464function authorString(user){
1465 return user.username+"#"+user.discriminator;
1466}
1467
1468// Because for some inane reason JavaScript does not include this on its own. Inefficient.
1469function replaceAll(string, toReplace, newString){
1470 var t=string;
1471 while (t.includes(toReplace)){
1472 t=t.replace(toReplace, newString);
1473 }
1474 return t;
1475}
1476
1477/*
1478 ********************
1479 * Help *
1480 ********************
1481 */
1482
1483// Prints an introduction to the bot
1484function helpHelpHelp(e){
1485 var message=myNick+" is a Discord bot for the Kingdom/Harem of Zeal. There's a few things it does. "+
1486 "Type one of the following to learn more:\n\n"+
1487 "e!help Says\n"+
1488 "e!help Twitch\n"+
1489 "e!help Lol\n"+
1490 "e!help Misc\n"+
1491 "e!help Reactions\n"+
1492 "e!help Mods\n\n"+
1493 "e!help Credits\n\n"+
1494 "All commands are case insensitive.";
1495 e.message.channel.sendMessage("```"+message+"```");
1496}
1497
1498// Introduction to quotes
1499function helpSays(e){
1500 var message=myName+"\n\n"+
1501 "The original function of "+myNick+" (then \"EyanSays\") was to "+
1502 "store all of the weird things that the King of Zeal says during "+
1503 "his Twitch streams, but it's kind of ballooned from there. Anyway, "+
1504 "people with kicking boots can add quotes with \"e!says-add <message>\"."+
1505 "To grab a random quote out of the archive, type "+myNick+". "+
1506 "Use \"e!size\" to see how many lines have been recorded.\n\n"+
1507 "If the King of Zeal says something you think is worthy of being added to the archive, ask "+
1508 "someone with kicking boots to do it for you."+
1509 "If you're not sure if you have kicking boots or not, you can check with \"e!test\" (but you "+
1510 "probably don't).";
1511
1512 e.message.channel.sendMessage("```"+message+"```");
1513}
1514
1515// Introduction to Twitch
1516function helpTwitch(e){
1517 var message="Twitch Stuff\n\n"+
1518 myNick+" will monitor the state of Zeal's Twitch stream, and can notify the server "+
1519 "when he goes live. If you want to find out if he's live or not, type \"e!live\" and "+myNick+" "+
1520 "will inform you."
1521 e.message.channel.sendMessage("```"+message+"```");
1522}
1523
1524// Introduction to Lol
1525function helpLol(e){
1526 var message="Poking fun at people\n\n"+
1527 myNick+" has a few commands for messing with people. Currently available are:\n\n"+
1528 "e!will\n"+
1529 "e!gummy\n"+
1530 "e!gummy-b\n"+
1531 "e!gummy-c\n"+
1532 "e!dragonite\n"+
1533 "e!dragonite-b\n"+
1534 "e!candy\n"+
1535 "e!candy-b"+
1536 "e!rainy\n"+
1537 "e!deci\n"+
1538 "e!ida\n"+
1539 "\n"+
1540 "Exactly how to get your own command is a secret.";
1541
1542 e.message.channel.sendMessage("```"+message+"```");
1543}
1544
1545// Introduction to Pictures
1546function helpPictures(e){
1547 var message="Miscellaneous Stuff\n\n"+
1548 myNick+" can embed a few fancy images into the channel. They're kinda broken though.\n\n"+
1549 "e!waifu\n"+
1550 "e!cat";
1551 e.message.channel.sendMessage("```"+message+"```");
1552}
1553
1554// Introduction to Misc
1555function helpMisc(e){
1556 var message="Miscellaneous Stuff\n\n"+
1557 myNick+" can do a few other things, too.\n\n"+
1558 "e!ping\n"+
1559 "e!stats\n"+
1560 "e!hug\n"+
1561 "e!sandwich\n"+
1562 "e!bot\n"+
1563 "e!pinned\n"+
1564 "e!game <game>\n"+
1565 "e!treason\n"+
1566 "e!back";
1567 e.message.channel.sendMessage("```"+message+"```");
1568}
1569
1570// Moderation panels
1571function helpMods(e){
1572 var prefix="~~The mods are beyond help~~";
1573 var message="Anyway . . . if you have kicking boots, there are a few control panels you can access. "+
1574 "(Or at least there's one important control panel at the moment, more may be added in the future.)\n"+
1575 "e!censor";
1576 e.message.channel.sendMessage(prefix+"```"+message+"```");
1577}
1578
1579// Reactionary stuff
1580function helpReactions(e){
1581 var message=myNick+" can and sometimes will react to certain lines in the chat."+
1582 "I'm not telling you what these reactions are or how to trigger them, because "+
1583 "it'll be funnier when people discover them on their own.";
1584 e.message.channel.sendMessage("```"+message+"```");
1585}
1586
1587// Credits, obviously
1588function helpCredits(e){
1589 var message="Credits\n\n"+
1590 "***"+myName+"***\n\n"+
1591 "Creator: Dragonite#7992\n"+
1592 "Version: 1.3.0\n"+
1593 "Library: Discordie\n\n"+
1594 "https://www.youtube.com/c/dragonitespam \n\n"+
1595 "Extra ideas came from SuperDragonite2172, willofd and probably Master9000.\n\n"+
1596 "Thanks to basically everyone on the Kingdom of Zeal server for testing this thing.";
1597 e.message.channel.sendMessage("```"+message+"```");
1598}