Making the bot stop sending messages if a user hasn't sent a message within x minutes - discord.js

I have a !trivia command which has 4 functions and inside the functions I have a .then() function and .setTimeout(). The problem is that once someone triggers the command, it will only stop once someone say '!stop'. How can I make it so it stops if no one typed in that channel within 5 minutes?

Use .awaitMessages()
let userUsingTheCommand = "<USER_ID>";
let filter = msg => msg.author.id = userUsingTheCommand;
// Errors: ['time'] treats ending because of the time limit as an error
function wait() {
channel.awaitMessages(filter, {
max: 1,
time: 60000 * 5,
errors: ['time']
})
.then(wait)
.catch(() => {
console.log("Time to stop!");
});
}

Related

Discord.js not sending message in channel, but does send number in console

I'm a very noob coder so I followed a tutorial to do most of this. I'm having an issue where a command used for my bot returns a number into the console instead of sending the message into the Discord channel. I noticed that "channel" in message.channel.send is a different color from the working blocks that did send messages. Here's a screenshot of that.
Also, client and args are said to be undeclared despite already being declared at the start. It seems like the module.exports isn't using any variables I declared before the if statement, so that might be causing the problem? Thanks folks.
module.exports={
name: "quiz",
description: "Test your knowledge about the Terrans.",
category: "Trivia",
run: async(client, message, args)=>{
let q = questions[Math.floor(Math.random()*(questions.length))];
let i = 0;
const Embed = new MessageEmbed()
.setTitle(q.title)
.setDescription(q.options.map(opt=>{
i++;
return `${i} - ${opt}\n`
}))
embed.setFooter({text: "Reply with the number of the choice. You have 15 seconds."})
message.channel.send({embeds:[Embed]})
try{
let msgs = await message.channel.awaitMessages(u2=>u2.author.id===message.author.id, {time: 15000, max: 1, errors: ["time"]})
if(parseInt(msgs.first().content)==q.correct){
return message.channel.send(`Right on target.`)
}else{
return message.channel.send(`You\'re off the mark.`)
}
}catch(e){
return message.channel.send(`Too slow!`)
}
}
}
On the lines 75, 77 and 80, you're sending the messages as a string. This would work in discord.js v12 but as you have to send objects now, you should be using message.channel.send({content: 'Your message here'});. Also don't understand why you are using the module.exports inside a command (check the screenshot to understand what I mean) as you only do that if you're using multiple files. You should only keep the code inside the run: function(bot, message, args) and remove everything from module.exports around it so you only have the following left:
let q = questions[Math.floor(Math.random()*(questions.length))];
let i = 0;
const Embed = new MessageEmbed()
.setTitle(q.title)
.setDescription(q.options.map(opt=>{
i++;
return `${i} - ${opt}\n`
}))
embed.setFooter({text: "Reply with the number of the choice. You have 15 seconds."})
message.channel.send({embeds:[Embed]})
try{
let msgs = await message.channel.awaitMessages(u2=>u2.author.id===message.author.id, {time: 15000, max: 1, errors: ["time"]})
if(parseInt(msgs.first().content)==q.correct){
return message.channel.send({content: `Right on target.`})
}else{
return message.channel.send(`You\'re off the mark.`)
}
}catch(e){
return message.channel.send({content: `Too slow!`})
}
Also I don't understand why you are using a map function inside the setDescription function as it returns an Array and you need to use a string.

Discord.js v13 awaitMessages not working properly

I have a guildMemberAdd event which whenever a user joins a server, it runs this code:
const msg = await member.send('hi')
const filter = message => message.content === "e"
msg.channel.awaitMessages({ filter, max: 1, time: 10000, errors: ['time'] }).then(c => {
console.log("pog")
}).catch(e => console.log("Failed!"));
Although, whenever I reply to the bot with "e", it does absolutely nothing, and after the 10 seconds have passed, it logs "Failed!" in the console.
What am I doing wrong here? There are no error outputs in the console either from execution of the code above.

How to store a value to a variable when a user reacts to a message?

I have figured out how to do make a bot react with its message from the following code:
if(message.content === "!start"){
message.channel.send(serve).then(message => {
message.react('764193096060764211');
})
}
(serve is an embed stored in a variable)
I want the user to react with it and the bot to do something with that information, for an example, storing the value 1 to a variable called startingServe. If the user doesn't react within 5 seconds, I want the bot to message "Gamer Ended". How do I do this? Looking forward for the help from this community! If there's anything else needed from me to answer this question, it is fine to ask.
Use something like this:
var startingServe = 0
message.awaitReactions(filter, { max: 1, time: 5000, errors: ['time'] })
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.id == "764193096060764211") {
startingServe = 1
} else {
message.channel.send('Gamer Ended')
}
})
.catch(collected => {
message.channel.send('Gamer Ended');
});
Source and more info on this guide page.

Discord.js message collector in a loop for tic tac toe

So i started to make a discord bot using discord.js which has a command for tic tac toe.
I tried using a message collector, like this in a while loop. After it enters the loop nothing happens. I added a console.log to see if the totalRouds variable is modifying and it was, so the loop somehow passed over the message collector code and executed just the last line.
while(numberOfrounds < 9){
const filter = m => m.author.id === message.author.id;
message.reply('Enter a position:');
message.channel.awaitMessages(filter, {max: 1, time: 3000, errors: ['time']}).then(collected => {
// code for drawing a canvas
}).catch(err => {
console.log(err);
});
console.log(totalRouds);
numberOfrounds ++;
}
.awaitMessages() returns a Promise that resolves into your collected message data asynchronously. That means that while your last log statement runs immediately after you start collecting messages, the collected messages are only available and thus processed at a later time.
To illustrate that, let me tidy your code a little and add some logs in the order that your code would normally run:
while (numberOfrounds < 9) {
console.log("1");
const filter = m => m.author.id === message.author.id;
message.reply('Enter a position:');
console.log("2");
message.channel.awaitMessages(
filter,
{ max: 1, time: 3000, errors: ['time'] }
).then(collected => {
console.log("5, after resolving, the collected data is only now avaiable");
}).catch(err => {
console.log(err);
});
console.log("3");
console.log(totalRouds);
numberOfrounds++;
console.log("4, immediately starts the next loop, back to #1 again");
}
I presume that your totalRouds variable is defined within the callback function passed into .then(). So other than the typo (let's fix that), your variable would be defined in the wrong scope and thus totalRounds would always remain undefined, even after the Promise resolves with your collected messages, you process those messages, you set totalRounds within the callback function etc. So here is our updated snippet:
while (numberOfrounds < 9) {
const filter = m => m.author.id === message.author.id;
message.reply('Enter a position:');
message.channel.awaitMessages(
filter,
{ max: 1, time: 3000, errors: ['time'] }
).then(collected => {
let totalRounds = 1 // Do your processing here
console.log(totalRounds); // This should log as expected
}).catch(err => {
console.log(err);
});
numberOfrounds++;
}
But this is still probably not the behaviour you are looking for. Why? Your bot will attempt to send all 9 replies (assuming your numberOfRounds starts at 0 earlier) at once, at which point Discord.js will automatically send them in batches to avoid spamming the API, and all message collectors would be waiting concurrently. You probably intend to "pause" or suspend processing until the Promise returned by .awaitMessages() resolves and you have finished processing the returned data, causing synchronous behaviour whilst using an asynchronous method call (therefore you say "the loop somehow passed over the message collector code and executed just the last line"). To do this, we can use async-await:
/*
You have not provided your full code,
so what you need to do is mark your message event's
callback function as async.
Refer to the linked article on MDN.
*/
while (numberOfrounds < 9) {
const filter = m => m.author.id === message.author.id;
message.reply('Enter a position:');
/*
Then, wait for the Promise returned by
this promise chain to resolve
before resuming operation
and moving on to the next iteration.
*/
await message.channel.awaitMessages(
filter,
{ max: 1, time: 3000, errors: ['time'] }
).then(collected => {
let totalRounds = 1
console.log(totalRounds);
}).catch(err => {
console.log(err);
});
numberOfrounds++;
}
My terminology may not be 100% correct, but this is my understanding. Feel free to comment if improvements can be made.

Switching a prefix for a command in discord.js

First post on this site so my bad if I don't format something correctly. I've been trying to make a change prefix command and I don't know how to check next message content for a variable to use instead of the old prefix.
msg.reply("Which prefix do you want?");
const collector = new Discord.MessageCollector(msg.channel, m => m.author.id === msg.author.id, { time: 5000 });
console.log(collector)
collector.on('collect', msg => {
newprefix=collector.content();
msg.reply('Prefix succesfully changed!');
});
I strongly advise using the awaitMessages method. First you need to define a filter, a delegate function that returns true if the reaction is one you want. Typically in a command/response setting, you want a filter that indicates the original command invoker replied.
const filter = (reaction, user) => {
return user.id === msg.author.id;
};
You can then define options for your awaitMessages. (It's quite common to do this in-line with the awaitMessages method, that's fine if that is more clear to you)
const options = {
max: 1,
time: 30000,
errors: ['time']
}
The above example accepts 1 message, if given in 30 seconds, otherwise it throws an exception.
Finally, you are ready to begin...
msg.reply("Which prefix do you want?").then(() => {
msg.channel.awaitMessages(filter, options)
.then(collected => {
newprefix = collected.first();
// Record newprefix to a persistent config here
msg.reply('Prefix successfully changed!');
})
.catch(collected => {
msg.reply("You didn't respond fast enough.");
});
}
Keep in mind, this occurs asynchronously, so if you need to write newprefix somewhere, a JSON config file for example, you should do from within the scope of the .then

Resources