How can I avoid sending two commands at once? - javascript

I'm creating a discord bot and part of its commands is to roll dice with different values (d6, d10, d20, d100). I've set it up like this:
const Discord = require('discord.js');
const client = new Discord.Client();
function commandIs (str, msg){
return msg.content.toLowerCase().startsWith("!" + str)
} //Function that shortens all response commands.
client.on ('message', message => {
if(commandIs("rolld6", message)){
var result = Math.floor(Math.random() * ((6 - 1) + 1) + 1);
message.channel.sendMessage (result);
} //rolls a d6
if(commandIs("rolld10", message)){
var result = Math.floor(Math.random() * ((10 - 1) + 1) + 1);
message.channel.sendMessage (result);
} //rolls a d10
if(commandIs("rolld20", message)){
var result = Math.floor(Math.random() * ((20 - 1) + 1) + 1);
message.channel.sendMessage (result);
} //rolls a d20
if(commandIs("rolld100", message)){
var result = Math.floor(Math.random() * ((100 - 1) + 1) + 1);
message.channel.sendMessage (result);
} //rolls a d100
})
client.login('<Discord bot token>'); //Bot token so it can login to Discord
The issue I have is when I send '!rolld100', the bot answers as if I sent '!rolld10' and '!rolld100' at the same time since 10 is in 100.
Any possible fixes? I'm also new to javascript so if you could explain what your solution does it would help me a lot.

The code seems to be a little complicated with duplicated code. You can simplify this down to a few lines of code by using a regular expression
const Discord = require('discord.js');
const client = new Discord.Client();
client.on ('message', message => {
const rollMatch = message.match(/roll(\d+)\s/)
if (rollMatch) {
const sides = Number(rollMatch)
var result = Math.floor(Math.random() * sides + 1);
message.channel.sendMessage (result);
}
})
client.login('<Discord bot token>'); //Bot token so it can login to Discord
Now if you want to do it your way. You basically would need to do
if(commandIs("rolld100", message)){ }
else if(commandIs("rolld10", message)){ }
else if(commandIs("rolld20", message)){ }
else if(commandIs("rolld6", message)){ }

Related

Discord Bot: How to check if the client message is the correct answer?

I'm trying to build a simple math game and it works fine, but I can't check if the answer someone gives to the math problem is correct or not.
I made an if statement to see if the answer matches the message content:
if (msg.content == answer) {
msg.reply('correct');
}
The problem is that msg.content only accepts a string, not an integer. Can anyone help me fix that issue?
Here is the full code:
const Discord = require('discord.js');
const client = new Discord.Client();
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`);
});
client.on('message', (msg) => {
var minimum = 1;
var maximum = 100;
var int1 = Math.floor(Math.random() * (maximum - minimum + 1)) + minimum;
var int2 = Math.floor(Math.random() * (maximum - minimum + 1)) + minimum;
if (msg.author.bot) return;
//step 1
if (msg.content === 'mathplus') {
msg.reply(`hi what is ${int1} + ${int2}`);
var answer = int1 + int2;
console.log(answer);
}
//check if answer is correct -- where the problem is
if (msg.content == answer) {
msg.reply('correct');
}
});
client.login(process.env.TOKEN);
The problem is NOT that the msg.content is not an integer. You're correctly using double equals here (and 5 == '5'). The problem is that answer is no longer the sum of int1 and int2, it's undefined. When you use the mathplus command, you define the answer but if you send a new message with the answer, it's no longer available.
Check out the example below:
function test(command) {
if (command === 'mathplus') {
var answer = 5
console.log(`"mathplus" command. The answer is ${answer}`)
}
if (command == answer) {
console.log('correct')
}
console.log({
answer,
command
})
}
test('mathplus')
test('5')
As Radnerus mentioned in their comment, you can use message collectors to wait for an answer from the user. I've added an example below how you could use it with lots of comments:
const Discord = require('discord.js');
const client = new Discord.Client();
const prefix = '!';
// helper function to get a number between min and max
function randomInt(min, max) {
if (min > max) [min, max] = [max, min];
return Math.floor(Math.random() * (max - min + 1) + min);
}
client.on('message', async (message) => {
if (message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
if (command === 'mathplus') {
const int1 = randomInt(0, 100);
const int2 = randomInt(0, 100);
const answer = int1 + int2;
// we only wait for 30s for an answer
const maxWait = 30000; // in ms
const embed = new Discord.MessageEmbed()
.setColor('#f8cf4d')
.setTitle(`Hey ${message.author.username}! What is ${int1} + ${int2}? 🙈`);
await message.channel.send(embed);
// filter checks if the response is from the same author who typed the command
const filter = (response) => response.author.id === message.author.id;
const collector = message.channel.createMessageCollector(filter, {
// set up the max wait time the collector runs
time: maxWait,
});
// fires when a response is collected
collector.on('collect', (response) => {
if (parseInt(response.content, 10) === answer) {
message.channel.send(
`🎉🎉🎉 Woohoo, ${response.author}! 🎉🎉🎉\n\nYou're a maths genius, the correct answer was \`${answer}\`.`,
);
// the answer is correct, so stop this collector and emit the "end" event
collector.stop();
} else {
// give the user another chance if the response is incorrect
message.channel.send(
`Oh, ${response.author}, \`${response.content}\` is not correct... 🙊\nDo you want to try again?`,
);
}
});
// fires when the collector is finished collecting
collector.on('end', (collected, reason) => {
// only send a message when the "end" event fires because of timeout
if (reason !== 'time') return;
// if there are incorrect answers
if (collected.size > 0) {
return message.channel.send(
`Ah, ${message.author}. Out of ${collected.size} guess${
collected.size > 1 ? 'es' : ''
} you couldn't find the number \`${answer}\`. I'm not saying you're slow, but no more answers are accepted.`,
);
}
// if the user haven't submitted any answer, let's get a bit more aggressive
return message.channel.send(
`Okay, ${message.author}, I'm bored and I can't wait any longer. No more answers are accepted. At least you could have tried...`,
);
});
}
});
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`);
});
client.login(process.env.TOKEN);
The result:
You might try this approach
if(!parseInt(message.content)){ // If the message wasn't actually a number
return message.reply("You can only answer numbers");
}
if(parseInt(message.content) === answer){ // Correct answer
return message.reply("Correct answer");
}else{ // Wrong answer
return message.reply("Oops");
}
parseInt() converts string to integers. So parseInt("10.103") would return 10. If you need to work with floating numbers try parseFloat()
Use these resources to learn more about these functions
Resources
parseInt()
parseFloat()

Discord.js | Cannot access "lol" before initialization

I am trying to get my bot to send random images in embeds but this logs in the terminal:
let lol = Math.floor (Math.random() * (lol - 1 + 1)) + 1;
^
ReferenceError: Cannot access 'lol' before initialization
This is the code its referring to:
case 'gif':
let maxImageNumber1 = 213;
let lol = Math.floor (Math.random() * (lol - 1 + 1)) + 1;
let imageName1 = `${maxImageNumber1}.gif`
let imagePath1 = `./GIF/${imageName1}`
let file2 = new Discord.MessageAttachment(imagePath1);
let embed1 = new Discord.MessageEmbed();
embed1.setImage(`attachment://${imageName1}`)
message.channel.send({ files: [file2], embed: embed1 });
break;
case 'aes':
let maxImageNumber = 100;
let imageNumber = Math.floor (Math.random() * (maxImageNumber - 1 + 1)) + 1;
let imageName = `${imageNumber}.jpg`
let imagePath = `./images/${imageName}`
let file1 = new Discord.MessageAttachment(imagePath);
let embed = new Discord.MessageEmbed();
embed.setImage(`attachment://${imageName}`)
message.channel.send({ files: [file1], embed: embed });
break;
How would i go about solving this issue?
where you trying to obtain a random number between 1 and maxImageNumber1?
if so, this is the answer:
let maxImageNumber1 = 213;
let lol = Math.floor(Math.random() * maxImageNumber1) + 1;
let imagePath1 = `./GIF/${lol}.gif`

Discordjs bot embed gifs

My bot are sends random gifs but not embed. I wanna sends random gifs with embed. How can I this ?
Codes:
if (msg.author.bot) return;
if (msg.content.toLowerCase() === prefix + 'xgif' ) {
number = 100;
imageNumber = Math.floor (Math.random() * (number -1 + 1)) + 1;
client.channels.cache.get(`channelID`).send( {files: ["./images/" + imageNumber + ".gif"]})
}
You need to first do
const { RichEmbed } = require('discord.js')
That'll get RichEmbed for you. Then, do
const embed = new RichEmbed()
There's a lot of things you can do to change the embed. There's
.setColor(hexidecimal)
.setThumbnail(normally user.displayAvatarURL)
.setFooter(whatever you want)
.setTimestamp()
.setDescription(whatever you want)
.setAuthor(whatever you want)
.addField(stuff)

Discord Random Image Bot spamming

I prepared an sending random images discord bot. bot works smoothly but instead of just sending an image, it randomly sends all images in the folder. I need your help.(12 images available, prefix: !! ) codes;
const Discord = require('discord.js');
const client = new Discord.Client();
const settings = require('./settings.json');
var prefix = settings.prefix;
client.on('ready', () => {
console.log(`${client.user.tag} ready!`);
});
client.on('message', msg => {
if (msg.content.toLowerCase() === prefix + 'xgif' )
number = 12;
imageNumber = Math.floor (Math.random() * (number -1 + 1)) + 1;
msg.channel.send ( {files: ["./images/" + imageNumber + ".gif"]})
});
client.login(TOKEN HERE)
You have numerous problems leading to this. First, your if statement isn't scoped properly. Your code is the functional equivalent of:
if (msg.content.toLowerCase() === prefix + 'xgif' ) {
number = 12;
}
imageNumber = Math.floor (Math.random() * (number -1 + 1)) + 1;
msg.channel.send ( {files: ["./images/" + imageNumber + ".gif"]})
So what is happening is number is not always set to 12, and the last two lines execute with every single message, including messages that come from the bot itself. You need to:
1. scope your if statement correctly.
2. ignore all bot message.
client.on('message', msg => {
if(msg.author.bot) return; // Ignore bots!
if (msg.content.toLowerCase() === prefix + 'xgif' ) {
number = 12;
imageNumber = Math.floor (Math.random() * (number -1 + 1)) + 1;
msg.channel.send ( {files: ["./images/" + imageNumber + ".gif"]})
} // End of if scope
}
Unlike Python, for one example, JavaScript and all other C-style syntax languages do not use white space to indicate scope. An if statement with no brackets only includes the next single statement in it's scope.

How to ensure invitation code is unique in Redis

I need to generate an unique user friendly code and save it into Redis either until the invited user grads it or it expires.
Since the code has to be user friendly I have decided to use 6 digit number, which the frontend will divide into two groups e.g. xxx-xxx.
Now, on the backend, I have NodeJS and node_redis.
This is how I generate the random string and save it into the Redis:
var invCode = Math.floor(Math.random() * 90000) + 100000;
var key = "invitation-code:" + invCode;
const TTL = 3 * 24 * 60 * 60; // 3 days
redis.client.existsAsync(key)
.then(res => {
if (!res) {
// ok, I can add the key, value pair
return redis.client.setAsync(key, value, 'EX', TTL);
} else {
// I have to generate new key and check it again
// how can I re-iterate the process???
return null;
}
})
.then(res => {
logger.info('InvitationCodeController::generate added <' + key + ', ' + value + '> pair');
})
.catch(error => {
logger.error('InvitationCodeController::generate Error ' + error);
});
Now, the point I cannot figure out is - in case the generated code already exists, how can I re-iterate the process, i.e. to generate another random string, format it, check in Redis and etc.
Since I have async call, I don't think any kind of loop can work for me?
Any ideas?
You could utilize a "attempts" process like the following.
You could also make a while loop similarly by removing the --n portion.
Additionally I think you should use the "NX" parameter for "SETNX" --- Set when the value does not exist. Otherwise it is possible that between the time you check redis for whether the key exists and the time you actually set it, you can overwrite some other key. You might even rewrite it at this point so rely on SETNX throwing an error on failing to set rather than checking the value each time.
const process = require('process');
const redis = require("redis");
const Bluebird = require('bluebird')
Bluebird.promisifyAll(redis.RedisClient.prototype)
Bluebird.promisifyAll(redis.Multi.prototype)
const winston = require('winston');
const logger = winston.createLogger({
level: 'silly',
format: winston.format.json(),
transports: [new winston.transports.Console({
format: winston.format.simple()
})]
});
const client = redis.createClient({
host:'redis-19141.c16.us-east-1-3.ec2.cloud.redislabs.com',
port:'19141'
});
client.auth('I6C2ISvac4suTbxSYcbsjWiz635NK8Wv');
// client.set("string key", "string val", redis.print);
var invCode = Math.floor(Math.random() * 90000) + 100000;
// test invCode being the same --- retry.
invCode = 111111;
var key = "invitation-code:" + invCode;
const TTL = 3 * 24 * 60 * 60; // 3 days
let value = "test";
const trySet = function(key,n){
const used = process.memoryUsage().heapUsed / 1024 / 1024;
logger.info(`The script uses approximately ${Math.round(used * 100) / 100} MB`);
return client.existsAsync(key)
.then(res => {
logger.info("existsAsync res",res);
if (!res) {
logger.info("Key does not exist!");
return client.setAsync(key, value, 'NX','EX', TTL)
.then(res => {
logger.info('InvitationCodeController::generate added <' + key + ', ' + value + '> pair');
return true;
})
} else {
logger.info("Key already exists!");
if(n > 0){
return trySet(key,--n);
}else{
return false;
}
}
})
.catch(error => {
logger.error('InvitationCodeController::generate Error ' + error);
return false;
});
}
trySet(key,50).then(function(res){
if(res){
logger.info('trySet::success');
}else{
logger.info('trySet::failed');
}
}).catch(error => {
logger.error('trySet::error');
});
https://repl.it/repls/ImmediateSufficientCoin
Since code generation is sync process, I figure out, I can do it other way around. Here is the code:
const TTL = 3 * 24 * 60 * 60; // 3 days
var invCode = '';
const pattern = "invitation-code:";
var prepKey = '';
redis.client.keysAsync(pattern + "*")
.then(keys => {
// these are all keys / invitation codes
var isFound = false;
do {
invCode = Math.floor(Math.random() * 90000) + 100000;
prepKey = pattern + invCode;
// traverse keys to check if the invitation code matches
keys.forEach(key => {
if (key === prepKey) {
isFound = true;
}
});
} while (isFound);
return prepKey;
})
.then(key => {
return redis.client.setAsync(key, value, 'EX', TTL);
})
.then(res => {
logger.info('InvitationCodeController::generate added <' + prepKey + ', ' + value + '> pair');
})
.catch(error => {
logger.error('InvitationCodeController::generate Error ' + error);
});
Hope this help anyone else on the topic...

Categories

Resources