Currently, I am using Discord.js to make a bot.
client.on('message', (message) => {
if (message.content === '$wa') {
message.channel.send({ embed: exampleEmbed }).then((embedMessage) => {
embedMessage.react('❤️');
embedMessage
.awaitReactions(
(filter = (reaction, user) => {
return reaction.emoji.name === '❤️' && user.id === message.author.id;
}),
{ max: 2, time: 60000, errors: ['time'] }
)
.then((collected) => {
const reaction = collected.first();
if (reaction.emoji.name === '❤️') {
message.channel.send(
':sparkling_heart: **Hanno** and **Roronoa Zoro** are now married! :sparkling_heart:'
);
}
});
});
}
});
If I type $wa the bot shows some embed. But the thing is that it automatically adds a heart to the embed. I want that if I click the heart as well (for a total count of 2 hearts) it executes the if statement at the bottom.
I've tried multiple methods but none worked. This is also my first time with Discord.js
You need to account for the bots own reaction. I recommend redoing your filter implementation to something like this.
The key takeaway is that you have to add !user.bot to the filter so that the bot's own reaction is ignored
const filter = (reaction, user) => {
return reaction.emoji.name === "❤️" && user.id === message.author.id && !user.bot
}
embedMessage.awaitReactions(filter, { max: 1, time: 60000, errors: ['time'] })
Please try this:
client.on('message', message => {
if (message.content === '$wa') {
message.channel.send({ embed: exampleEmbed }).then(embedMessage => {
embedMessage.react('❤️');
embedMessage.awaitReactions(filter = (reaction, user) => {
return reaction.emoji.name === '❤️' && user.id === message.author.id;
},
{ max: 1, time: 60000, errors: ['time'] }).then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === '❤️') {
message.channel.send(':sparkling_heart: **Hanno** and **Roronoa Zoro** are now married! :sparkling_heart:');
}
}).catch(() => {
// user didn't react with ❤️ in given time (here: 60 secs)
message.channel.send('no reaction in time');
});
});
}
});
I changed the max value to 1 and also added a catch block to catch a UnhandledPromiseRejectionWarning. If you don't do so in the future, it might exit the program with an error. You can of course execute whatever you like when the user didn't react to the embedMessage in time.
Related
I'm creating a discord bot command that gives a question and two emojis on the question's message for user to react. If you select the wrong emoji, the bot will tell you "Wrong", react again on the message, and wait for the user to react. I want to put this into an infinite loop that only stops when the user chooses the correct emoji. This is what I have worked so far:
message.channel.send(`Question?`).then(sentMessage => {
sentMessage.react('✅');
sentMessage.react('❌');
const filter = (reaction, user) => {
return ['✅', '❌'].includes(reaction.emoji.name) && user.id != `${bid}`; // bid = bot's id
};
sentMessage.awaitReactions({ filter, max: 1, time: 60000, errors: ['time'] }).then(collected => {
var reaction = collected.first();
if (reaction.emoji.name === '❌') {
var check = true;
while (check) {
console.log('?');
message.channel.send('Wrong').then(sentMessage => {
sentMessage.react('✅');
sentMessage.react('❌');
const filter = (reaction, user) => {
return ['✅', '❌'].includes(reaction.emoji.name) && user.id != `${bid}`;
};
sentMessage.awaitReactions({ filter, max: 1, time: 60000, errors: ['time'] }).then(collected => {
var reaction = collected.first();
if (reaction.emoji.name == '✅') check = false;
});
});
}
}
});
});
The idea is when the user finally reacts ✅ after first reacting some ❌, check will become false and the loop will stop. However, after first choosing ❌, the while loop is not running any code inside it other than looping console.log('?'). Can someone point out where I did wrong?
In your code, you send Wrong and put the reaction check logic inside then and wrap with while.
However, since Channel.send returns a Promise, it will end almost instantly, continue the loop while doing Channel.send and reaction logic simultaneously.
You can use an async function and call it recursively.
So the code would be this:
message.channel.send(`Question?`).then(sentMessage => {
sentMessage.react('✅');
sentMessage.react('❌');
const filter = (reaction, user) => {
return ['✅', '❌'].includes(reaction.emoji.name) && user.id != `${bid}`; // bid = bot's id
};
sentMessage.awaitReactions({ filter, max: 1, time: 60000, errors: ['time'] }).then(collected => {
var reaction = collected.first();
if (reaction.emoji.name === '❌') {
async function reactionLoop() {
console.log('?');
let sentMessage = await message.channel.send('Wrong');
await sentMessage.react('✅');
await sentMessage.react('❌');
const filter = (reaction, user) => ['✅', '❌'].includes(reaction.emoji.name) && user.id != `${bid}`;
let collected = await sentMessage.awaitReactions({ filter, max: 1, time: 60000, errors: ['time'] })
var reaction = collected.first();
if (reaction.emoji.name == '✅') await reactionLoop();
}
reactionLoop();
}
});
});
This is my sample code:
const Discord = require('discord.js')
module.exports = {
name: 'help',
description: 'help',
execute(message, args) {
const embed = new Discord.MessageEmbed()
.setTitle('Page One')
.setDescription('This is page one')
message.channel.send(embed).then((msg) => {
msg.react('⬅️')
msg.react('➡️')
const filter = (reaction, user) => {
return ['⬅️', '➡️'].includes(reaction.emoji.name) && user.id === message.author.id;
};
msg.awaitReactions(filter, { max: 1, time: 60000, errors: ['time'] })
.then(collected => {
const reaction = collected.first()
if (reaction.emoji.name === '⬅️') {
message.channel.send(embed)
}
else {
const secEmbed = new Discord.MessageEmbed()
.setTitle('Help')
.setDescription('This is help page 2')
msg.edit(secEmbed);
}
})
})
}
}
This is working, but when i try to move it backwards to the previous page after i have moved to the second page, the thing stops working.... I meant, then the embed pages won't move forth or back. Is there anyway to solve this prob? Thank You.
You could simply call msg.awaitReactions() again; wrap it in a function to make it easier to repeat the reaction collection.
Using msg.awaitReactions():
message.channel.send(embed).then((msg) => {
msg.react("⬅️");
msg.react("➡️");
function handleReactions() {
const filter = (reaction, user) => {
return ['⬅️', '➡️'].includes(reaction.emoji.name) && user.id === message.author.id;
};
msg.awaitReactions(filter, {max: 1, time: 60000, errors: ["time"]})
.then((collected) => {
const reaction = collected.first();
const name = reaction.emoji.name;
if (name === "⬅️") {
// edit page a certain way
handleReactions();
} else if (name === "➡️") {
// edit page another way
handleReactions();
}
});
}
handleReactions();
});
Another way would be to listen for reaction events:
message.channel.send(embed).then((msg) => {
msg.react("⬅️");
msg.react("➡️");
// handles reactions
function handleReaction(reaction, user) {
// ignore the reaction if the reaction is on a different message
if (reaction.message.id !== msg.id && user.id === message.author.id) {return;}
const name = reaction.emoji.name;
if (name === "⬅️") {
// move page a certain way
} else if (name === "➡️") {
// move page another way
}
}
// add a listener for message reactions
message.client.on("messageReactionAdd", handleReaction);
// wait a specific amount of time to stop listening
setTimeout(() => {
// remove the listener
message.client.off("messageReactionAdd", handleReaction);
}, 60000); // 60 seconds
/*
You could add functions to reset the timeout after each reaction as well.
*/
});
I'm trying to display who win the poll but i run into a problem. While I want to get the number of the reactions with
.addField("🔴:", `${results.get("🔴").count}`)
My console says that the count is undefined. I've tried to search it but I didn't find anything and I tried so many ways but nothing.
The code:
const BaseCommand = require('../../utils/structures/BaseCommand');
const Discord = require("discord.js")
module.exports = class HelpCommand extends BaseCommand {
constructor() {
super('vote', 'moderation', []);
}
async run(client, message, args) {
const filter = m => m.author.id == message.author.id;
let embed = new Discord.MessageEmbed()
.setFooter(`${message.author.tag} started the poll`)
.setTimestamp();
message.channel.send('what the question is?');
try {
let msg = await message.channel.awaitMessages(filter, { max: 1, time: 15000, errors: ['time'] });
console.log(msg.first().content);
embed.setTitle(msg.first().content);
} catch (err) {
console.log(err);
message.channel.send('You run out of time! Pls type again the command \`~prefix~ vote\`');
}
message.channel.send('first option?');
try {
let msg = await message.channel.awaitMessages(filter, { max: 1, time: 15000, errors: ['time'] });
console.log(msg.first().content);
embed.addField(`[🔴] the first option:`, msg.first().content);
} catch (err) {
console.log(err);
message.channel.send('You run out of time! Pls type again the command \`~prefix~ vote\`');
}
message.channel.send('second option?');
try {
let msg = await message.channel.awaitMessages(filter, { max: 1, time: 15000, errors: ['time'] });
console.log(msg.first().content);
embed.addField(`[🔵] the second option`, msg.first().content);
} catch (err) {
console.log(err);
message.channel.send('You run out of time! Pls type again the command \`~prefix~ vote\`');
}
try {
await message.channel.bulkDelete(7)
.then(message.channel.send(embed).then(sentMessage => sentMessage.react('🔴')).then(reaction => reaction.message.react('🔵')));
} catch (err) {
console.log(err);
}
const filters = (reaction) => reaction.emoji.name === "🔴" || reaction.emoji.name === "🔵";
const results = await message.awaitReactions(filters, { time: 15000 })
let resultsEmbed = new Discord.MessageEmbed()
.setTitle(`the poll result`)
.setDescription(`the result of the poll: ${args.join(" ")}`)
.addField("🔴:", `${results.get("🔴").count}`)
.addField("🔵:", `${results.get("🔵").count //if i dont type here the .count then i've got this embed but after the "🔵": says'undefined' }`)
.setColor("#84daf8")
.setTimestamp()
message.channel.send(resultsEmbed);
}
}
A szavazás eredménye = The poll result in my language. I see this when i dont write the .count there: .addField("🔴:", `${results.get("🔴").count}`)
and i see this when i write .count
The problem was that the bot was trying to retrieve the reactions of a deleted message I believe. In order to fix this, you'll have to put your resultsEmbed code inside of your chained then methods.
Code:
try {
await message.channel.bulkDelete(7)
.then(message.channel.send(embed)
.then(sentMessage => sentMessage.react('🔴'))
.then(reaction => reaction.message.react('🔵'))
.then(reaction => {
const filters = (reaction) => reaction.emoji.name === "🔴" || reaction.emoji.name === "🔵";
reaction.message.awaitReactions(filters, { time: 15000 }).then(collected => {
console.log(collected);
if (collected.get("🔴") !== undefined && collected.get("🔵") !== undefined) {
let optionOne = collected.get("🔴").count;
let optionTwo = collected.get("🔵").count;
let resultsEmbed = new Discord.MessageEmbed()
.setTitle("the poll result")
.setDescription(`the result of the poll: ${args.join(" ")}`)
.addField("🔴:", `${optionOne}`)
.addField("🔵:", `${optionTwo}`)
.setColor('#')
.setTimestamp()
message.channel.send(resultsEmbed);
} else {
//there were no votes for one of the options, thus it will not be able to get property
message.channel.send("There were no votes for one of the options.");
}
})
})
);
} catch (err) {
console.log(err);
}
I currently have a Discord bot which reads information of a API that deals with a game server panel.
In this Bot there is tasks that are to start/restart/stop/kill the server. i want to give the option for the end user to react to a embed posted by a bot with a certain reaction to trigger these tasks.
The Command and embed that are posted by the bot are:
The code which currently checks which reaction has been triggered looks like this:
message.channel.send(embed).then(async (sentEmbed) => {
sentEmbed.react("🟩")
sentEmbed.react("🔁")
sentEmbed.react("🟥")
sentEmbed.react("❌")
const filter = (reaction, user) => {
console.log(reaction.emoji.name)
return reaction.emoji.name === '🟩' && user.id === message.author.id;
};
const collector = sentEmbed.createReactionCollector(filter, {time: 20000});
collector.on('collect', (reaction, user) => {
Client.startServer(args[0]).then((response) => {
const start_embed = new Discord.MessageEmbed()
.setTitle(response)
.setColor(settings.embed.color.default)
.setFooter(settings.embed.footer);
message.channel.send(start_embed);
}).catch((error) => {
message.channel.send(client.embederror(error))
});
});
const filter2 = (reaction, user) => {
return reaction.emoji.name === '🔁' && user.id === message.author.id;
};
const collector2 = sentEmbed.createReactionCollector(filter2, {time: 20000});
collector.on('collect', (reaction, user) => {
Client.restartServer(args[0]).then((response) => {
const restart_embed = new Discord.MessageEmbed()
.setTitle(response)
.setColor(settings.embed.color.default)
.setFooter(settings.embed.footer);
message.channel.send(restart_embed);
}).catch((error) => {
message.channel.send(client.embederror(error))
});
});
const filter3 = (reaction, user) => {
return reaction.emoji.name === '🟥' && user.id === message.author.id;
};
const collector3 = sentEmbed.createReactionCollector(filter3, {time: 30000});
collector.on('collect', (reaction, user) => {
console.log(`User Stopped There Server`);
});
const filter4 = (reaction, user) => {
return reaction.emoji.name === '❌' && user.id === message.author.id;
};
const collector4 = sentEmbed.createReactionCollector(filter4, {time: 30000});
collector.on('collect', (reaction, user) => {
console.log(`User Killed There Server`);
});
})
This code works for detecting the reactions onto the message, however when a user reacts with any reaction it runs all of the trigger code, so the bot posts two embeds which i have defined as what the bot should output when a reaction is triggered.
I just want the user to click one reaction, then the bot does something, then the use can click another and the bot does something else.
Thanks in advance
The issue was you used collector.on("collect") 4 times instead of using collector2, collector3 and collector4
It's best not to have variables like that since like it shows you might get confused
Plus you should not have 4 different filters and collectors, especially since you repeat a lot of the code
const validEmojis = ['🟩', '🔁', '🟥', '❌'];
const filter = (reaction, user) => {
return validEmojis.includes(reaction.emoji.name) && user.id === message.author.id;
};
const collector = sentEmbed.createReactionCollector(filter, { time: 20000, maxEmojis: 1 });
collector.on('collect', (reaction, user) => {
const name = reaction.emoji.name;
//you only use it in two cases but I assume you will use it for all later on
const embed = new Discord.MessageEmbed()
.setColor(settings.embed.color.default)
.setFooter(settings.embed.footer);
if (name === '🟩' || name === '🔁') {
const method = name === '🟩' ? "startServer" : "restartServer";
Client[method](args[0])
.then(response => {
embed.setTitle(response);
message.channel.send(start_embed);
}).catch((error) => {
message.channel.send(client.embederror(error))
});
} else if (name === '🟥') {
console.log(`User Stopped There Server`);
} else if (name === '❌') {
console.log(`User Killed There Server`);
}
});
How to fix this ? i want to delete message when user click reaction X
client.on('message', async message => {
if (message.channel.id === emojiChannelID) {
try {
await message.react('✅');
await message.react('✖');
} catch(err) {
console.error(err);
}
}
});```
There's an message.awaitReaction() in discord.js, that will return reactions from users
// Filter for only
const filter = function(reaction, user) {
return reaction.emoji.name === '✅' || reaction.emoji.name === '✖';
}
// {...}
let reactionMessage = await message.react('✅');
// Make sure to set max: 1 so that the promise returns after the first reaction
let reactionCollection = await reactionMessage.awaitReactions(filter, { max: 1});
// reactionCollection is a Collection<string, MessageReaction>
// Use first() to get the first (and only)
let reaction = reactionCollection.first();
Kian here,
This code should work for you,
if you would like I can go through and explain each line :)
Have a good day chief!
async function emojiMessage(message, validReactions) {
for (const reaction of validReactions) await message.react(reaction);
const filter = (reaction, user) => validReactions.includes(reaction.emoji.name) && (!user.bot)
return message
.awaitReactions(filter, {
max: 1,
time: 42000
})
.then(collected => collected.first() && collected.first().emoji.name);
}
async function deleteMessage(message) {
const emoji = await emojiMessage(message, ["✅", "❌"]);
console.log(emoji)
// if the emoji is a tick:
if (emoji === "✅") {
// delete their message
console.log("tick")
if (message.deletable == true) {
console.log("can delete")
console.log("attempting to delete")
message.delete()
}
if (!message.deletable == false) {
"cannot delete"
}
} else if (emoji === "❌") { // if the emoji is a cross
/*
* do something else
*/
return;
}
}
client.on('message', message => {
if (message.channel.id === emojiChannelID) {
// runs the function
deleteMessage(message)
}
/*
* do something else
*/
})
Note:
First upload 🎉
I've tried my best to make the code understandable/work , if there is any issues feel free to comment, I'll fix it :)
Example Usage:
const m = await message.channel.send('hi!');
reactionDelete(m, message, 20000); // assuming 'message' is the actual sent message
async function reactionDelete (botMessage, playerMessage, timeout) {
const filter = (reaction, user) => {
return ['🗑️'].includes(reaction.emoji.name) && user.id === playerMessage.author.id;
};
botMessage.react('🗑️');
botMessage.awaitReactions(filter, { max: 1, time: timeout})
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === '🗑️') {
botMessage.delete();
}
})
.catch(collected => {
if (botMessage.deletable) botMessage.reactions.removeAll();
});
};