1
votes

So I'm new to discord botting and js and I'm playing around with my own bot. I want to make a typing minigame. When you type ?type in chat, the bot will say something in chat and then edit that message while counting down. When the counting down is finished, it will display the random generated word. The player needs to type the exact random word in the chat and the bot will show the total time taken.

Here is my code:

case "type":
        let randomWord = Math.random().toString(36).replace(/[^a-z]+/g, '');
        let timer = 3;
        message.channel.send("Generating a new word..")
          .then((msg)=> {
            var interval = setInterval(function () {
              msg.edit(`Starting in **${timer--}**..`)
            }, 1000)
          });
        setTimeout(function() {
          clearInterval(interval);
          message.channel.send(randomWord)
          .then(() => {
            message.channel.awaitMessages(response => response.content == randomWord, {
              max: 1,
              time: 10000,
              errors: ['time'],
            })
            .then(() => {
              message.channel.send(`Your time was ${(msg.createdTimestamp - message.createdTimestamp) / 1000} seconds.`);
            })
            .catch(() => {
              message.channel.send('There was no collected message that passed the filter within the time limit!');
            });
          });
        }, 5000);
        break;

Currently the code stops after it counted to down 0. I dont understand why message.channel.send(randomWord) doesn't work. Also I would love it if someone could help me change this code to use asynch and await if that's something viable.

1

1 Answers

0
votes

I started researching your problem and here's the system I came up with.

Here is the bot listening to messages from different users. Once a user types '?type', the function runWordGame is called, passing in the message's channel.

// set message listener 
client.on('message', message => {
    switch(message.content.toUpperCase()) {
        case '?type':
            runWordGame(message.channel);
            break;
    }
});

Here in runWordGame, the bot creates a random word, then displays a countdown to the user (see displayMessageCountdown below). When the countdown is over, the message is edited with the random word. Next, the bot waits for 1 message for 10 seconds - waiting for the user to input the random word. If successful, a success message is sent. Otherwise, an error message is sent.

// function runs word game
function runWordGame(channel) {
    // create random string
    let randomWord = Math.random().toString(36).replace(/[^a-z]+/g, '');

    channel.send("Generating a new word..")
    .then(msg => {
        // display countdown with promise function :)
        return displayMessageCountdown(channel);
    })
    .then(countdownMessage => {
        // chain promise - sending message to channel
        return countdownMessage.edit(randomWord);
    })
    .then(randomMsg => {
        // setup collector
        channel.awaitMessages(function(userMsg) {
            // check that user created msg matches randomly generated word :)
            if (userMsg.id !== randomMsg.id && userMsg.content === randomWord)
                return true;
        }, {
            max: 1,
            time: 10000,
            errors: ['time'],
        })
        .then(function(collected) {
            // here, a message passed the filter!
            let successMsg = 'Success!\n';

            // turn collected obj into array
            let collectedArr = Array.from(collected.values());

            // insert time it took user to respond
            for (let msg of collectedArr) {
                let timeDiff = (msg.createdTimestamp - randomMsg.createdTimestamp) / 1000;

                successMsg += `Your time was ${timeDiff} seconds.\n`;
            }

            // send success message to channel
            channel.send(successMsg);
        })
        .catch(function(collected) {
            // here, no messages passed the filter
            channel.send(
                `There were no messages that passed the filter within the time limit!`
            );
        });
    })
    .catch(function(err) {
        console.log(err);
    });
}

This function extrapolates the countdown message display. The same message object is edited until the timer gets to zero, then the Promise gets resolved, which triggers the next .then(... method inside runWordGame.

// Function displays countdown message, then passes Message obj back to caller
function displayMessageCountdown(channel) {
    let timer = 3;

    return new Promise( (resolve, reject) => {
        channel.send("Starting in..")
        .then(function(msg) {
            var interval = setInterval(function () {
                msg.edit(`Starting in **${timer--}**..`);

                // clear timer when it gets to 0
                if (timer === 0) {
                    clearInterval(interval);
                    resolve(msg);
                }
            }, 1000);
        })
        .catch(reject);
    }); 
}

Let me know if you have questions, or if you are looking for a different end result.