I've been trying to code a Discord bot and I can't figure out how to make it wait until you say Y or N. Right now, I'm trying to code the ban command and it works pretty well until it asks you to say Y or N. Then once it asks that and you answer, nothing happens.
Here's the code:
module.exports = {
name: 'ban',
description: 'This bans a member!',
execute (message, args){
var member = message.mentions.users.first();
if(member){
var memberTarget = message.guild.members.cache.get(member.id);
message.channel.send(`Are you sure you want to ban ${member}? (Y or N)`);
var messagethingy = message.first()
var askingBan = ('1')
do { if (messagethingy.content.toLowerCase === 'y' || messagethingy.content.toLowerCase === 'yes' || messagethingy.content.toLowerCase === 'n' || messagethingy.content.toLowerCase === 'no'); {
if (messagethingy.content.toLowerCase === 'no' || messagethingy.content.toLowerCase === 'n') {
message.channel.send('The Action has been cancelled')
var askingBan = ('0')
return
} else if (messagethingy.content.toLowerCase === 'y' || messagethingy.content.toLowerCase === 'yes') {
message.channel.send(`You have banned ${member}!`)
memberTarget.ban();
var askingBan = ('0')
}}
}
while (askingBan = '1');
} else {
message.channel.send("You couldn't ban that member!");
}
}
}
FYI these commands are in a different thingy. The main commands are in main.js and the command that senses when you say ban works perfectly fine.
Instead of a do-while loop, you can use a message collector. You can send a confirmation message and in the same channel set up a collector using createMessageCollector.
For its filter, you can check if the incoming message is coming from the same user who want to ban the member, and check if the message content is one of the accepted answers (y, yes, n, no). You can convert the message to lowercase to make it case insensitive.
You can also add some options, like the maximum number of accepted answers, and the maximum time the collector is collecting messages. I set it to one minute, and after a minute it sends a message letting the original poster know that the action is cancelled.
module.exports = {
name: 'ban',
description: 'This bans a member!',
async execute(message, args) {
const member = message.mentions.members.first();
if (!member) {
return message.channel.send('You need to mention a member you want to ban!');
}
// TODO: check if message.author can ban users
const confirmation = await message.channel.send(`Are you sure you want to ban ${member}? (Y or N)`);
const answers = ['y', 'yes', 'n', 'no'];
const filter = (m) =>
answers.includes(m.content.toLowerCase()) &&
m.author.id === message.author.id;
const collector = confirmation.channel.createMessageCollector(filter, {
max: 1,
time: 60000,
});
collector.on('collect', async (m) => {
if (
m.content.toLowerCase() === answers[2] ||
m.content.toLowerCase() === answers[3]
) {
return message.channel.send(
`The action has been cancelled, ${member} is not banned.`
);
}
try {
await member.ban();
return message.channel.send(`You have banned ${member}!`);
} catch (error) {
return message.channel.send(`Oops, error: ${error}`);
}
});
collector.on('end', (collected, reason) => {
if (reason === 'time') {
message.channel.send(
`${message.author}, it's been a minute without confirmation. The action has been cancelled, ${member} is not banned.`
);
}
});
},
};
Related
I'm currently working on a bot where I need to go into DM's with a user, answer questions and update roles in the server.
My current problem is that it gives the role fine, but after the user has been given the role, the bot don't update the roles in it's memory.
So after the user has been given the first role, he needs to send a message in the server for the bot to knows his new roles, and I want to avoid that.
Example : Send message in server -> Bot DM's, answers the questions, bot gives role and send second question -> User answers the new question but bot don't see the user's new role.
function restart(msg, member, memberRole1){
if(msg.content == "!start"){
msg.author.send("Riddle1" )
member.roles.add(memberRole1)
}
}
function test(msg, memberRole,memberRole2,memberRole3,memberRole4, member){
console.log(client.guilds.cache.get('ServerID').members.cache.get(msg.author.id).roles)
if (client.guilds.cache.get('ServerID').members.cache.get(msg.author.id).roles.cache.some(role => role.name === 'Role1')){
try {
if(msg.channel.type == 'DM'){
if(msg.content == 'Answer1'){
member.roles.add(memberRole)
msg.author.send("Riddle2")
}
}
} catch (error) {
console.log(error)
}
}
else if(client.guilds.cache.get('ServerID').members.cache.get(msg.author.id).roles.cache.some(role => role.name === 'Role2')){
try {
if(msg.channel.type == 'DM'){
if(msg.content == 'Answer2'){
member.roles.add(memberRole2)
msg.author.send("Riddle3")
}
}
} catch (error) {
console.log(error)
}
}
else if(client.guilds.cache.get('ServerID').members.cache.get(msg.author.id).roles.cache.some(role => role.name === 'Role3')){
try {
if(msg.channel.type == 'DM'){
if(msg.content == 'Answer3'){
member.roles.add(memberRole3)
msg.author.send("Riddle4")
}
}
} catch (error) {
console.log(error)
}
}
else if(client.guilds.cache.get('ServerID').members.cache.get(msg.author.id).roles.cache.some(role => role.name === 'Role4')){
try {
if(msg.channel.type == 'DM'){
if(msg.content == 'Answer4'){
member.roles.add(memberRole4)
}
}
} catch (error) {
console.log(error)
}
}
}
client.on('messageCreate', (msg) => {
let server = client.guilds.cache.get('ServerID')
let memberRole1= server.roles.cache.find(role => role.name === "role1")
let memberRole= server.roles.cache.find(role => role.name === "role2")
let memberRole2= server.roles.cache.find(role => role.name === "role3")
let memberRole3= server.roles.cache.find(role => role.name === "role4")
let memberRole4= server.roles.cache.find(role => role.name === "FinalRole")
let member = server.members.cache.get(msg.author.id)
restart(msg, member, memberRole1)
test(msg, memberRole,memberRole2,memberRole3,memberRole4, member)
}
);
I've already tried to use the same function that is used in the IF, but as said, the bot don't update it's infos until the user send a message in the server.
Thanks for the help.
You can always force-update the member by doing:
member.fetch(true);
https://discord.js.org/#/docs/main/stable/class/GuildMember?scrollTo=fetch
I would not recommend doing this often, though. Instead, you should probably do this once per user if you don't know what riddle they're on, and then locally store state of what riddle they're on in an object. For example:
const userToRiddleNum = {};
const roleToRiddleNum = {
role1: 1,
role2: 2,
role3: 3,
'final role': 4,
};
// Later, in test() or 'messageCreate' or what not
if (!(member.user.id in userToRiddleNum)) {
// Make sure roles are up to date
await member.fetch(true);
// Set the user's riddle num to the highest
// riddle num of all their roles
userToRiddleNum[member.user.id] = Math.max(
...member.roles.cache.map((role) => roleToRiddleNum[role.name] || 0),
);
}
// Later
userToRiddleNum[member.user.id] // Up to date!
// Now the user solved a riddle:
userToRiddleNum[member.user.id]++
As you mentioned you use roles as the way to indicate what question the user is on currently, I would recommend doing something "easier", and that is using quick.db
With that, you can just keep track of peoples questions doing for example something like:
db.set(`${message.member.id}.question`, 1);
and then just check what question they are in
if(`${message.member.id}.question`) == 1){
//They are on question 1 do stuff -->
db.set(`${message.member.id}.question`, 2);
}
You can get familiar with quick.db documentation and play around with it.
I want the user to answer a "yes or no" question using reactions. However, there is a bug in which when the tagged user reacts to the question, the bot is not sending a message on whether or not the tagged user wants to negotiate. Here is my code below.
const yesEmoji = '✅';
const noEmoji = '❌';
client.on('message', (negotiate) => {
const listen = negotiate.content;
const userID = negotiate.author.id;
var prefix = '!';
var negotiating = false;
let mention = negotiate.mentions.users.first();
if(listen.toUpperCase().startsWith(prefix + 'negotiate with '.toUpperCase()) && (mention)) {
negotiate.channel.send(`<#${mention.id}>, do you want to negotiate with ` + `<#${userID}>`)
.then(async (m) => {
await m.react(yesEmoji);
await m.react(noEmoji);
//get an answer from the mentioned user
const filter = (reaction, user) => user.id === mention.id;
const collector = negotiate.createReactionCollector(filter);
collector.on('collect', (reaction) => {
if (reaction.emoji.name === yesEmoji) {
negotiate.channel.send('The mentioned user is okay to negotiate with you!');
}
else {
negotiate.channel.send('The mentioned user is not okay to negotiate with you...')
}
})
})
negotiating = true;
}
})
So far, the code displays the reaction but it does not make the bot send a message whether the tagged user is ok or not ok to negotiate with the user that tagged them.
UPDATE:
I managed to get the bot to send a message whether the tagged user is ok or not ok to negotiate with the user that tagged them. Now there is an error in which is shown after 10 seconds (specified time). Here is the updated code below:
const yesEmoji = '✅';
const noEmoji = '❌';
client.on("message", async negotiate => {
const listen = negotiate.content;
let mention = negotiate.mentions.users.first();
if(listen.toUpperCase().startsWith(prefix + 'negotiate with '.toUpperCase()) && (mention)) {
let mention = negotiate.mentions.users.first();
let msg = await negotiate.channel.send(`${mention} do you want to negotiate with ${negotiate.author}`);
var negotiating = false;
await msg.react(yesEmoji);
await msg.react(noEmoji);
const filter = (reaction, member) => {
return reaction.emoji.name === yesEmoji || reaction.emoji.name === noEmoji && member.id === mention.id;
};
msg.awaitReactions(filter, { max: 1, time: 10000, errors: ['time'] })
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === yesEmoji) {
negotiating = true;
negotiate.reply('The mentioned user agreed to negotiate with you!');
}
else return negotiate.reply('The mentioned user did not agree to negotiate with you.')
})
}
})
I have a much easier solution to your problem:
const yesEmoji = '✅';
const noEmoji = '❌';
let mention = negotiate.mentions.users.first();
if(mention.id === negotiate.author.id) return message.channel.send("You cannot tag yourself!");
let msg = await negotiate.channel.send(`${mention} do you want to negotiate with ${negotiate.author}`);
var negotiating = false;
await msg.react(yesEmoji);
await msg.react(noEmoji);
const filter = (reaction, member) => {
return (member.id === mention.id && reaction.emoji.name === yesEmoji) || (member.id === mention.id && reaction.emoji.name === noEmoji);
};
msg.awaitReactions(filter, { max: 1, time: 10000, errors: ['time'] })
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === yesEmoji) {
negotiating = true;
negotiate.channel.send('The mentioned user is okay to negotiate with you!');
}
else if (reaction.emoji.name === noEmoji) return negotiate.channel.send('The mentioned user is not okay to negotiate with you...')
}).catch(err => {
if(err) return message.channel.send(`${mention} did not react within the 10 seconds!`);
})
So first we got the two emojis, we want the user to react with. mention is our mentioned user, msg is the "yes or no" question and negotiating is set to false by default. At first we react to the question with our emojis. In this example I am using awaitReactions, because it is very simple to use. For this we need a filter. In this case I named the variable also filter. filter checks if the reaction wether is yesEmoji or noEmoji and if the user who reacted is mention (our mentioned user). Then in awaitReactions we want only 1 reaction (yes or no), and I set the time to 10 seconds, but you can change it if you want. After awaitReactions is set up we want to collect our reaction. This is done in .then(). collected gives us the reactions, and we only want the first one, so we store collected.first() in reaction. Now we have a really simple if-else statement. If the reacted emoji is yesEmoji, negotiating will be set to true and a message gets sent into the channel, otherwise it will only sent a message and return.
It is important to set negotiating only to true if the user reacted with yesEmoji. In your code it is true even if nothing happens, because as you run the command everything in that command code will be executed. and your last line there was negotiating = true;. And I think that is not what you wanted to do.
I'm creating a discord bot using the discord.js v12.2.0+ library. Im creating a !enslave command which gets the bot to ping the target person once every 2 seconds 60 times. So for example !enslave #Hello123 gets the bot to spam this "Torturing #Hello123 :evil:" but the bot doesn't if I do !enslave 35203573250237 and it sends "Torturing undefined :evil:". The long number being the discord user's id.
This is my enslave.js code:
module.exports = {
run: async(client, message, args) => {
if(!message.member.hasPermission('ADMINISTRATOR')) {
message.channel.send("You don't have permission to use that command.");
}
else {
try {
let counter = 0;
message.delete()
let user = message.mentions.members.first() || await message.guild.members.fetch(args[0])
console.log(args[0])
let i = setInterval(function(){
const bot = client.emojis.cache.get('712787936734609419');
message.channel.send(`Torturing ${user} ${bot}`);
counter++;
if(counter === 60) {
clearInterval(i);
}
}, 2000);
}
catch(err) {
console.log(err);
}
}
},
aliases: [],
description: 'Make ImmortusMC torture someone'
}
This is my message.js code:
const PREFIX = process.env.PREFIX;
module.exports = (client, message) => {
if(message.author.bot) return;
if(!message.content.startsWith(PREFIX)) return;
let cmdName = message.content.substring(message.content.indexOf(PREFIX)+1).split(new RegExp(/\s+/)).shift();
let argsToParse = message.content.substring(message.content.indexOf(' ')+1);
if(client.commands.get(cmdName))
client.commands.get(cmdName)(client, message, argsToParse);
else
console.log("Command does not exist.");
};
Use message.guild.members.fetch(args[0]) instead of message.guild.members.cache.get(args[0]).
The reason why you're getting undefined is that the member has not been cached yet so you can't get them using the members cache.
let user = message.mentions.members.first() || await message.guild.members.fetch(args[0])
Sorry for the late answer, but ry:
let user = message.mentions.members.first() || message.guild.members.cache.get(args[0]);
You should use .get() when you are going to use the IDs. I also removed the await and added the ; at the end.
When I or some random user try to use the !clear command I see this message in my channel.
"Yeah... That's not a number? I also can't delete 0 messages by the way.
Something went wrong... " + this error message.
TypeError [MESSAGE_BULK_DELETE_TYPE]: The messages must be an Array, Collection, or number.
In my console I get this error msg:
(node:28184) UnhandledPromiseRejectionWarning: TypeError [INVALID_TYPE]: Supplied options is not an object.
this is my clear.js script:
const discord = require("discord.js");
module.exports.run = async (bot, message, args) => {
if (message.deletetable) {
message.delete();
}
// Member doesn't have permission
if (!message.member.hasPermission("MANAGE_MESSAGES")) {
message.channel.send("You can't delete messages...").then(m => m.delete(5000));
}
// Check if args[0] is a number
if (isNaN(args[0]) || parseInt(args[0]) <= 0) {
message.channel.send("Yeah... That's not a number? I also can't delete 0 messages by the way.").then(m => m.delete(5000));
}
// Maybe the bot can't delete messages
if (!message.guild.me.hasPermission("MANAGE_MESSAGES")) {
message.channel.send("Sorry... I can't delete messages.").then(m => m.delete(5000));
}
let deleteAmount;
if (parseInt(args[0]) > 100) {
deleteAmount = 100;
} else {
deleteAmount = parseInt(args[0]);
}
message.channel.bulkDelete(deleteAmount, true)
.then(deleted => message.channel.send(`I deleted \`${deleted.size}\` messages.`))
.catch(err => message.channel.send(`Something went wrong... ${err}`));
}
module.exports.help = {
name: "clear"
}
Thanks in advance!
Greetings
You must return when one condition is not true.
For the command works you must give a number of messages to clear: !clear <Number>.
//...
// Member doesn't have permission
if (!message.member.hasPermission("MANAGE_MESSAGES")) {
return message.channel.send("You can't delete messages...").then(m => m.delete(5000));
}
// Check if args[0] is a number
if (isNaN(args[0]) || parseInt(args[0]) <= 0) {
return message.channel.send("Yeah... That's not a number? I also can't delete 0 messages by the way.").then(m => m.delete(5000));
}
// Maybe the bot can't delete messages
if (!message.guild.me.hasPermission("MANAGE_MESSAGES")) {
return message.channel.send("Sorry... I can't delete messages.").then(m => m.delete(5000));
}
//...
You can find more information here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return
Hope this help !
I have created a discord bot recently using node js which when I do !purge, responds with Unknown command, do !help to view a list of command but after saying it, it is purging the messages. That is, it works well but posting that error message. I don't know what's the problem please help me
const commando = require('discord.js-commando');
const bot = new commando.Client();
const prefix = '!';
bot.on('message', message => {
let msg = message.content.toUpperCase();
let sender = message.author;
let cont = message.content.slice(prefix.length).split(" ");
let args = cont.slice(1);
if (msg.startsWith(prefix + 'PURGE')) {
async function purge() {
message.delete();
if (isNaN(args[0])) {
message.channel.send('Please input a number of messages to be deleted \n Syntax: ' + prefix + 'purge <amount>');
return;
}
const fetched = await message.channel.fetchMessages({limit: args[0]});
console.log(fetched.size + ' messages found, deleting...');
// Deleting the messages
message.channel.bulkDelete(fetched)
.catch(error => message.channel.send(`Error: ${error}`));
}
purge();
}
});
bot.login('MY BOT TOKEN HERE');
Right now you're using the discord.js-commando library. Any reason you decided to use that library? It looks like you're just using standard discord.js functions like bot.on, message.channel.send, message.channel.fetchMessages, message.channel.bulkDelete...
You should be good just useing the standard discord.js library, starting your code with this:
const Discord = require('discord.js');
const bot = new Discord.Client();
You can find this code on the main "Welcome" page of Discord.js
Edit:
I'm still not sure why you're using discord.js-commando, but that doesn't matter. Here's an example command I came up with using the discord.js-commando library:
const commando = require('discord.js-commando');
class PurgeCommand extends commando.Command {
constructor(client) {
super(client, {
name: 'purge',
group: 'random', // like your !roll command
memberName: 'purge',
description: 'Purge some messages from a Text Channel.',
examples: ['purge 5'],
args: [
{
key: 'numToPurge',
label: 'number',
prompt: 'Please input a number ( > 0) of messages to be deleted.',
type: 'integer'
}
]
});
}
run(msg, { numToPurge }) {
let channel = msg.channel;
// fail if number of messages to purge is invalid
if (numToPurge <= 0) {
return msg.reply('Purge number must be greater than 0');
}
// channel type must be text for .bulkDelete to be available
else if (channel.type === 'text') {
return channel.fetchMessages({limit: numToPurge})
.then(msgs => channel.bulkDelete(msgs))
.then(msgs => msg.reply(`Purge deleted ${msgs.size} message(s)`))
.catch(console.error);
}
else {
return msg.reply('Purge command only available in Text Channels');
}
}
};
module.exports = PurgeCommand
I'd also recommend using a new type instead of integer so you can validate the user's response and make sure they enter a number greater than 0.
If you need help setting up an initial discord.js-commando script, I'd take a look at this repo provided by the Discord team: https://github.com/discordjs/Commando/tree/master/test
You might wanna use this. This purge command is intended for discord.js v11.5.1 and I haven't tested to see if it works on v12, but I think this might work for you. I should say that THIS DELETES ALL THE CONTENT INSIDE THE CHANNEL (Nested command)
exports.run = (bot, message, args) => {
let filter = m => message.author.id === message.author.id;
message.channel.send("Are you sure you wanna delete all messages? (y/n)").then(() => {
message.channel.awaitMessages(filter, {
max: 1,
time: 30000,
errors: ['time']
})
.then(message => {
message = message.first();
if (message.content.toUpperCase() == "YES" || message.content.toUpperCase() == "Y") {
message.channel.bulkDelete(100);
} else if (message.content.toUpperCase() == "NO" || message.content.toUpperCase() == "N") {
message.channel.send("Terminated").then(() => {message.delete(2000)});
} else {
message.delete();
}
})
.catch(collected => {
message.channel.send("Timeout").then(() => {message.delete(2000)});
});
}).catch(error => {
message.channel.send(error);
});
};