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.
Related
So i made a discord bot, and i want to make a command that works only if the person who used the command have a role called "colorm"
this is this code
client.on('message', msg => {
if (msg.content === '!setupcolors'){
if(msg.guild.roles.find(role => role.name === "colorm")){
console.log("cmd: !setupcolors >> Command used.");
msg.reply(String('Hi! this command is under constuction'));
}
else{
msg.reply(String('Hi! you need to have a rank called "colorm" to acces this command.'));
console.log("Error[cmd: !setupcolors] >> No perms.");
}
}
});
thanks! :D
You can check whether a member has a specific role as follows:
msg.member.roles.find(r => r.name === "colorm")
Alternatively, you can use the ID of the role to check:
// First you need to retrieve the role:
const role = guild.roles.cache.find(r => r.name === "colorm")
// You can now check if the user has the role with:
member.roles.cache.has(role.id)
// (Optional)
// If 'role' isn't undefined and the user has the appropriate role you can continue
if (role && member.roles.cache.has(role.id)) {
// Do your stuff here, if the user has the role
}
Try using this - if(!msg.member.roles.cache.some(role => role.name === 'colorm'))
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.`
);
}
});
},
};
This is the current code that I have, I would like to make it where if you have a certain role then you can bypass the cooldown, also if anyone knows how to make a command that restricts a certain command to a certain channel, instead of having this really long message.channel.id.
const Discord = require('discord.js');
const fetch = require('node-fetch');
const talkedRecently = new Set();
module.exports.run = async(client, message, args, queue, searcher, ) => {
if (talkedRecently.has(message.author.id)) {
message.channel.send("Wait 1 minute before getting typing this again. " +'<#'+ message.author.id + '>');
} else {
switch(args[0].toLowerCase()){
case 'neko':
if(message.channel.id === '739002385531404288'||
message.channel.id === '646849145289834506'||
message.channel.id === '785079847763574794'||
message.channel.id === '782891383361896469'||
message.channel.id === '784417039425994772'){
fetch('https://nekos.life/api/v2/img/lewd')
.then(res => res.json())
.then(json => {
let nekoEmbed = new Discord.MessageEmbed()
.setTitle('Lewd Nekos! (=^・ω・^=)')
.setImage(json.url)
message.channel.send(nekoEmbed)
})
}else{
return}}
talkedRecently.add(message.author.id);
setTimeout(() => {
talkedRecently.delete(message.author.id);
}, 60000);
}
}
module.exports.config = {
name: "hentai",
aliases: ['ht']
}
```
Answering Your First Question:
Simply check if the member has a certain role. If they do, construct your if statement so that it will not fire if they have that role
Make sure to use message.member when checking roles
if (talkedRecently.has(message.author.id) && !message.member.roles.cache.has('bypass role id here')) {
// Your cooldown message
}
Learn more about Roles#has
Answering your 2nd question:
You can have an array of channel id's then use includes to check if any of the id's in the array match the current channel id
const ids = ['id1', 'id2', 'id3', 'id4'] // And so on
if (ids.includes(message.channel.id)) {
// Your Code
}
Learn more about Array.prototype.includes
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 trying to make a simple discord bot with node.js but when I try to use a command, nothing happens. Nothing that should get logged gets logged on the console except the discord bot going online.
const Prefix = '$';
bot.on('ready', () => {
console.log('The Bot Is Logged In');
});
bot.on('message', (message) => {
if (message.author.bot === true) return;
if (message.content.startsWith === Prefix) {
const [Cmd_name, ...args] = message.content
.trim()
.substring(Prefix.length)
.split(/\s+/);
if (Cmd_name === 'kick') {
if (args.length === 0) return message.reply('Please Provide A User ID');
const member = message.guild.members.cache.get(args[0]);
if (member) {
member.kick();
} else {
message.reply('That member was not found');
}
}
}
});
bot.login(process.env.DISCORD_BOT_TOKEN);
Can someone explain what went wrong?
String.prototype.startsWith is a function, not a string, and thus you must call it as a function.
if (message.content.startsWith(Prefix)) {