Different cooldown length for different parts of a command - discord.js

I have a command called "work". This command has 3 parts, list, apply and regular work. When user runs -work list, available jobs are being listed, I don't want any cooldown for this part. -work apply changes the job of the user, and -work just generates random number. So, I want it like when user runs -work apply and change their job, a 1-day cooldown must be applied. And when user just passes -work I want a 1-hour cooldown. I thought of something like different parts of the command would return different strings, such as work_apply and work_work, and use that information to apply different cooldown lengths. But that isn't possible since I can't apply any cooldown without having the output from the command, and to have some output I must run the command. So I can't apply any cooldown without running it.

I dont really know how your command handler works so i will give you an idea.
you can try making a map and pushing the message author and the time they ran the command. once you done this, the next time the same person runs the code under the time limit, set it so that the command handler looks for the member in the map and if they find it, they check when they last ran the command and if its under the time limit, it returns the function
again i dont know how your command handler works but here is how i did it
PS. If your entire command is in 1 file then the code im gonna show wont work. you should try to edit some parts of the code to make it work to ur liking
// command handler file
const cooldowns = new Map();
let name = command.name;
if (!cooldowns.has(name)) {
cooldowns.set(name, new Discord.Collection());
}
if (!message.member.roles.cache.has('ROLE_ID')) { // role that bypass cooldown
const current_time = Date.now();
const time_stamps = cooldowns.get(name);
const cooldown_amount = (command.cooldown) * 1000;
if (time_stamps.has(message.author.id)) {
const expiration_time = time_stamps.get(message.author.id) + cooldown_amount;
if (current_time < expiration_time) {
message.reply({
content: `Please wait until the cooldown has ended`
});
return;
}
}
time_stamps.set(message.author.id, current_time);
setTimeout(() => time_stamps.delete(message.author.id), cooldown_amount);
}
// command file
module.exports = {
name: 'commandname',
cooldown: 15 // this has to be in seconds | you can type '0' if there r no cooldowns
async execute(YOUR PARAMETERS) {
// command code
}
}

Related

Discord.js - Getting multiple reactions to execute a command through awaitReactions method

I'm currently in the process of making a little game of TicTacToe, and the idea I had in mind is to make it so instead of the channel being spammed with constant embeds asking for the person's next move, is to simply make it reaction-based, where you get to pick 1 out of 9 reactions (And of course, you wont be able to pick it again if the other player has already picked it).
I have never really worked with requiring multiple reactions, therefore I'd like to ask your help on how exactly to make it so that the message command execution isn't a one-time thing, but will go on until there's eventually a winner.
So far, with the code I have written, this does work 2 times, but then it randomly stops and no longer works.
In addition, when I'm trying to declare a spot as an x or a circle, the spot turns completely blank.
Please help!
The code I have so far:
https://sourceb.in/S7cayfoYjp
Edit: I have now also found that the bot at first kind of skips the whole awaitReactions code. I used 'console.log(i)' for this, so that every time it loops it prints out 'i', and it seemed to be printing out the numbers 0-8 immediately, meaning it's not properly going through the code.
I think what you can use best there is a reactionCollector. It's a temporary reaction listener, attached to a message. A sample code for that would be:
const msg = await message.channel.send('tic tac toe test');
const acceptedEmojis = ['↖️', '⬆️', '↗️', '⬅️', '⏺️', '➡️', '↙️', '⬇️', '↘️']
const filter = (reaction, user) => {
return acceptedEmojis.includes(reaction.emoji.name) && user.id === turnId;
}
//here you create the collector. It has following attributes: it stops after 10 minutes or after 2 minutes of not collecting anything.
const collector = msg.createReactionCollector(filter, { time: 600000, idle: 120000});
//here you start the listener
collector.on('collect', (reaction, user) => {
if (reaction.emoji.name === '↖️') {
//remove the reaction
await msg.reactions.resolve('↖️')
acceptedEmojis.splice(acceptedEmojis.indexOf('↖️'), 1);
//rest of your code...
} else if (reaction.emoji.name === '⬆️') {
...
}
});

Can Command B only be Executed if command A is executed succesfully

I am trying to make a smart questions bot, and I was wondering if there is a way for allowing command B to be executed if command A was executed first
} else if(message.content.match(/Discord/gi)){
const Embed = new Discord.MessageEmbed()
}
This looks for messages that contains Discord (lowercase or uppercase)
I don't want the bot to look for every message that contains Discord.
I was hoping that It would only execute if the preceding command was executed first, and then after that it would also be disabled, sounds complicated but possible
Assuming I understood your intentions correctly, you want to only look for command B after command A is called, and then once command B is executed, you want to stop looking for it. This can be achieved using a message collector that searches for command B. Here is some sample code (works in the latest version):
if (message.content.match("Command A")) {
//Execute your command A code
message.channel.send("Did some command A stuff");
//After command A code is executed, do the following:
var filter = m => m.author.id == message.author.id;
//Creates a message collector, to collect messages sent by the same user
//When max is 1, only 1 message will be collected and then the collector dies
const collector = new Discord.MessageCollector(message.channel, filter, {max: 1});
collector.on("collect", msg => {
//msg is the new message that the user just sent, so check if it contains Discord
if(msg.content.match(/Discord/gi)){
//Do your command B stuff:
const Embed = new Discord.MessageEmbed()
}
});
}
This code checks for Command A, and executes the Command A code. Then it creates a message collector. The message collector will wait until the user that just executed Command A sends another message. Once the user sends another message, it will run the code listening for the collect event. So we take the collected message, in this case msg, and we check if it matches "Discord". From there, you can do your Command B functionality.
Note that immediately after the user sends a message after executing Command A, the collector ends. That means if the user does not enter a message containing "Discord" within 1 attempt, the collector ends and the user must execute Command A once again in order to attempt to execute Command B again. If you want to allow the user to make more attempts to execute Command B, or if you want the user to be able to execute Command B more than once in a row after executing Command A, then you'll need to increase the value of max.

Discord.js channel name renaming stopped working, Correct format but don't know why

So I created a program that allows you to have a variable that shows how many times a command has been executed, and here is what it looks like:
var timesRunned = 0
if(message.content.startsWith(`${prefix}command`)) {
timesRunned++
let myGuild = client.guilds.cache.get('Guild-ID')
let channel = myGuild.channels.cache.get('Voice-Channel-ID')
channel.setName('Commands Executed: ' + timesRunned)
.catch()
}
But after I run the command more than 3 Times, The voice channel does not even change no matter how many times I run the command, it just stays as "Commands Executed: 2"
Am I doing something wrong? This is in the main app javascript file. The bot itself has enough permissions.
Okay, here's the problem. It seems like you are putting the var timesRunned = 0 in the message event. This means that every time you run a command, this number is reset to 0, which means it forever stays at 1.
If you move the variable to outside the message event, it should work fine.
I will give you another tip, because by just moving it to outside the message event, the variable will clear every time it restarts.
What you can do is get the channel each time the command is run and see how many are on the channel already, then add 1. You would end up with something like this:
var channel = client.channels.cache.get('someID');
var numberExecuted = parseInt(channel.name.split(':').trim());
channel.setName(`Commands Executed: ${numberExecuted + 1}`);
Hope this helps.

Time Delay until next message sent from Discord Bot

In the Discord bot I'm creating, I'd like to make it so that the bot waits lets say 60 seconds before sending another reply to the same command or "includes" word. For instance, if someone says ping below, I want the bot to wait a minute until the next one is sent. I do not want the bot to hold it and put it into a queue or anything of that sort, I just want it to ignore the command for a minute until the next one happens.
if (message.content.includes("ping")) {
message.reply("pong!");
}
If I understand your question correctly, you would want to make a boolean variable and use setTimeout.
The global function setTimeout waits for the provided amount of milliseconds, in this case 60000 (60 seconds), then changes the variable to true again so it can be run.
var pingEnabled = true;
if (ping command run && pingEnabled) {
reply("Pong!");
pingEnabled = false;
setTimeout(() => { pingEnabled = true }, 60000);
}
most of this is pseudocode and you may need to adapt it to your situation.

Discord.js - Getting information after Prefix and command

I'm now working in a new command, a poll command.
For that, I need a way of get the arguments after the prefix and the command itself.
Example: +Poll Do you like puppies?
And, it'd ignore the "+Poll", and get only the question itself, for then create a poll.
To get the arguments, I'm using:
var Args = message.content.split(/\s+/g)
You probably want to try creating the poll with a command, store the question in your database, and then use a separate command to display current polls that are open. Then the users would select the poll via command and the bot would await the response to the question.
I won't go into detail about storing the question in a database, because that's a totally different question. If you need help setting up a local database and store the polls, link to another question and I'll be happy to give more examples.
To go with your question, I would suggest using subStr to save each word after the command in an array, so you can later use those parts in the code. Something like this will store everything after !poll in the variable poll:
if (message.content.startsWith("!poll ")) {
var poll = message.content.substr("!poll ".length);
// Do something with poll variable //
message.channel.send('Your poll question is: ' + poll);
});
For the user answering the poll, you can try using awaitMessage to ask the question, and give a set number of responses. You would want to wrap this in a command that queries your database for the available polls first, and use that identifier to actually get the right question and possible reponses. The example below just echos the response that is collected, but you would want to store the response in the database instead of sending it in a message.
if (message.content === '!poll') {
message.channel.send(`please say yes or no`).then(() => {
message.channel.awaitMessages(response => response.content === `yes` || response.content === 'no', {
max: 1, // number of responses to collect
time: 10000, //time that bot waits for answer in ms
errors: ['time'],
})
.then((collected) => {
var pollRes = collected.first().content; //this is the first response collected
message.channel.send('You said ' + pollRes);
// Do something else here (save response in database)
})
.catch(() => { // if no message is collected
message.channel.send('I didnt catch that, Try again.');
});
});
};

Resources