DEV Community

Ray
Ray

Posted on

As a Real Gamer...

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.

The Discord bot dashboard

For the uninitiated, Discord is a Slack-like chatting platform that makes use of servers and channels.

Discord vs Slack sidebars

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.

Demonstration

The demonstration above betrays what the project I worked on was: a Discord bot for the game "MouseHunt".

GitHub logo 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:

  1. The user attempts to query the bot for the locations of a mouse over the past 3 months

  2. The bot spits out the location of the mouse but only since the last 3 days

  3. 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

Creating a 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"
Enter fullscreen mode Exit fullscreen mode

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.

Connect to Discord

Once the bot is in, I simply need to run npm install and node MHTimer.js and we're on our way!

Bot works!

I can even get it chatting

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];
}
Enter fullscreen mode Exit fullscreen mode

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';
Enter fullscreen mode Exit fullscreen mode

With this simple change, we can give the bot 3 days and 3 months and get the correct output!

It works!

Great! Now that we're done changing the code, let's perform the pull request

Uh oh....

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
        ];
Enter fullscreen mode Exit fullscreen mode

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

Well... alright...

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
        ];
Enter fullscreen mode Exit fullscreen mode

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.

lgtm

...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';
Enter fullscreen mode Exit fullscreen mode

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)