This week, keeping with tradition, I wanted to dip my nose into something new. This time, however, I wanted to at least keep in with the comfort of Javascript. I like the language and I'd like to have a versatile set of skills with it to match the versatility of the language itself. So this time I went about helping out with a
Discord bot.
For the uninitiated, Discord is a Slack-like chatting platform that makes use of servers and channels.
A Discord bot is a programmable user in the server that will display certain information upon being issued commands. Not unlike any given command-line interface.
The demonstration above betrays what the project I worked on was: a Discord bot for the game "MouseHunt".
AardWolf / MHTimerBot
Discord bot that understands mousehunt timers
MHTimerBot
Discord bot that understands mousehunt timers
Needs
Store timers in a file, database, or something "static" for when it's offline The definition of these timers should help determine that format Timers have a next occurrence. A duration. A repeat frequency. Some timers would change into next if they're fancy - spill timers, season timers. Or do like the currently do and repeat themselves Timers need a way to catch back up if offline a while.
Commands
- next <area> - displays how long until the next timer of that type and what the display message would be -next spill: The levels will rise to Arch in 2h31m
- remind <area> [sub-area] [always|once|stop|] - Sends a PM to remind of ANY timer for an area -remind season once - Will only remind the next time the timer goes -remind season winter once - Will only remind the next time the timer goes
- …
I won't go into too much detail on what the game entails (frankly I'm a little confused myself) but it seems to revolve around hunting mice that turn up in certain in-game locations on certain specific times of day and days of the week.
What this bot is meant to do is alert users in its own channel when a certain mouse has appeared in-game and allow users to query it for the last time a certain mouse was spotted.
The issue in question is as follows:
The user attempts to query the bot for the locations of a mouse over the past 3 months
The bot spits out the location of the mouse but only since the last 3 days
Solution: we must change the code so that it will spit out the correct timeframe
This is a simple enough fix and I didn't expect it to be terribly difficult to replace a few lines of code. What the issue presented was an opportunity to learn about Discord bots! That was my goal.
Setting up My Bot
So, in order to test my changes, I need to set up a discord bot in a testing server so I can issue it commands. Obviously, the first step is making a bot.
After that, I simply need to grab the bot token and put it into my settings.json
settings.json
{
"token": "<token>",
"bitly_token": "",
"linkConversionChannel": "larrys-freebies",
"timedAnnouncementChannels": {},
"relic_hunter_webhook": "283571156236107777",
"botPrefix": "-mh",
"owner": "0",
"reactions": {
"success": "✅",
"failure": "❌",
"errorSequence": [
"🤖",
"💣",
"💥"
]
},
"guilds": {
"772109745703616524": {
"timedAnnouncementChannels": [
"timers"
],
"linkConversionChannel": "larrys-freebies",
"botPrefix": "-mh"
}
},
"version": "1.00"
After that, I needed to invite the bot user into my server. Discord makes this pretty easy since I can just generate a link to my bot and plug it into an invite to my server.
Once the bot is in, I simply need to run npm install
and node MHTimer.js
and we're on our way!
If anyone else is interested in building a bot, I'd suggest referring to the very short tutorial on discordpy.io.
The Work
Next comes, of course, the actual coding. Like I said before, this wouldn't be completely difficult and will only require changing a few lines.
original getFilter() function
function getFilter(tester) {
// Process filter-y nicknames
if (!tester)
return;
tester = `${tester}`;
if (tester.startsWith('3'))
tester = '3_days';
else if (tester.startsWith('all'))
tester = 'alltime';
else if (tester === 'current') {
tester = '1_month';
for (const filter of filters) {
if (filter.start_time && !filter.end_time && filter.code_name !== tester) {
tester = filter.code_name;
break;
}
}
}
return getSearchedEntity(tester, filters)[0];
}
As we can see above, when the user inputs anything with "3" at the beginning, the tester defaults to "3_days" and therefore only ever grabs the last 3 days (see explanation above). So what do we do? It's simple. Because we want to discern between 3 months and 3 days, we just change the if statement to pick.
new getFilter() function snippet
if (tester.startsWith('3_d'))
tester = '3_days';
else if (tester.startsWith('3_m'))
tester = '3_months';
With this simple change, we can give the bot 3 days and 3 months and get the correct output!
Great! Now that we're done changing the code, let's perform the pull request
Oh no! Looks like we missed something! Let's take a look at our tests.
tests excerpts
suite.test('given string input - returns known shortcuts', t => {
const inputs = [
{ input: '3', expected: '3_days' },
{ input: '3day', expected: '3_days' },
{ input: 'all', expected: 'alltime' },
{ input: 'allowance', expected: 'alltime' },
{ input: 'current', expected: '1_month' }, //NOTE this can only be asserted because we don't load the filter list
];
It looks like now that we changed the "3" = "3_days" in the above code snippet, the test doesn't work! This is unfortunate and will require a bit of change to the tests. Or maybe my commit will need to be changed to reflect that. Regardless I don't think I have bad code or anything. I think I'll wait to see what the repo maintainers have to say about it.
The response
So it looks like we have a task! Let's update the testing files.
the new test snippet
suite.test('given string input - returns known shortcuts', t => {
const inputs = [
{ input: '3_d', expected: '3_days' },
{ input: '3days', expected: '3_days' },
{ input: '3_m', expected: '3_months' },
{ input: '3months', expected: '3_months' },
{ input: 'all', expected: 'alltime' },
{ input: 'allowance', expected: 'alltime' },
{ input: 'current', expected: '1_month' }, //NOTE this can only be asserted because we don't load the filter list
];
As you can see I just added in my new test conditions and off we go! This was all we had that was a problem so I'm pretty happy with this pull request.
...and it looks like they are too. What a nice ending.
I should note a changed one more little thing in my code.
if (tester.startsWith('3_d') || tester.startsWith('3d'))
tester = '3_days';
else if (tester.startsWith('3_m') || tester.startsWith('3m'))
tester = '3_months';
Just to add the condition of using '3days'/'3months' or '3d'/'3m' as an input because from what I saw before - it kinda seems like we want it there.
Conclusion
So that's it! I learned how to set up a Discord bot and read through the code for this one to determine the best way to start on one which was my main goal with this issue. Not to mention, I edited some test code! Which I've never done before. I'm very happy with this week! I can't wait to apply this practice to a project of my own.
Top comments (0)