I am using discord.js to create a "text-adventure" bot. The user chooses what they would like to do by replying a, b, c, or d. I have separated the questions by using a variable called "stage". The problem is, the bot does not let the user choose the next choice, but instead uses their previous answer.
I tried using .lastMessage, but I either couldn't get it to work. That or I had been using it wrong, as I am a bit of an amateur.
Below is a bit of code to show you how I handled it. (I removed the story as it got a bit...violent)
require("dotenv").config();
var stage = 0;
let time = 0;
const { Client } = require('discord.js');
const client = new Client();
client.on('ready', () => {
console.log(`${client.user.username} has arrived`);
});
client.on('message', (message) => {
if (message.author.bot === true) return;
if (message.content === 'begin') {
}
if (message.content === 'restart'){
stage = 0;
message.channel.send('Welcome adventurer! To begin, type "a"');
}
if (message.content === 'a' && stage === 0) {
message.channel.send('...');
message.channel.send('...');
message.channel.send('...');
message.channel.send('Do you:');
message.channel.send('a) ...');
message.channel.send('b) ...');
message.channel.send('c) ...');
message.channel.send('d) ...');
stage = 1;
}
if (message.content === 'a' && stage === 1) {
message.channel.send('...');
message.channel.send('...);
message.channel.send('...');
message.channel.send('...');
message.channel.send('...');
message.channel.send('Do you:');
message.channel.send('a) ...');
message.channel.send('b) ...');
}
});
client.login(process.env.DISCORDJS_BOT_TOKEN);
EDIT: Sorry I didn't add that much code, I am unfamiliar with this website, and added the rest. The bot itself works, I'm just not sure how to make it only respond to one message once.
I used this video if you need more info:
https://www.youtube.com/watch?v=BmKXBVdEV0g&t=15s&ab_channel=TraversyMedia
At the end of your first message.content check block, your code sets stage = 1;. Then it immediately evaluates the next message.content && stage check as true, because you just set stage to 1. Try:
} else if (message.content === 'a' && stage === 1) {
or use a switch/case statement. You could also return; right after stage = 1;. Here is a simplified example:
var stage = 0;
function client_on(message) {
if (message.content === 'a' && stage === 0) {
//...
console.log(stage,message.content);
stage = 1;
//Return here, or else the next block will evaluate to true
return;
}
if (message.content === 'a' && stage === 1) {
//...
console.log(stage,message.content);
stage = 2;
//Return here also, if you have more checks to run
return;
}
}
client_on({content:'a'});
console.log('next message');
client_on({content:'a'});
Also, your entire code logic could just be represented as a data structure like:
var storyMap = new Map([
['0restart', 'Welcome adventurer! To begin, type "a"'],
['1a', '...\nDo you:\na)...\nb)...\nc)...\nd)...'],
['1b', '...\nDo you:\na)...\nb)...\nc)...\nd)...'],
['1c', '...\nDo you:\na)...\nb)...\nc)...\nd)...'],
['1d', '...\nDo you:\na)...\nb)...\nc)...\nd)...'],
['2a', '...\nDo you:\na)...\nb)...\nc)...\nd)...'],
['2b', '...\nDo you:\na)...\nb)...\nc)...\nd)...'],
['2c', '...\nDo you:\na)...\nb)...\nc)...\nd)...'],
['2d', '...\nDo you:\na)...\nb)...\nc)...\nd)...'],
]);
client.on('message', (message) => {
var key = stage.toString() + message.content;
var response = storyMap.get(key);
if (response) {
message.channel.send(response);
stage++;
} else {
message.channel.send('error, try again');
}
}
Related
I am trying to make a sort of trivia bot but the problem is that I can't get it working. I have it so that when you type "-quiz" it sends a embed with a random question. Now you might say that I need to make a separate JSON file and put the questions and answers there, the problem is, is that I need variables in those strings and when I tried it, it wouldn't work because the order or something like that. I tried to fix that but it seems like a bad solution anyway. I set it up so it looks for a message after the initial commands, problem is that it reads it's own embed and I honestly don't know how to make it skip bot messages
client.on('message', message =>{
if(!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
if(command === 'quiz'){
var TypeID = (Math.floor(Math.random() * 11))
var toLog = (Math.floor(Math.random() * 2))
{ //there is something here that is used for the variables above but it is super long
}
var question = [`Question one`, `Question two`]
var answers = [[Answer1_1, Answer1_2],[Answer1_1]]
if(toLog === 0){
const quizEmbed1 = new Discord.MessageEmbed()
.setColor('#0099ff')
.setTitle('quiz')
.setDescription(`${question[0]}`)
message.channel.send(quizEmbed1)
if(!message.content || message.author.bot) return;
if(message.content === [answers[0], answers[1], answers[2], answers[3], answers[4], answers[5]]){
message.channel.send('Good Job! That is right!')
}else{
message.channel.send('Oops! that is wrong.')
}
}else if(toLog == 1){
const quizEmbed2 = new Discord.MessageEmbed()
.setColor('#0099ff')
.setTitle('quiz')
.setDescription(`${question[1]}`)
message.channel.send(quizEmbed2)
if(!message.content || message.author.bot) return;
if(message.content === [answers[6]]){
message.channel.send('Good Job! That is right!')
}else{
message.channel.send('Oops! That is wrong.')
}
}
}
});
if something it wrong it is most likely because I changed it to make it smaller, I am fairly newer to coding in JavaScript
Try using a MessageCollector. There is a good guide on the discord.js guide
Or using awaitMessages. Again there is a guide on the discord.js guide
Here is the example using awaitMessages
const filter = response => {
return item.answers.some(answer => answer.toLowerCase() === response.content.toLowerCase());
};
message.channel.send(item.question).then(() => {
message.channel.awaitMessages(filter, { max: 1, time: 30000, errors: ['time'] })
.then(collected => {
message.channel.send(`${collected.first().author} got the correct answer!`);
})
.catch(collected => {
message.channel.send('Looks like nobody got the answer this time.');
});
});
I would like to know if it is possible to do some sort of "SlowMode" for a specific person on Discord.
The reason is that I have a "spammer" friend, and I would like to calm him down with a command that might slow him down when he speaks for "x" secondes.
So I would like to know if this is possible? and if yes, how?
Thank you for your kindness =) (and sorry for this english i use GoogleTraductor)
Here's how I'd do that.
let ratelimits = [];
client.on("message", (msg) => {
// APPLYING RATELIMITS
const appliedRatelimit = ratelimits.find(
(value) =>
value.user === msg.author.id && value.channel === msg.channel.id
);
if (appliedRatelimit) {
// Can they post the message?
const canPostMessage =
msg.createdAt.getTime() - appliedRatelimit.ratelimit >=
appliedRatelimit.lastMessage;
// They can
if (canPostMessage)
return (ratelimits[
ratelimits.indexOf(appliedRatelimit)
].lastMessage = msg.createdAt.getTime());
// They can't
msg.delete({ reason: "Enforcing ratelimit." });
}
// SET RATELIMIT
if (msg.content === "!ratelimit") {
// Checking it's you
if (msg.author.id !== "your id") return msg.reply("You can't do that.");
// You can change these values in function of the received message
const targetedUserId = "whatever id you want";
const targetedChannelId = msg.channel.id;
const msRateLimit = 2000; // 2 seconds
// Delete existant ratelimit if any for this user on this channel
ratelimits = ratelimits.filter(
(value) =>
!(
value.user === targetedUserId &&
value.channel === targetedChannelId
)
);
// Add ratelimit
ratelimits.push({
user: targetedUserId,
channel: targetedChannelId,
ratelimit: msRateLimit,
lastMessage: 0,
});
}
// CLEAR RATELIMITS
if (msg.content === "!clearRatelimits") {
// Checking it's you
if (msg.author.id !== "your id") return msg.reply("You can't do that.");
// Clearing all ratelimits
ratelimits = [];
}
});
I've just started using discord.js to make a bot to my discord server. I'm trying to make the bot to send a message but it just doesn't do it. I don't even get any errors.
Here's a clip of the code that doesn't work:
bot.on('voiceStateUpdate', (oldMember, newMember) => {
let newUserChannel = newMember.voiceChannel
let oldUserChannel = oldMember.voiceChannel
if(oldUserChannel === undefined && newUserChannel !== undefined) {
// User Joins a voice channel
console.log("Join");
if(newMember = manu) {
console.log("kyllä")
bot.on('message', msg => {
msg.channel.send("Manu, oletko käynyt parturissa? \n Kirjoita vastauksesi numero. \n 1. Olen \n 2. En");
})
bot.on('message', msg => {
if(msg.content === "2") {
msg.channel.send("Ja parturin kautta takasin");
}
else if(msg.content === "1") {
msg.channel.send("Hyvvö");
}
else {
msg.channel.send("Puhu suomea");
}
})
}
}
else if(newUserChannel === undefined){
// User leaves a voice channel
console.log("Leave");
}
})
If you can understand the language in the text sections please notice this bot is just for fun :D.
What am I doing wrong?
You wrote if(newMember = manu) {. You need to use === or == to compare two values. Use = only to assign a value to a variable.
I think the problem is: You put a bot.on in a bot.on. What you can do is put the second bot.on with messages underneath the other bot.on, and it should fix your problem.
how do I read args in discord.js? I am trying to create a support bot and I want to have an !help {topic} command. how do I do that?
my current code is very basic
const Discord = require('discord.js');
const client = new Discord.Client();
const prefix = ("!")
const token = ("removed")
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`);
});
client.on('message', msg => {
if (msg.content === 'ping') {
msg.reply('pong');
}
if (msg.content === 'help') {
msg.reply('type -new to create a support ticket');
}
});
client.login(token);
You can make use of a prefix and arguments like so...
const prefix = '!'; // just an example, change to whatever you want
client.on('message', message => {
if (!message.content.startsWith(prefix)) return;
const args = message.content.trim().split(/ +/g);
const cmd = args[0].slice(prefix.length).toLowerCase(); // case INsensitive, without prefix
if (cmd === 'ping') message.reply('pong');
if (cmd === 'help') {
if (!args[1]) return message.reply('Please specify a topic.');
if (args[2]) return message.reply('Too many arguments.');
// command code
}
});
you can use Switch statement instead of
if (command == 'help') {} else if (command == 'ping') {}
client.on ('message', async message => {
var prefix = "!";
var command = message.content.slice (prefix.length).split (" ")[0],
topic = message.content.split (" ")[1];
switch (command) {
case "help":
if (!topic) return message.channel.send ('no topic bro');
break;
case "ping":
message.channel.send ('pong!');
break;
}
});
let args = msg.content.split(' ');
let command = args.shift().toLowerCase();
this is the simplified answer from #slothiful.
usage
if(command == 'example'){
if(args[0] == '1'){
console.log('1');
} else {
console.log('2');
You can create a simple command/arguments thing (I don't know how to word it correctly)
client.on("message", message => {
let msgArray = message.content.split(" "); // Splits the message content with space as a delimiter
let prefix = "your prefix here";
let command = msgArray[0].replace(prefix, ""); // Gets the first element of msgArray and removes the prefix
let args = msgArray.slice(1); // Remove the first element of msgArray/command and this basically returns the arguments
// Now here is where you can create your commands
if(command === "help") {
if(!args[0]) return message.channel.send("Please specify a topic.");
if(args[1]) return message.channel.send("Too many arguments.");
// do your other help command stuff...
}
});
You can do
const args =
message.content.slice(prefix.length).trim().split(' ');
const cmd = args.shift().toLocaleLowerCase();
Word of advice, use a command handler and slash commands - this will solve both the need for a help command and reading arguments. Also helps with readability.
Anyways...
message.content.split(' '): This will split your string into an array of sub-strings, then return a new array.
.shift(): This will remove the first index in the array.
Combining this will get you your arguments: const args = message.content.split(' ').shift()
I am trying to post a random dog picture when someone says toggledoggo. Every time I try to run the command, it gives me an error message in the terminal, and does nothing.
Here is my code:
const Discord = require('discord.js');
const client = new Discord.Client();
client.on("message", message => {
var prefix = 'toggle';
var doggos = ['dog1', 'dog2'];
var dog1 = message.channel.send({ files: ['dog1.jpg'] });
var dog2 = message.channel.send({ files: ['dog2.jpg'] });
if (message.content.startsWith(prefix + 'doggo')) {
Math.floor(Math.random() * doggos.length);
};
});
client.login('token');
If you want a truly random picture (pseudo-random but still) use an api. I use dog.ceo. Heres a code that, while big, gives a user plenty of options to choose from.
if(msg.split(' ')[0] === prefix + "doggo"){
let breeds = []; // Initializing an array to use later
let breeds2 = []; // Due to the size, we need to split it.
request('https://dog.ceo/api/breeds/list/all', async function (error, response, body) { // Begin a request to list all breeds.
if (!error && response.statusCode == 200) {
var importedJSON = JSON.parse(body);
for(var name in importedJSON.message){ // looping through every breed and pushing it into the array made earlier
breeds.push(name)
if(importedJSON.message[name].length != 0){
for(var i = 0; i < importedJSON.message[name].length; i++){
breeds.push("- " + importedJSON.message[name][i]) // Pushing sub-breeds into the array too
}
}
}
for(var j = 0; j < breeds.length/2; j++){ // Halving the previous array because it's too big for one message.
let toArray = breeds.shift()
breeds2.push(toArray)
}
}
})
let args = msg.split(' ').slice(1)
if(!args[0]){ // if no breed, then send a random image
request('https://dog.ceo/api/breeds/image/random', async function (error, response, body) {
if (!error && response.statusCode == 200) {
var importedJSON = JSON.parse(body);
return await message.channel.send(importedJSON.message)
}
})
}
if(args[0] === "breeds"){ // Command to list the breeds.
setTimeout(async function(){
let m = breeds2.map(name => name.charAt(0).toUpperCase() + name.slice(1)) // Creating a map of the arrays earlier to send as a message
let m2 = breeds.map(name => name.charAt(0).toUpperCase() + name.slice(1))
await message.channel.send(m)
return await message.channel.send(m2)
}, 1000);
}
if(args[0]){
setTimeout(async function(){
for(var i = 0; i < breeds.length; i++){ // Looping through every breed in the array to see if it matches the input
if(args[0] == breeds[i]){
let input = breeds[i]
args.shift() // This is to check for a sub breed input, which is taken into account in the else statement of this if statement
if(!args[0] || args[0] == undefined){
request(`https://dog.ceo/api/breed/${input}/images/random`, async function (error, response, body) {
if (!error && response.statusCode == 200) {
var importedJSON = JSON.parse(body);
return await message.channel.send(importedJSON.message)
}else{
await message.channel.send(`You must have typed something wrong, do ${prefix}doggo breeds for a list of breeds.`)
return
}
})
return
}else{
request(`https://dog.ceo/api/breed/${input}/${args[0]}/images/random`, async function (error, response, body) { // requesting a dog of a certain breed and sub breed
if (!error && response.statusCode == 200) {
var importedJSON = JSON.parse(body);
return await message.channel.send(importedJSON.message)
}else{
await message.channel.send(`You must have typed something wrong, do ${prefix}doggo breeds for a list of breeds.`)
return
}
})
return
}
}
}
for(var i = 0; i < breeds2.length; i++){ // This is identical to the above, but with the other array
if(args[0] == breeds2[i]){
let input = breeds2[i]
args.shift()
if(!args[0] || args[0] == undefined){
request(`https://dog.ceo/api/breed/${input}/images/random`, async function (error, response, body) {
if (!error && response.statusCode == 200) {
var importedJSON = JSON.parse(body);
return await message.channel.send(importedJSON.message)
}else{
await message.channel.send(`You must have typed something wrong, do ${prefix}doggo breeds for a list of breeds.`)
return
}
})
return
}else{
request(`https://dog.ceo/api/breed/${input}/${args[0]}/images/random`, async function (error, response, body) {
if (!error && response.statusCode == 200) {
var importedJSON = JSON.parse(body);
return await message.channel.send(importedJSON.message)
}else{
await message.channel.send(`You must have typed something wrong, do ${prefix}doggo breeds for a list of breeds.`)
return
}
})
return
}
}
}
}, 1000);
}
};
The acceptable command for this are: (prefix)doggo, (prefix)doggo breeds, (prefix)doggo (breed), (prefix)doggo (breed) (sub breed)
You will need the "request" module you can read up on it here: https://www.npmjs.com/package/request. Hopefully the comments I put in the code are enough to explain whats going on if not, ask for clarification. If you just wanted a small command for 2 pictures then you can also tell me and I'll delete this post entirely.