How to put a timer between 2 bot messages / commands - javascript

I've made a discord bot, here the code
const Discord = require("discord.js");
const client = new Discord.Client();
client.on("ready", () => {
console.log("I am ready!");
});
client.on("message", (message) => {
if (message.content.startsWith("!kevin")) {
message.channel.send("i'm kevin");
}
if (message.content.startsWith("!thomas")) {
message.channel.send("random text blabla");
}
Basically, when I type !something, my bot answer in the chat by the proper line, my current issue is my discord is kinda big nowadays, and I would like to restrict the bot to only X messages per minutes, but I can't find an easy function to do that
my question :
Is it possible to get a timer between 2 messages to send by the bot, because without that my bot is just spamming answer to each users typing !somethingsomething, I would like my bot to as soon as someone type !something, the bot lock itself of replying to any other !something for X amount of time
Example,
User 1 : !thomas
User 2 : !thomas
User 3 : !thomas
But the bot only reply to one of them and put a timer to himself before being able to send a new !message reply
So basically, is it any way to make the bot reply to X amounts of !cmd each minutes, or to limits the cooldown between 2 messages the bot send
here my script : https://i.imgur.com/Q7w98Rm.jpg ( i know its terrible especially since it have over 9000 differents !cmd , but i converted quickly a old MIRC script and im terrible at javascript)

Cooldown for the users and/or bot
So I found out from your comments that you want the bot to only run a command only every "X" amount of time. I don't recommend this, I recommend just preventing USERS from registering a cmd every "X" amount of time. I've included both in this example.
let lastCmdSentTime = {};
let waitTimeForUser = 60000 * 5; //Users can only run a command once every 5 minutes
let botLastSent = false;
let timeBetweenEachCmd = 60000; //Bot will only respond once a minute.
client.on("message", (message) => {
if(botLastSent !== false ? message.createdTimestamp - botLastSent < timeBetweenEachCmd : false) return; //don't let the bot run a cmd every [timeBetweenEachCmd]
let userLastSent = lastCmdSentTime[message.author.id] || false;
if(userLastSent !== false ? message.createdTimestamp - userLastSent < waitTimeForUser : false) return; //don't let the user run a cmd every [waitTimeForUser]
lastCmdSentTime[message.author.id] = message.createdTimestamp;
botLastSent = message.createdTimestamp;
//RUN COMMANDS
});

Cooldown for commands
Simply store the date the command was ran, then check if a certain amount has passed since the date was set.
Example:
Edited to support multiple commands
let date = false;
let commandsTimers = {
"!kevin":{
waitTime: 5 * 60000, // 5 minutes wait for this particular command.
lastUsed: false,
}
}
let defaultWaitTime = 60000 * 2; //User needs to wait 2 minutes for each command unless specified
client.on("message", (message) => {
let msgSentDate = Date.now();
let commandWaitTimer = commandsTimers[message.content.split(" ")[0]] || {waitTime:defaultWaitTime, lastUsed:false};
if((commandWaitTimer.lastUsed !== false ? msgSentDate - commandWaitTimer.lastUsed < commandWaitTimer.waitTime : false)){
console.log('User needs to wait: ' + (commandWaitTimer.waitTime - (msgSentDate - commandWaitTimer .lastUsed)) / 1000 + ' seconds');
return
}
commandsTimers[message.content.split(" ")[0]].lastUsed = msgSentDate;
if (message.content.startsWith("!thomas")) {
message.channel.send("random text blabla");
}
if (message.content.startsWith("!kevin")) {
message.channel.send("Kevin!");
}
});

Related

Cool down discord.js

Here is my code, I want it to send a message if the command has been used twice within like 10 seconds. Idk but it is very wrong
var bumpEmbedTwo = new Discord.MessageEmbed()
.setTitle('Cool Down!!!')
.setColor(0xFF0000)
.setDescription('Please waitt 30 more seconds before you use this command again')
setTimeout(() => {
message.channel.send(bumpEmbedTwo)
}, 5000)
var bumpEmbed = new Discord.MessageEmbed()
.setTitle('Time to Bump!')
.setColor(0xFF0000)
.setDescription('Please use the command `!d bump` to bump the server!!!')
setTimeout(() => {
message.channel.send('<#&812133021590880316>')
message.channel.send(bumpEmbed)
}, 1000)
The code you have provided isn't correct as your doing a set timeout without an await so it would completely ignore the purpose of the timeout. Also, whenever the .on('message') function is used, it would still carry out the command, what you have to do is to create an object: const cooldowns = new Discord.Collection(); and whenever the 'message' event is triggered, you would have to add whatever amount of cool down you want.
So here's the code:
const now = Date.now();
let cooldownAmount = 5 * 1000; // In this case, it is 5 seconds
if (cooldowns.has(message.author.id)) {
const expirationTime = cooldowns.get(message.author.id) + cooldownAmount;
if (now < expirationTime) {
const timeLeft = (expirationTime - now) / 1000;
return message.channel.send(`Please wait ${timeLeft.toFixed(1)} more second(s) before using another command`);
}
}
if(!cooldowns.has(message.author.id)){
<command>.run() // Be sure to edit <command to whatever the fetched command is> and add to the (), e.g. message, args, bot, etc.
}
cooldowns.set(message.author.id, now);
setTimeout(() => cooldowns.delete(message.author.id), cooldownAmount);
PS: the client in the arrow symbols are for you to change.
If there are any extra questions, you can comment in this post! Or dm me on discord: N̷i̷g̷h̷t̷m̷a̷r̷e̷ ̷ Jeff#2616
One way to approach this problem would be to save user+command+time in DB or in some global variable.
And then perform a check.
Pseudo-code:
var storage = {
"/command": {
"user-id-123": "22/02/2021 5:27pm"
"user-id-345": "22/02/2021 3:12pm"
}
};
Chat.on("/command", (user) => {
if (!storage["/command"].hasOwnProperty(user.id)) {
storage["/command"][user.id] = Date.now();
}
if (storage["/command"][user.id] > Date.now() + 10 seconds) {
return "Please wait more";
} else {
return "I'm running your command";
}
});

how to do a simple global cooldown using discord.js

So I have a new discord bot and newish to programming, like I kinda understand it but can't do it on my own. but on to the question. The bot is all in the .js (I do have the config.json) but I have yet to get event handler to work. but my code is.
client.on("message", (message) => {
if (message.author.bot) return;
if (message.content.includes ("John")) {
message.channel.send ("Oh yeah, that guy...");
}
}
How can I get a global cooldown? I want the cooldown so if a convo about John occurs, the bot isn't gonna respond to every message.
Easiest thing to do is create a variable outside the listener, with a timestamp, and compare current timestamp to the one set outside the scope, like so
var lastReply = 0;
client.on("message", (message) => {
if (Date.now() - lastReply < 10000) return; // don't respond within 10 seconds
lastReply = Date.now();
if (message.author.bot) return;
if (message.content.includes ("John")) {
message.channel.send ("Oh yeah, that guy...");
}
}
I've set it to 10 seconds, but you can of course get this from a config, or change it yourself. For clarity (easy reading) you can also set a value like this (for lets say, 5 minutes): lastReply < 5 * 60 * 1000
var cooldown = false;
client.on("message", (message) => {
if (message.author.bot) return;
if (message.content.includes("John")) {
if (cooldown == true) {
//Bot is on a cooldown
return;
} else {
message.channel.send("Oh yeah, that guy...");
cooldown = true;
setTimeout(() => {
cooldown = false
}, 60000); //Timeout for a minute
}
}
}
Kinda new to discord programming myself but this is similar to what I used.

Message Collector doesn't start when bot DMs user to collect response

So this is moretheless in relation to the previous question, which was answered (the previous one) The bot is no longer spitting out a lot of errors whenever somebody runs the command, and the bot successfully DMs the user the response prompt, but it seems as if the Message Collector isn't starting? The bot DMs the user, nothing spits out in Console, and that's it. You can respond to the bot all day, and it wont collect it and send it to the channel ID. Any pointers?
Here's the code I believe it may revolve around:
collector.on('collect', (message, col) => {
console.log("Collected message: " + message.content);
counter++; ```
And here is all of the code (just in case it actually doesn't revolve around that):
``` if(message.content.toLowerCase() === '&reserveupdate') {
message.author.send('**Thanks for updating us on the reserve. Please enter what you are taking from the reserve below this message:**');
let filter = m => !m.author.bot;
let counter = 0;
let collector = new discord.MessageCollector(message.author, m => m.author.id, filter);
let destination = client.channels.cache.get('my channel id');
collector.on('collect', (message, col) => {
console.log("Collected message: " + message.content);
counter++;
if(counter === 1) {
message.author.send("**Thanks for updating us on the reserve, it is highly appreciated.**");
collector.stop();
}
I think you might be wrong on how you created your message collector.
According to the docs, you should make it this way :
const filter = m => !m.author.bot;
// If you are in an async function :
const channel = await message.author.createDM();
// Paste code here
// Otherwise :
message.author.createDM.then(channel => {
// Paste code here
});
// Code to paste :
const collector = channel.createMessageCollector(filter, { max: 1, time: 60000 });
collector.on('collect', msg => {
// ...
});
Hope this will help you to solve your issue ! :)

Discord.js Cooldowns with Time Remaining using Command Handler

I am looking to make a cool down system for discord bot commands using discord.js. I am looking for it to show the time remaining left on the cool down when the user tries to do the command. Currently I have it so it does a cool down using the command handler so that I just have to add "timeout: '10000'," although I cant seem to find a way to get it show the time remaining by using this system.
This is the code that I currently have in my message.js file so that is can be used with the command handler so that I do not have to write the timeout code on every command file. Code below is the whole message.js file.
const Timeout = new Set();
const { MessageEmbed } = require('discord.js')
const {prefix} = require('../../config.json')
const ms = require('ms')
module.exports=async(bot, message)=>{
if(message.author.bot) return;
if(!message.content.toLowerCase().startsWith(prefix)) return;
if(!message.member) message.member = await message.guild.fetchMember(messsage);
if(!message.guild) return;
const args = message.content.slice(prefix.length).trim().split(/ +/g);
const cmd = args.shift().toLowerCase();
if(cmd.length === 0) return;
let command = bot.commands.get(cmd);
if(!command) command = bot.commands.get(bot.aliases.get(cmd));
if(command){
if(command.timeout){
if(Timeout.has(`${message.author.id}${command.name}`)){
return message.reply(`**Slow down, you can only use this command every ${ms(command.timeout)}!**`)
} else {
command.run(bot, message, args);
Timeout.add(`${message.author.id}${command.name}`)
setTimeout(() => {
Timeout.delete(`${message.author.id}${command.name}`)
}, command.timeout);
}
} else {
command.run(bot, message, args)
}
}
}
Current response is above in bold text.
For reference, the message.js file is referenced in the following code in my index.js file.
bot.on('message', async message =>{
require('./events/guild/message')(bot, message)
})
The following is what I have to put at the beginning of each command file, with a simple command example shown for reference.
const Discord = require('discord.js');
module.exports={
name: 'test',
category: 'info',
timeout: '15000', //This would result in a 15 second cooldown as time is in ms.
run: async(bot, message, args) =>{
message.channel.send(`test`)
}
}
To conclude, I am looking to keep my system, but instead of it saying "Slow down, you can only use this command every 15000! (For example above) I would like it to say something in the lines of "Slow it down, you can use this command again in 10s.
The default cooldown is 15s.
If I'm not mistaken you want to convert every 15000 into every 15s?
You already have the ms module so looks like you are just confused how to use it:
If it receives a string it converts it into ms, if it receives a number it converts it into a readable format like 1d 2h 3m,
In your module.exports you have it a string, so make it a number and everything is fixed.
That string might also intercept with setTimeout(func, time)
If for some reason you don't want to change the module.exports.timeout into a string, before you call ms, you will have to do parseInt(command.timeout)
code:
let command = bot.commands.get(cmd) || bot.commands.get(bot.aliases.get(cmd));
if (!command) return;
if (!command.timeout) return command.run(bot, message, args);
//if you changed it to a number in module.exports you don't have to parseInt it
const timeout = parseInt(command.timeout);
if (Timeout.has(`${message.author.id}${command.name}`)) {
return message.reply(`**Slow down, you can only use this command every ${ms(timeout)}!**`)
} else {
command.run(bot, message, args);
Timeout.add(`${message.author.id}${command.name}`)
setTimeout(() => {
Timeout.delete(`${message.author.id}${command.name}`)
}, timeout);
}
Second part:
You will need to track when you set the timeout, the issue with using the Set class is that it's
not a key value based, so there's two options:
Set.add({ key: key, time: Date.now()}) or use Discord.Collection / Map
First: still using Set, setting objects instead:
const timeout = command.timeout;
const key = message.author.id + command.name;
let found;
for(const e of Timeout) {
if(e.key === key) {
found = e;
//possibly bad practice, arguable
break;
}
}
if(found) {
const timePassed = Date.now() - found.time;
const timeLeft = timeout - timePassed;
//the part at this command has a default cooldown of, did you want to hard code 15s? or have it be the commands.config.timeout?
return message.reply(`**Slow down, you can use this command again in ${ms(timeLeft)} This command has a default cooldown of ${timeout}!**`)
} else {
command.run(bot, message, args);
Timeout.add({ key, time: Date.now() });
setTimeout(() => {
Timeout.delete(key);
}, timeout);
}
Second: Discord.Collection or Map works too since its just an extended class from that
I'm going with Map, if you use Collection just do:
const { MessageEmbed, Collection } = require("discord.js");
const Timeout = new Collection();
Map code:
const Timeout = new Map();
After code:
const timeout = command.timeout;
const key = message.author.id + command.name;
const found = Timeout.get(key);
if(found) {
const timePassed = Date.now() - found;
const timeLeft = timeout - timePassed;
//the part at this command has a default cooldown of, did you want to hard code 15s? or have it be the commands.config.timeout?
return message.reply(`**Slow down, you can use this command again in ${ms(timeLeft)} This command has a default cooldown of ${timeout}!**`);
} else {
command.run(bot, message, args);
Timeout.set(key, Date.now());
setTimeout(() => {
Timeout.delete(key);
}, timeout);
}

JS - Discord Bot Send Message on specific channel AT MIDNIGHT

Iam trying to make my bot posting message based on array at midnight + also before specific time. The only way I know is to set the delay to the bot but what I want to do is to call a function at midnight (00:00 CET)
I've got array that contains text which bot should announce at midnight. Please point me in good direction :joy:
This is a function that bot use to storage data, to send
if (command === 'koth'){
const massageContent = message.content.toLowerCase();
// console.log(massageContent.slice(config.prefix.length+command.length+1))
if(AreaLowerCase.includes(massageContent.slice(config.prefix.length+command.length+1)) === true) {
AreaToDefend.push(massageContent.slice(config.prefix.length+command.length+1));
// console.log(AreaToDefend)
} else return message.channel.send("Area isnt exist, check the name");
}
I would recommend getting node-schedule-tz.
With this you can create a schedule like so :
var ruleName = new schedule.RecurrenceRule();
tournRule.hour = 00;
tournRule.minute = 00;
tournRule.tz = 'CET';
var r = schedule.scheduleJob(ruleName, function() {
// Call your desired function
})

Categories

Resources