Having an issue with randomization in Discord JS - javascript

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

Related

Discord.JS (14.0) Random chance to React with Emoji?

I'm very new to JS, and DiscordJS in general.
I am trying to get my bot to have a CHANCE to react to any message from a specific user, with a specific emoji ID.
The documentation I found says to use "client.emojis.find", but I get a TypeError that tells me this is not a function.
Any help is appreciated!
client.on("messageCreate", (message) => {
if (message.author.id === "217900978756780032") {
const otterEmoji = client.emojis.find(
(emoji) => emoji.id === "1028007226859855914"
);
if (Math.random() < 0.5) {
message.react("otterEmoji");
}
}
});
EDIT:
This seems to work, but if anyone has other ideas for a cleaner randomizer, let me know!
client.on("messageCreate", (message) => {
const a = Math.floor(Math.random() * 11);
if (a >= 8) {
if (message.author.id === "217900978756780032") {
message.react("๐Ÿฆฆ");
}
}
});
I think instead of client.emojis, you need to use client.emojis.cache:
const otterEmoji = client.emojis.cache.find((emoji) => emoji.id = '1028007226859855914'
(based on https://github.com/AnIdiotsGuide/discordjs-bot-guide/blob/master/coding-guides/using-emojis.md#how-does-discordjs-store-emojis)

Discord JS, how to not allow user to execute a command while answering another command's question, unless it's finished

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.

In discord.js, how could i create a command that displays the avatar of a user tagged, or if not tagged - my avatar?

client.on("message", msg => {
if (msg.content === `${prefix}pfp`) {
var users = msg.mentions.users.first() || msg.author;
msg.channel.send(users.displayAvatarURL());
}
})
Usually, this code only sends the display of the message author's avatar, but not the person who was tagged in the command.
client.on("message", msg => {
if (msg.content === `${prefix}pfp`) {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
var users = msg.mentions.users.first() || msg.author;
msg.channel.send(users.displayAvatarURL());
}
})
You're using msg.content which is the overall content of the message. If you mention someone, the content will be ${prefix}pfp <#a_user's_id> instead of ${prefix}pfp which will then not call the command.
Try instead to use msg.startsWith() like shown below:
client.on("message", msg => {
if (msg.content.startsWith(`${prefix}pfp`)) {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
var users = msg.mentions.users.first() || msg.author;
msg.channel.send(users.displayAvatarURL());
}
})
This will call the function if it starts with ${prefix}pfp rather than it containing such. Which will allow them to mention someone.

How to update 'bot.users.size' in bot status without restarting

So basically I want my bot to have a dynamic status that changes every 5 seconds and displays how many users my bot is currently helping. The changing status part is not the issue, the problem is the users helped count does not change without restarting my bot, which is not ideal considering it is hosted and on many servers, no point restarting all the time just for the user count to be accurate.
What I have tried is by including a interval timer that will update the userCount variable in an attempt to make it accurate to how many users it is helping. What seems to be happening is when a user joins the server, the variable will update accordingly and display +1 in relation to the previous number of users helped. But, when a user leaves, it does not subtract one from the count, instead, it just leaves it at the previous count. I included console.log(userCount) just to make it easier to see the number every 10 seconds in the console, instead of having to wait for the bot's status to change to the proper one.
bot.on('ready', function() {
let userCount = bot.users.size
setInterval(() => {
userCount = bot.users.size
console.log(userCount)
}, 10000);
setInterval(async () => {
let statuslist = [
'blah',
"blah'",
'blah ' + ` ${userCount} Users`
];
const random = Math.floor(Math.random() * statuslist.length);
try {
await bot.user.setPresence({
game: {
name: `${statuslist[random]}`,
type: "Playing"
},
status: "online"
});
} catch (error) {
console.error(error);
}
}, 5000);
console.log("Logged in as " + bot.user.username);
});
I feel as though this isn't a library issue, because I am not very confident in my ability to create code that checks for changes. Ideally, it will display the accurate number based on users joining/leaving servers the bot is on, as well as guilds inviting/removing the bot from the guild. I am not sure if I should use events for this, and even if I was to, I do not know how I could.
But, when a user leaves, it does not subtract one from the count, instead, it just leaves it at the previous count.
This is expected of client.users. It's a collection of all the users the client has cached at some point, so it shouldn't remove any. I think what you're looking for is this...
bot.on('ready', () => {
setInterval(async () => {
let users = 0;
for (let g of bot.guilds.array()) users += (g.members.size - 1));
await bot.user.setActivity(`${users} user${users !== 1 ? 's' : ''}`, {type: 'WATCHING'})
.catch(err => console.error());
}, 15000);
});
Note that this will count users over again if they're in 2 guilds. If you'd rather have a precise count, at the cost of memory, you could use...
bot.on('ready', () => {
setInterval(() => {
let guilds = bot.guilds.array();
let users = [];
for (var i = 0; i < guilds.length; i++) {
let members = guilds[i].members.array();
for (var i = 0; i < members.length; i++) {
if (members[i].user.id !== bot.user.id && users.indexOf(members[i].user.id) === -1) users.push(members[i].user.id);
}
}
bot.user.setActivity(`${users.length} user${users.length !== 1 ? 's' : ''}`, {type: 'WATCHING'})
.catch(err => console.error());
});
});
You have 2 setIntervals, combine them!
That should solve your issue.
You could also use the guildMemberAdd / guildMemberRemove event.
bot.on('ready', function() {
setInterval(async () => {
const statuslist = [
'blah',
'blah_1',
` ${bot.users.size} Users`,
];
console.log(statuslist);
const random = Math.floor(Math.random() * statuslist.length);
try {
await bot.user.setPresence({
game: {
name: `${statuslist[random]}`,
type: 'Playing',
},
status: 'online',
});
}
catch (error) {
console.error(error);
}
}, 15000);
console.log('Logged in as ' + bot.user.username);
});

Javascript: Anti-spam Automoderator (Discord.js)

I am coding a multipurpose Discord bot to replace some of the more minor ones, and I am looking for a piece of code for a feature that recognizes repeated messages or messages sent in a very short time period (let's say 5000ms).
Here is what could be used to implement this idea.
client.on("message", (message) => {
//let's use something like a spam variable for 10 or more messages sent within 5000ms
if(message.content === spam) {
message.reply("Warning: Spamming in this channel is forbidden.");
console.log(message.author.username + " (" + message.author.id + ") has sent 10 messages or more in 5 seconds in " + message.channel.name + ".");
}
});
For reference, I also made a feature that deletes messages, using a ~delete [n] command. It looks like this:
//this will only delete one message in the channel, the most recent one.
message.delete(1000);
//1000 represents the timeout duration. it will only delete one message, regardless of the value.
//we can delete multiple messages with this, but note it has to come before the reply message.
message.channel.bulkDelete(11);
I was thinking of somehow combining the delete command with recognizing spam messages. If you have any ideas, that would be perfect.
Try This:
const usersMap = new Map();
const LIMIT = 7;
const DIFF = 5000;
client.on('message', async(message) => {
if(message.author.bot) return;
if(usersMap.has(message.author.id)) {
const userData = usersMap.get(message.author.id);
const { lastMessage, timer } = userData;
const difference = message.createdTimestamp - lastMessage.createdTimestamp;
let msgCount = userData.msgCount;
console.log(difference);
if(difference > DIFF) {
clearTimeout(timer);
console.log('Cleared Timeout');
userData.msgCount = 1;
userData.lastMessage = message;
userData.timer = setTimeout(() => {
usersMap.delete(message.author.id);
console.log('Removed from map.')
}, TIME);
usersMap.set(message.author.id, userData)
}
else {
++msgCount;
if(parseInt(msgCount) === LIMIT) {
message.reply("Warning: Spamming in this channel is forbidden.");
message.channel.bulkDelete(LIMIT);
} else {
userData.msgCount = msgCount;
usersMap.set(message.author.id, userData);
}
}
}
else {
let fn = setTimeout(() => {
usersMap.delete(message.author.id);
console.log('Removed from map.')
}, TIME);
usersMap.set(message.author.id, {
msgCount: 1,
lastMessage : message,
timer : fn
});
}
})

Categories

Resources