· 6 years ago · Aug 11, 2019, 01:08 AM
1const tmi = require('tmi.js');
2const _ = require('lodash');
3
4// Define configuration options
5const opts = {
6 identity: {
7 username: "cheerupbot",
8 password: "<OAUTH_TOKEN>"
9 },
10 channels: [
11 "cheerupbeer"
12 ]
13};
14
15let countryList = [
16 ['usa', ['us']],
17];
18let countryMap = new Map();
19
20// TODO
21
22function countryMatches(a, b) {
23 a = a.toLowerCase().trim();
24 b = b.toLowerCase().trim();
25
26 // TODO better country name matching, need to add a list of supported countries
27 // TODO notify users in chat if their country isn't recognized
28
29 // e.g. at the moment if the user guesses "us" and the answer is "usa" it won't count as the same
30
31
32 return a === b;
33}
34
35class Round {
36 constructor(parent) {
37 this.parent = parent;
38 this.guesses = new Map();
39 }
40 guess(player, country) {
41 this.guesses.set(player, country);
42 }
43 playersWhoSelected(answer) {
44 let result = [];
45 for (let [player, options] of this.guesses) {
46 if (countryMatches(options.answer, guess)) {
47 result.push(options.displayname);
48 }
49 }
50 return result;
51 }
52}
53
54class Game {
55 constructor(parent) {
56 this.parent = parent;
57 this.streaks = new Map();
58 }
59 addWinner(displayname) {
60 let obj = this.streaks.get(displayname);
61 if (!obj) {
62 obj = { value: 0 };
63 this.streaks.set(displayname, obj);
64 }
65 obj.streak += 1;
66 }
67 sortedWinners() {
68 let winners = [];
69 for (let [player, obj] of this.streaks) {
70 winner.push([player, obj.streak]);
71 }
72 winner = _.orderBy(winner, x => x[1], 'desc');
73 return winner;
74 }
75}
76
77class Controller {
78 constructor(client) {
79 this.client = client;
80 this.newRound();
81 this.newGame();
82 }
83 newRound() {
84 this.round = new Round(this);
85 }
86 newGame() {
87 this.game = new Game(this);
88 }
89
90 recv(channel, userstate, msg, self, isWhisper) {
91 const displayname = userstate['display-name'];
92 const username = userstate['username'];
93 const userkey = username['user-id'];
94
95 if (username === 'cheerupbeer') {
96 if (/^!answer\b/i.test(msg)) {
97 let answer = /^![a-z]+\s([^\n]+)/i.exec(msg)[1];
98 if (answer) {
99 answer = answer.trim();
100 let winners = this.round.playersWhoSelected(answer);
101 for (let winner of winners) {
102 this.game.addWinner(winner);
103 }
104 this.client.say(target, `The winners were ${winners.map(w => '@'+w).join(', ')}`);
105 }
106 }
107 }
108 if (isWhisper && /^!g(?:uess)?\b/i.test(msg)) {
109 let answer = /^![a-z]+\s([^\n]+)/i.exec(msg)[1];
110 if (answer) {
111 answer = answer.trim();
112 this.round.set(userkey, {
113 displayname, answer
114 });
115 }
116 }
117 if (/^!leaderboard\b/i.test(msg)) {
118 let sortedWinners = this.game.sortedWinners();
119 let strs = [''];
120 for (let [displayname, streak] of sortedWinners) {
121 let str1 = strs[strs.length - 1];
122 let str2 = `${streak} ${displayname}`;
123 let suffix = ' ; ' + str2;
124 // Limit message lengths to 500
125 if ((str1 + suffix).length >= 500) {
126 strs.push(str2);
127 } else {
128 strs[strs.length - 1] += suffix;
129 }
130 }
131 for (let str of strs) {
132 this.client.say(str);
133 }
134 }
135 }
136}
137
138// Create a client with our options
139const client = new tmi.client(opts);
140
141// Register our event handlers (defined below)
142client.on('message', onMessageHandler);
143client.on('whisper', onWhisperHandler);
144client.on('connected', onConnectedHandler);
145
146// Connect to Twitch:
147client.connect();
148
149const controller = new Controller(client);
150
151// https://github.com/tmijs/docs/blob/gh-pages/_posts/v1.4.2/2019-03-03-Events.md#message
152
153// Called every time a message comes in
154function onMessageHandler (channel, userstate, message, self) {
155 if (self) { return; } // Ignore messages from the bot
156
157 // If the command is known, let's execute it
158 controller.recv(channel, userstate, msg.trim(), self, false);
159}
160
161function onWhisperHandler (channel, userstate, message, self) {
162 if (self) { return; } // Ignore messages from the bot
163
164 // If the command is known, let's execute it
165 controller.recv(channel, userstate, msg.trim(), self, true);
166}
167
168// Called every time the bot connects to Twitch chat
169function onConnectedHandler (addr, port) {
170 console.log(`* Connected to ${addr}:${port}`);
171}