So I'm creating a Discord Application bot, Ban appeal Application that works within DM's only. I type the command p!apply and start the application, however whenever I try to cancel the application by typing cancel it only replies and does not actually cancel the whole form.
Here's my code:
let userApplications = {}
client.on("message", function(message) {
if (message.author.equals(client.user)) return;
let authorId = message.author.id;
if (message.content === prefix + "apply") {
if (!(authorId in userApplications)) {
userApplications[authorId] = { "step" : 1}
message.author.send("**__Team PhyZics Discord Ban Appeal Form__** \n If you're applying to get unbanned from our server, please fill this application out. We do not accept all applications, so take this application seriously and take your time when filling this out. \n \n - If you want to cancel this application please type `cancel`");
message.author.send("**Question 1: Which server did you get banned from?**");
}
} else {
if (message.channel.type === "dm" && authorId in userApplications) {
if (message.content.toLowerCase() === 'cancel') {
return message.author.send('Application Cancelled');
}
let authorApplication = userApplications[authorId];
if (authorApplication.step == 1 ) {
authorApplication.answer1 = message.content;
message.author.send("**Question 2: Why did you get banned/What reason did you get banned for?**");
authorApplication.step ++;
}
else if (authorApplication.step == 2) {
authorApplication.answer2 = message.content;
message.author.send("**Question 3: Why do you want to get unbanned?**");
authorApplication.step ++;
}
else if (authorApplication.step == 3) {
authorApplication.answer3 = message.content;
message.author.send("**Question 4: Any questions or concerns? If not, please type `no`.**");
authorApplication.step ++;
}
else if (authorApplication.step == 4) {
authorApplication.answer4 = message.content;
message.author.send("Your application has been submitted, please be patient and do not ask any staff member regarding to your ban appeal.");
client.channels.cache.get("790376360848785419")
.send(`**${message.author.tag}'s Application** \n **Q1**: ${authorApplication.answer1} \n **Q2:** ${authorApplication.answer2} \n **Q3:** ${authorApplication.answer3} \n **Q4:** ${authorApplication.answer4} `);
delete userApplications[authorId];
}
}
}
});
enter image description here
You're getting this problem because you're only returning a message Application cancelled without actually removing the user from your userApplications object.
To fix this, all you have to do is delete the entry from your object when the user cancels, like so:
if (message.content.toLowerCase() === 'cancel') {
delete userApplications[authorId];
return message.author.send('Application Cancelled');
}
Related
so i've been trying to make it so that every time the user sends a message there's a 50/50 chance that the bot reacts with an emoji, however the number is only picked every time i restart the bot. any ideas on how i can make it pick the number every time the command is triggered?
i tried to use setInterval but that didn't work so idk
here code;
const userID = "user id"
let random = Math.floor(Math.random()*2)
client.on('messageCreate', (message) => {
if(random === 1) {
if(message.author.id === userID) {
message.react('emoji');
}
}
});
Simply, define the random variable inside the messageCreate event.
Example:
const userID = "user id";
client.on('messageCreate', (message) => {
let random = Math.floor(Math.random() * 2);
if (random === 1) {
if (message.author.id === userID) {
message.react('emoji');
}
}
});
If you define random inside of the messageCreate event it means that a new random number is generated each time the even is called.
const userID = "user id"
client.on('messageCreate', (message) => {
let random = Math.floor(Math.random()*2)
if(random === 1) {
if(message.author.id === userID) {
message.react('emoji');
}
}
});
As Tyler2P has already shown an example, just wanted to explain why this works.
Thanks
So, I have these two (kind of messy) commands.
Here are the codes, though their content doesn't really matter (I guess so):
This one is a find the hidden ball inside the boxes game.
client.on("message", async message => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();
const { MessageCollector } = require("discord.js-collector");
function randomIntFromInterval(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min)
}
const rndInt = randomIntFromInterval(1, 5)
console.log(rndInt)
let answerBox = "";
if (command === "b" || command === "box") {
const user = message.author.id
switch(rndInt) {
case 1:
answerBox = 1;
break;
case 2:
answerBox = 2;
break;
case 3:
answerBox = 3;
break;
case 4:
answerBox = 1;
break;
case 5:
answerBox = 2;
break;
default:
message.channel.send("ERROR: If you received this message, please contact the support.");
};
message.channel.send(`A ball is hidden under the boxes below!!
:gift: ── :one:
:gift: ── :two:
:gift: ── :three:`);
const botMessage = await message.channel.send(`<#${user}>, Type how many coins you wanna bet.`);
const userMessage = await MessageCollector.asyncQuestion({
botMessage,
user: message.author.id,
});
let coinsBet = userMessage.content;
if (coinsTotal < coinsBet) {
await message.channel.send("You don't have enough coins to bet.");
} else if (isNaN(coinsBet) == false) {
const botMessage = await message.channel.send("Type which box do you think the ball is (1, 2 or 3).");
const userMessage = await MessageCollector.asyncQuestion({
botMessage,
user: message.author.id
});
let bet = userMessage.content;
if (userMessage.content == answerBox) {
await message.reply("You got it right and won double the coins!");
coinsTotal += coinsBet * 2;
} else if (isNaN(bet) == true || bet >= 4) {
await message.channel.send("That wasn't a valid input, please type =b ou =box.");
} else {
await message.reply(`You got it wrong and lost all the coins which you bet. The right answer was ${answerBox}.`);
coinsTotal -= coinsBet;
}
} else {
await message.channel.send("That wasn't a valid input, please type =b ou =box.");
}
};
});
And this other one opens up a store:
client.on("message", (message) => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();
if (command === "store") {
message.channel.send(`╭⋟────────────────────────╮
──•~ Type the product code (number) to buy it.
✦✧✦✧ STORE
» 1 - Green Seed: 0 coins.
╰────────────────────────⋞`)
message.channel.awaitMessages(m => m.author.id == message.author.id,
{max: 1, time: 10000}).then(collected => {
if (collected.first().content.toLowerCase() == '1') {
message.reply(`You bought 1 "Green seed" with success!`);
seedGreen++;
seedTotal++;
}
else
message.reply(`Something happened, and it wasn't possible to complete your order..`);
}).catch(() => {
message.reply('Your order was cancelled due to lack of response.');
});
};
});
Notice how none of that is actually connected to a database, but that's not the point. Thing is, everything is actually working without any issues, except one thing.
In the store code, if an user type "=b" or "=box" instead of "1" or another wrong answer, the bot starts the box game, and whenever an user answers the box game questions with "=store", it also starts the store code.
I tried to figure out how to prevent this from happening, once I created a "let isActive = false" variable on top of the code, and set it to true whenever the bot started the store or box code, and set to false when it was finished, so I could put (&& isActive === false) at the first if of those codes and let them execute only if they are "inactive" (not doing any event I coded).
But it was all in vain, it didn't really work, so I'm pretty much stuck here, and I would gladly accept any kind of help to overcome this.
There are many ways to solve this issue. Here's one that I thought out: At the beginning of the script, you can provide some sort of state prop to the client. I called it userState and set it to a Collection:
client.userState = new Discord.Collection();
Then whenever a user starts a multi-step command that you don't want them to execute while still in the command, you can set that user's id to some descriptive state, e.g. "boxGame":
client.userState.set(message.author.id, "boxGame");
And whenever you need to check if they're in a multi-step command, you can check with:
client.userState.get(message.author.id);
Which will either return "boxGame" or undefined, and you can easily differentiate between them to stop them or let them execute a command, for example, using a switch statement:
if (client.userState.has(message.author.id)) {
const state = client.userState.get(message.author.id);
switch (state) {
case "boxGame":
message.channel.send("you have to complete the box game first bro");
break;
default:
message.channel.send("You're doing something, finish that something first!");
}
}
And when they complete the box game, you can
client.userState.delete(message.author.id);
to clear their state.
Edit: Just reminding you again that this is only one solution on how to solve it, and there are probably better solutions to this than mine.
I want to add a reason to my blacklists (with the command !blacklist {userid} {reason}) which are visible in the embeds below like .addField ("💬 Reason:", somecode) how can I fix this?
if (command === "blacklist") {
if(!config["allowed-users"].includes(message.member.id)) return;
const user = client.users.cache.get(args[0]);
if(!user) {
return message.channel.send("This user does not exist")
}
if(blacklist.has(user.id)) {
return message.channel.send("This user is already on the blacklist")
}
blacklist.set(user.id, 'blacklisted');
let set = db.fetch(`g_${message.guild.id}`);
var embed = new Discord.MessageEmbed()
.setTitle(":warning: Blacklisted :warning:")
.setColor('#fc5a03')
.addField("👮 Moderator:", message.author.tag)
.addField("👤 User:", user.username)
.addField("🆔 User ID:", user.id)
.addField("🕒 Blacklisted on:", message.createdAt)
.setFooter("© 2020 - 2021 GlobalChat", "https://cdn.discordapp.com/avatars/759021875962576916/cc32b2b08fdd52ae86294516d34532c5.png?size=128")
.setThumbnail(user.avatarURL({ dynamic:true }))
.addField("Unblacklist?", "Please contact <#267818548431290369> or <#331736522782932993>");
client.guilds.cache.forEach(g => {
try {
client.channels.cache.get(db.fetch(`g_${g.id}`)).send(embed);
} catch (e) {
return;
}
});
}
First you'll want to check if there is no reason, this can be simple done by checking, for both approaches, if the second argument is undefined, like so
if (args[1] === undefined) {
const reason = "No reason.";
}
This solution will work for both approaches, since if the second argument is undefined there can be no more after it
You could take reason as an argument.
Inside the command add
const reason = args[1];
OR if you wanted to have the rest of the blacklist args dedicated to the reason you could add something along the lines of
let reason = ""
for (let i = 1; i < args.length; i++) {
// It's very important that i starts as 1, so we do not take the first argument into account for the reason
reason += args[i];
}
And then you can add to the embed
.addField("💬 Reason:", reason);
If you went with the first approach, the blacklist command would work like this
!blacklist 012345678910111213 the_reason_here
// or
!blacklist 012345678910111213 reason
The limitation to this approach is that a multi word reason isn't very intuitive.
If you went with the second approach though, the blacklist command would work like this
!blacklist 012345678910111213 The reason the user was banned and it can go on and on and on as long as the writer wants
You'll want to fetch the reason in the same way that you fetched the user id, like this:
const reason = args[1];
After that, in order to make sure that the reason doesn't show as undefined, you'll want to add a check in the form of an if statement, like this:
if (!reason) {
reason = "No reason";
}
After that, add .addField("💬 Reason:", reason) in the position of fields you want it to be.
Your code should look something like this:
if (command === "blacklist") {
if (!config["allowed-users"].includes(message.member.id)) return;
const user = client.users.cache.get(args[0]);
const reason = args[1];
if (!user) {
return message.channel.send("This user does not exist")
}
if (blacklist.has(user.id)) {
return message.channel.send("This user is already on the blacklist")
}
if (!reason) {
reason = "No reason";
}
blacklist.set(user.id, 'blacklisted');
let set = db.fetch(`g_${message.guild.id}`);
var embed = new Discord.MessageEmbed()
.setTitle(":warning: Blacklisted :warning:")
.setColor('#fc5a03')
.addField("👮 Moderator:", message.author.tag)
.addField("👤 User:", user.username)
.addField("🆔 User ID:", user.id)
.addField("🕒 Blacklisted on:", message.createdAt)
.addField(("💬 Reason:", reason)
.setFooter("© 2020 - 2021 GlobalChat", "https://cdn.discordapp.com/avatars/759021875962576916/cc32b2b08fdd52ae86294516d34532c5.png?size=128")
.setThumbnail(user.avatarURL({
dynamic: true
}))
.addField("Unblacklist?", "Please contact <#267818548431290369> or <#331736522782932993>");
client.guilds.cache.forEach(g => {
try {
client.channels.cache.get(db.fetch(`g_${g.id}`)).send(embed);
} catch (e) {
return;
}
});
}
For some reason which I don't know, my code is not realising that there is a channel that contains the message senders username.
To use this bot, you DM the bot, and then it creates a channel that is named your tag. An example, is that my discord tag is Llama#0729 and it creates a channel named llama0729. The issue is that when the code runs, before making the channel it checks to make sure that there is no channel that contains any part of the user's username. It always makes a channel though.
if (msg.channel.type == "dm") {
if (!client.guilds.cache.get('720571393636434031').channels.cache.find(channel => channel.name == msg.author.username.toLowerCase())) {
client.guilds.cache.get('720571393636434031').channels.create(msg.author.tag, {type: 'text'}).then((channel) => {
channel.setParent('778216162403942401');
});
};
} else {
console.log('A Channel For ', msg.author.tag, 'Has Already Been Made.');
return;
};
When you're checking to see if any channels exist, you should compare their tag not their username. I've slightly modified your code and also removed the # from their tag.
var newChannelName = msg.author.tag.replace("#", "").toLowerCase();
if (msg.channel.type == "dm") {
if (!client.guilds.cache.get('720571393636434031').channels.cache.find(channel => channel.name == newChannelName)) {
client.guilds.cache.get('720571393636434031').channels.create(newChannelName, {type: 'text'}).then((channel) => {
channel.setParent('778216162403942401');
})
.catch(error => {
console.log(error);
});
}
else
{
console.log('A Channel For ' + newChannelName + ' Has Already Been Made.');
return;
}
}
I'm working on a kick command for a Discord bot in Discord.js. How it works is a previous function passes an array of user IDs to attempt to kick from the server. For some reason, the for loop is repeating more than it should and the i value doesn't seem to change sometimes.
Here's my code:
exports.kick = async (guild, targets, member, reason, bot) => {
var modRoleQuery = await exports.queryModRole(guild, member, bot);
var outputMessage = '';
if (modRoleQuery === false && !member.hasPermission('ADMINISTRATOR') && member != guild.me) return `You do not have permission to execute this command.`;
else if (targets.length === 0) return `Command usage: ${config.prefix}kick <#mentions/IDs> [reason]`;
else if (!guild.me.hasPermission('KICK_MEMBERS')) return `I require the \`Kick Members\` permission to execute this command.`;
else if (targets.length > 10) return `You may only kick 10 members at a time.`;
else if (reason.length > 1000) return `The kick reason must not exceed 1000 characters. Currently, it is ${reason.length}.`;
for (i = 0; i < targets.length; i++) {
console.log(`checking ${targets[i]}, ${i}`);
let targetMember = guild.member(targets[i]);
if (targetMember) {
if (targetMember.kickable) {
let targetMemberModRole = await exports.queryModRole(guild, targetMember, bot);
if ((targetMemberModRole || targetMember.hasPermission('ADMINISTRATOR')) && !member.hasPermission('ADMINISTRATOR')) {
outputMessage += `Unable to kick \`${targetMember.user.tag}\`: Only administrators can kick people with the moderator role and/or admin perms.\n`
} else {
await targetMember.user.send(`You were kicked from ${targetMember.guild.name} by ${member.user.tag}:\nReason: \`${reason}\``).catch(err => {});
await targetMember.kick(`[${member.user.tag}] ${reason}`);
exports.modLogEvent(bot, guild, `KICK`, targetMember.user, member.user, reason);
outputMessage += `Successfully kicked \`${targetMember.user.tag}\`\n`;
}
} else {
outputMessage += `Unable to kick \`${targetMember.user.tag}\`: I don't have permission to kick them.\n`;
}
} else {
outputMessage += `Unable to kick \`${targets[i]}\`: They don't seem to be in this server.\n`;
console.log(`${targets[i]} is not a member`)
}
}
outputMessage += `**Kick Reason:**\n\`${reason}\``;
return outputMessage;
}
When the size of the array is 1, this works as expected, however when it is more than 1, it doesn't. I've put in some console.log() functions for debugging purposes.
For some reason, the i value gets stuck on 1. I also ran it a bit earlier (this is before I added the console.log()s) and it behaved even more oddly:
I've been trying to debug this for over a day now and I'm not getting anywhere. Any assistance would be greatly appreciated.