I've been trying to program a discord bot to play hangman except I'm doing it in embeds to learn how they work. Unfortunately, I've been at a roadblock trying to resend my embed after they got a letter right or not.
I tried to follow the discord.js guide and use the message.embeds[0] command but it doesn't output anything. The example embed just outputs with the field I added after.
Here's the important part:
const gameEmbed = new Discord.MessageEmbed()
.setColor(embedColour)
.setTitle('Hangman')
.setDescription('Play hangman in discord!')
.addFields(
{ name: chosenWord.length.toString() + '-letter word', value: seenWord },
);
const receivedEmbed = message.embeds[0];
const exampleEmbed = new Discord.MessageEmbed(receivedEmbed).addFields({ name: chosenWord.length.toString() + '-letter word', value: seenWord });
message.channel.send(gameEmbed);
collector.on('collect', m => {
if (!knownLetters.includes(m.content.toLowerCase()) || !incorrectLetters.includes(m.content.toLowerCase())) {
if (wordLetters.includes(m.content.toLowerCase())) {
message.channel.send('Congratulations! You guessed a letter correctly!');
knownLetters[wordLetters.indexOf(m.content.toLowerCase())] = m.content.toLowerCase();
updateWord();
message.channel.send(exampleEmbed);
}
And the whole program, in case there's anything you need:
module.exports = {
name: 'hangman',
description: 'Play hangman in discord!',
run(message, args, Discord) {
const words = require('./words.json');
const chosenWord = words.words[Math.floor(Math.random() * 981)];
const wordLetters = new Array();
const knownLetters = new Array();
const incorrectLetters = new Array();
let seenWord = '';
let i;
const embedColour = Math.floor(Math.random() * 16777215).toString(16);
for (i = 0; i < chosenWord.length; i++) {
wordLetters.push(chosenWord[i]);
}
for (i = 0; i < chosenWord.length; i++) {
knownLetters.push('\\_', ' ');
}
function updateWord() {
for (i = 0; i < knownLetters.length; i++) {
seenWord += knownLetters[i];
}
}
updateWord();
const filter = m => m.author.id === m.author.id && !m.author.bot && m.content.toLowerCase().length == 1;
const collector = new Discord.MessageCollector(message.channel, filter, {
time: 1000 * 30,
});
const gameEmbed = new Discord.MessageEmbed()
.setColor(embedColour)
.setTitle('Hangman')
.setDescription('Play hangman in discord!')
.addFields(
{ name: chosenWord.length.toString() + '-letter word', value: seenWord },
);
const receivedEmbed = message.embeds[0];
const exampleEmbed = new Discord.MessageEmbed(receivedEmbed).addFields({ name: chosenWord.length.toString() + '-letter word', value: seenWord });
message.channel.send(chosenWord);
message.channel.send(gameEmbed);
collector.on('collect', m => {
if (!knownLetters.includes(m.content.toLowerCase()) || !incorrectLetters.includes(m.content.toLowerCase())) {
if (wordLetters.includes(m.content.toLowerCase())) {
message.channel.send('Congratulations! You guessed a letter correctly!');
knownLetters[wordLetters.indexOf(m.content.toLowerCase())] = m.content.toLowerCase();
updateWord();
message.channel.send(exampleEmbed);
}
else {
message.channel.send('I\'m sorry, that letter is not in the word. Try again!');
}
}
else {
message.chanel.send('You have already guessed that letter. Try again!');
}
});
collector.on('end', (collected) => {
message.channel.send(`done, collected ${collected.size} messages`);
});
},
};
message.embeds is an empty array as the user only sends a simple message, so you can't use that. What you can do is... change the field you added to your embed and send that again:
gameEmbed.fields[0] = {
name: chosenWord.length.toString() + '-letter word',
value: seenWord,
};
message.channel.send(gameEmbed);
I've made quite a few changes (and added comments) in your code, but at least it seems to be working now:
const words = require('./words.json');
const chosenWord = words.words[Math.floor(Math.random() * words.length)];
// destructuring is easier than a for loop
const wordLetters = [...chosenWord];
// don't use new Array(), use [] instead
const knownLetters = [];
const incorrectLetters = [];
let seenWord = '';
for (let i = 0; i < chosenWord.length; i++) {
knownLetters.push('\\_', ' ');
}
function updateWord() {
// you need to reset seenWord, not just add new characters to it
seenWord = '';
for (let i = 0; i < knownLetters.length; i++) {
seenWord += knownLetters[i];
}
}
updateWord();
// m.author.id === m.author.id doesn't make sense
const filter = (m) => !m.author.bot && m.content.toLowerCase().length == 1;
const collector = new Discord.MessageCollector(message.channel, filter, {
time: 1000 * 30,
});
const gameEmbed = new Discord.MessageEmbed()
// you can use RANDOM to set the colour to random :)
.setColor('RANDOM')
.setTitle('Hangman')
.setDescription('Play hangman in discord!')
.addFields({
name: chosenWord.length.toString() + '-letter word',
value: seenWord,
});
message.channel.send(chosenWord);
message.channel.send(gameEmbed);
collector.on('collect', (m) => {
const letter = m.content.toLowerCase();
// try to return early to avoid ifs inside ifs inside ifs
if (knownLetters.includes(letter) || incorrectLetters.includes(letter)) {
return message.chanel.send(
'You have already guessed that letter. Try again!',
);
}
if (!wordLetters.includes(letter)) {
// don't forget to add letter to incorrectLetters
incorrectLetters.push(letter);
return message.channel.send(
"I'm sorry, that letter is not in the word. Try again!",
);
}
message.channel.send('Congratulations! You guessed a letter correctly!');
// you need to double the index if you added spaces between the underscores
// TODO: it only replaces the first occurrence, you need to replace all!
knownLetters[wordLetters.indexOf(letter) * 2] = letter;
updateWord();
// simply update the first field
gameEmbed.fields[0] = {
name: chosenWord.length.toString() + '-letter word',
value: seenWord,
};
// and send the same embed
message.channel.send(gameEmbed);
});
collector.on('end', (collected) => {
message.channel.send(`done, collected ${collected.size} messages`);
});
Related
I need help with a discord counting bot. Whatever server it is in, it has the same counter number. what I mean is that they are all paired and do the same count instead of it being server by server.
Here is the main part (not all of it), I just need to learn to have the servers separate from one another:
const Discord = require('discord.js');
const client = new Discord.Client();
var counter = [{
name: "bot",
nummer: 0
}];
client.on("message", message => {
if (message.channel.name === "counting") {
if (!isNaN(message.content)){
var counterlast = counter[counter.length - 1];
var countercheck = counterlast["nummer"] + 1;
var pinger = parseInt(message.content);
var lastuser = counterlast["name"];
if(countercheck === pinger && lastuser !== message.author.id){
counter.push({name: message.author.id, nummer: countercheck});
message.react('✅');
}
else{
if(lastuser === message.author.id){
message.react('❌');
message.reply(`Wrong Number. The new number is **1**.`);
counter.length = 0;
counter.push({name: "bot", nummer: 0}); Number
}
else{
message.react('❌');
message.reply(` ruined it at ${countercheck}. the new
number is **1**.`);
counter.length = 0;
counter.push({name: "bot", nummer: 0});
}
}
}
}
});
client.login('N/A');
I'm not sure what this counting bot is or how you store your data. However, you can get the server id from the message by accessing message.guild.id. It means that you can check this id before you do anything to the server's "count".
You can use an object with the server ids as its keys like this:
const counter = {
`630930214659670528`: 304,
`630136153655430054`: 941,
`685932343451250658`: 34123,
};
The following code increases the counter of the server it's accessed from by one:
const counter = {};
client.on('message', (message) => {
if (!message.channel.name === 'counting' || isNaN(message.content)) return;
// get the server id
const { id } = message.guild;
counter[id] = counter[id] ? counter[id] + 1 : 1;
message.channel.send(`The counter is at ${counter[id]}`);
});
Edit: As you've updated your question with your code, here's how I'd add different counters for different servers:
const { Client } = require('discord.js');
const client = new Client();
const counters = {};
client.on('message', (message) => {
if (
message.author.bot ||
message.channel.name !== 'counting' ||
isNaN(message.content)
)
return;
const { id } = message.guild;
// if this is the first counter from this server set it up
if (!counters[id]) {
counters[id] = [
{
name: 'bot',
value: 0,
},
];
}
const counter = counters[id];
const last = counter[counter.length - 1];
const increasedValue = last.value + 1;
const pingerCount = parseInt(message.content);
if (increasedValue === pingerCount && last.name !== message.author.id) {
counter.push({ name: message.author.id, value: increasedValue });
message.react('✅');
} else {
if (last.name === message.author.id) {
message.react('❌');
message.reply(
'Wrong, the last user was also you. The new number is **1**.',
);
counter.length = 0;
counter.push({ name: 'bot', value: 0 });
} else {
message.react('❌');
message.reply(`Ruined it at ${increasedValue}, the new number is **1**.`);
counter.length = 0;
counter.push({ name: 'bot', value: 0 });
}
}
});
I have created a simple idea of Hangman game, which runs on console. Everything works, but when I try to use window.addEventListener('keypress, function(e) I cannot press the characters for the game.
const Hangman = function(word, remainguess) {
this.word = word.toLowerCase().split('')
this.remainguess = remainguess
this.guessedLetters = []
}
Hangman.prototype.getPuzzle = function() {
let puzzle = ' '
this.word.forEach(element => {
if (this.guessedLetters.includes(element) || element === ' ') {
puzzle += element
} else {
puzzle += '*'
}
});
return puzzle
}
Hangman.prototype.guessing = function(guess) {
guess = guess.toLowerCase()
const isUnique = !this.guessedLetters.includes(guess)
const isBaddGuess = !this.word.includes(guess)
if (isUnique) {
this.guessedLetters.push(guess)
}
if (isBaddGuess) {
this.remainguess--
}
// return this.remainguess
}
const game1 = new Hangman('cat', 1)
window.addEventListener('keypress', function(e) {
const guess = String.fromCharCode(e.charCode)
game1.guessing(guess)
console.log(game1.getPuzzle())
console.log(game1.remainguess)
})
for a gaming app, a player can select card types for his/her deck (first eachfor) and amount of each card type (2nd each.for). After this, I want to push this selection in an array.
Following part of my code works well:
//defining card types
let availableRoles = ["werwolf", "dorfbewohner", "seherin", "hexe", "jaeger", "armor", "heiler", "prinz"]
let gameState = {
roles: {}
}
//set card amount 0
;(() => {
availableRoles.forEach(role => gameState.roles[role] = 0)
})()
//adding & subtracting roles
const addRole = role => {
gameState.roles[role]++
document.getElementById(role + "_btn_remove").disabled = false;
document.getElementById(role + '_cnt').innerHTML = gameState.roles[role];
document.getElementById('total_cnt').innerHTML = totalNumberOfRolesInGame();
}
const removeRole = role => {
gameState.roles[role]--
if (gameState.roles[role] <= 0) {
gameState.roles[role] = 0
document.getElementById(role + "_btn_remove").disabled = true;
}
document.getElementById(role + '_cnt').innerHTML = gameState.roles[role];
document.getElementById('total_cnt').innerHTML = totalNumberOfRolesInGame();
}
const totalNumberOfRolesInGame = () => Object.values(gameState.roles).reduce((a,c) => a + c)
Now I want to hit every role and hit every number insider the role by using for each command. But it does not work.
var rollen = []
function Holmir() {
;(() => {
gameState.roles.forEach(element => element.forEach (myRole => rollen.push(myRole))
) })()
{
I'm thankful for any help!
forEach works with an array.
gameState = {
roles: {}
}
gameState.roles gives you an object so forEach won't work with this
Actually, i try to create a bot with discord.js and i try to do a help command.
i don't understand why my loop do this (i know it's not a good way for this)
let i = 0;
const embed = new RichEmbed();
if (args.length < 1) {
embed.setColor('#5B4DCA');
while (i < list_groups.length) {
let x = 0;
embed.setTitle(`${list_groups[i]}`)
while (x < groups.length) {
if (groups[x] === list_groups[i]) {
embed.addField('test1', 'test2')
}
x++;
}
message.channel.send(embed)
i++;
}
}
"Modérations" is supposed to display one command, "level & rank" too, "Outils" 4 command and "Sondage" too
enter image description here
I think you solutuion its not right way. If you will have more then 10 groups bot will spam commands list. The 1 way to do it its display all categories list if args.length===0, if args !==0 you try to find all commands in this category. To discord embed you can add only 18 fields, so if you have more then 18 command in categroy you will get api error. So you need spliced commands to pages.
This code will display all categories if args.length === 0, or command groups not fined.
If group fined bot send embed message with command in group (max 10), and react message if pages more then 1, so user can change page with reaction.
const {Discord,RichEmbed} = require('discord.js');
const {prefix,token,classic_roles} = require('../config.json');
const logs = require('../logs/logs');
module.exports.run = async (bot, message, args) => {
if(args.length === 0) {
//Show user all allowed groups commands
let commandCategories = bot.commands.map(command => `!help ${command.help.groups}`).filter(onlyUnique).join('\n') //find all categories and get onlyUnique
let helpMessage = `**The list of command groups:**\n\n ${commandCategories}`
let Embed = new Discord.RichEmbed()
.setAuthor(message.author.tag, message.author.displayAvatarUrl)
.setDescription(helpMessage)
.setColor('#e0c40b')
message.channel.send(Embed)
} else {
//try find required group
let commandsInCategory = bot.commands.filter(command => command.help.groups === args.join(' ').toLowerCase())
if(commandsInCategory.size === 0) {
// if no group find, then display user list of groups
let commandCategories = bot.commands.map(command => `!help ${command.help.groups}`).filter(onlyUnique).join('\n')
let helpMessage = `**For get command list use**\n\n ${commandCategories}`
let Embed = new Discord.RichEmbed()
.setAuthor(message.author.tag, message.author.displayAvatarUrl)
.setDescription(helpMessage)
.setColor('#e0c40b')
message.channel.send(Embed)
return
}
let counter = 0
let allCommands = []
commandsInCategory.map(command => {
allCommands.push({
name: command.help.name,
description: command.help.description
})
})
allCommands = generateHelpArray(allCommands)
//for better display, we will display only 10 in page
let Embed = new Discord.RichEmbed()
Embed.setAuthor(message.author.tag, message.author.displayAvatarUrl)
Embed.setDescription(`The list command of group : **${args.join(' ')}**`)
allCommands[counter].map(command => {
Embed.addField(`**${command.name}**`,`${command.description}`,false)
})
Embed.setColor('#E8DB0E')
Embed.setFooter(`Page ${counter+1} of ${allCommands.length}`)
message.channel.send(Embed).then(msg => {
if(allCommands.length < 2) return
// To change page we will use react emoji
msg.react(`◀️`).then(() => msg.react('▶️'))
const filter = (reaction, user) => {
return [`◀️`, '▶️'].includes(reaction.emoji.name) && user.id === message.author.id;
};
const collector = msg.createReactionCollector(filter, { max:50, time: 60000 });
collector.on('collect', (reaction, reactionCollector) => {
if (reaction.emoji.name === `◀️`) {
//Change counter, remove user reaction and call change embed function
reaction.remove(message.author.id)
counter-=1
if(counter < 0) counter = 0
editEmbed(message, msg, counter, args.join(' '), allCommands)
} else if (reaction.emoji.name === `▶️`) {
//Change counter, remove user reaction and call change embed function
reaction.remove(message.author.id)
counter+=1
if(counter >= allCommands.length) counter = allCommands.length -1
editEmbed(message, msg, counter, args.join(' '), allCommands)
}
});
collector.on('end', (reaction, reactionCollector) => {
msg.clearReactions()
})
})
}
}
module.exports.help = {
name: "help",
description: "Vous permet d'obtenir toutes les commandes accessibles pour vos rôles.",
access: "Public",
groups: "Outils"
}
const onlyUnique = (value, index, self) => {
return self.indexOf(value) === index;
}
const editEmbed = (message, msg, counter, category, allCommands) => {
let Embed = new Discord.RichEmbed()
Embed.setAuthor(message.author.tag, message.author.displayAvatarURL)
Embed.setDescription(`The list command of group : **${category}**`)
Embed.setColor('#E8DB0E')
allCommands[counter].map(command => {
Embed.addField(`**${command.name}**`,`${command.description}`,false)
})
Embed.setFooter(`Page ${counter+1} of ${allCommands.length}`)
msg.edit(Embed)
}
const generateHelpArray = (arr) => {
let newArray = [];
for (let i = 0; i < arr.length; i+=10) {
newArray.push(arr.slice(i,i+10))
}
return newArray
}
I have cities and countires list in a json file. For a given string, I need to check the city name and country name is present or not. If present I have to capitalize the word. what is the best way to acheive this in node JS
Please consider json from this link.
https://raw.githubusercontent.com/russ666/all-countries-and-cities-json/master/countries.json
my input is "united states to play davis cup in bratislava"
output should be "United States to play davis cup in Bratislava"
Hint: First letter of city and country name should be capital.
I am expecting code something like this
var myString="united states to play davis cup in bratislava";
var data=myjson;
var i=0;
myString=myString.split("");
for(i=0;i<myString.length;i++){
var output="";
//help this line
var check=myString[i].match(data)
if(check){
output+=myString[i].charAt(0).toUpperCase() + myString[i].slice(1);
}
else{
output+=myString[i]}
}
It all starts from function start() at the bottom. For displaying purpose i've used a small dataset but you can require the data from the json file by using const data = require('data.json'). I've tested for large dataset also, works like a charm. Hope it helps.
const data = {
"United States":[
"Washington","Bratislava","Hard","Going"],
"Afghanistan": [
"Herat",
"Kabul",
"Kandahar",
"Molah",
"Rana",
"Shar",
"Sharif",
"Wazir Akbar Khan"
]};
Array.prototype.myJoin = function(start,end){
if(!start) start = 0;
if(!end) end = this.length - 1;
end++;
return this.slice(start,end);
};
const getCityData = async (country) => {
return country;
}
const changeFormat = async () => {
try {
let countries = Object.keys(data).map( (country, index) => {
return country;
})
let citiesData = [];
await countries.map( (country, index) => {
citiesData = citiesData.concat(data[country]);
})
return countries.concat(citiesData);
} catch (err) {
return err;
}
}
const checkSentence = (text, text_original, number, modified_data) => {
return new Promise((resolve, reject)=>{
try {
if( !text || !text.length ){
throw new Error('empty text');
}
// console.log('started ' + number);
// console.log('number ' + number +' started')
let upperCase = [];
const number_const = number;
let temp1 = new Array(text.length);
temp1.fill(2);
temp1.map( (v, i) => {
// let temp = text;
let temp = [...text_original, ...[]];
// console.log('i' + i);
// console.log('number' + number);
if(i + number <= text.length ) {
// console.log('inside 1st if');
temp = temp.slice(i, i + number)
// console.log(text + ' 1');
temp = temp.join(' ')
// console.log(text + ' 2');
temp = temp.toLowerCase();
// console.log(text + ' 3');
if(modified_data.indexOf(temp) != -1){
upperCase.push({ start: i, end: i + number - 1 })
}
}
})
let toBeChanged = [];
if(upperCase.length){
upperCase.map( (v, i) => {
// console.log(v);
let arr = range( v.start, v.end )
toBeChanged = toBeChanged.concat(arr);
})
}
// console.log('ended number' + number);
// console.log(toBeChanged);
return resolve(toBeChanged);
} catch (err) {
return reject(err);
// console.error(err);
// return false;
}
})
}
const range = (start, end) => {
// console.log(start);
// console.log(end);
return Array(end - start + 1).fill().map((_, idx) => start + idx)
}
const start = async() => {
try {
excludeWords.map( (word, index) => {
excludeWords[index] = excludeWords[index].toLowerCase();
});
let modified_data_1 = await changeFormat();
let maximum = 1;
modified_data = modified_data_1.map( (v, i) => {
if(v.split(' ').length > maximum){
maximum = v.split(' ').length
}
if(excludeWords.indexOf(v.toLowerCase()) == -1) {
return v.toLowerCase();
}
});
text = text.split(' ');
if(maximum > text.length){
maximum = text.length;
}
// console.log(maximum);
let temp = new Array(maximum);
temp.fill(2);
let answer = await temp.map( (v, i) => {
let tempArray = [...text, ...[]];
let tempArray1 = [...text, ...[]];
return checkSentence(tempArray, tempArray1, (maximum - i), modified_data);
})
return Promise.all(answer).then( (results) => {
let merged = [].concat.apply([], results);
// console.log('merged');
merged = new Set(merged);
merged = [...merged];
// console.log(merged);
merged.map((v, i) => {
if(v == undefined || v == null){
return;
}
let temp1 = text[v].split('');
temp1[0] = temp1[0].toUpperCase();
text[v] = temp1.join('');
})
// console.log(text.join(' '));
return text.join(' ');
}).catch((err)=>{
console.log(err);
})
} catch (err) {
// console.error('here ERROR');
console.error(err);
return false;
}
}
let excludeWords = ['Hard', 'Going'];
let text = 'united states to davis cup hard wazir Akbar Khan in bratislava';
( async () => {
let answer = await start();
console.log(answer);
})();
Hi I have done in simple way it is also working. My problem is in the string the word "davis" also present as a city in json. How to not capitalize that word. For ex: "Hard", "Going" these words also have city name. but these words not be considered as city in my program.
Case 1:
Input: taiwan hit hard by sars outbreak.
Output should be: Taiwan hit hard by sars outbreak.
My output: Taiwan hit Hard by sars outbreak.
Please install capitalize npm and use data.json folder in your root folder to execute below code
var myData=require("./data");
var countriesArray=Object.keys(myData.data);
var citiesArray=Object.values(myData.data);
var capitalize=require('capitalize');
var citiesFlatten = [].concat.apply([], citiesArray);
var countryCities=countriesArray.concat(citiesFlatten);
var str = 'russia ponders space tourism deal';
var pattern = new RegExp("\\b("+countryCities.join("|")+")\\b","ig");
var matchArray=str.match(pattern);
if(!!matchArray){
matchArray.forEach(function(item) {
str=str.replace(item,capitalize.words(item));
});
console.log( str.replace(/^\w/, c => c.toUpperCase()));
}