diff --git a/README.md b/README.md index 51241a2a..ab348cc9 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Xiao is a Discord bot coded in JavaScript with 6. Run `npm i -g pm2` to install PM2. 7. Run `pm2 start Xiao.js --name xiao` to run the bot. -## Commands (343) +## Commands (341) ### Utility: * **eval:** Executes JavaScript code. @@ -267,7 +267,6 @@ Xiao is a Discord bot coded in JavaScript with * **hangman:** Prevent a man from being hanged by guessing a word as fast as you can. * **hunger-games:** Simulate a Hunger Games match with up to 24 tributes. * **lottery:** Attempt to win the lottery with 6 numbers. -* **mafia:** Who is the Mafia? Who is the doctor? Who is the detective? Will the Mafia kill them all? * **math-quiz:** See how fast you can answer a math problem in a given time limit. * **quiz-duel:** Answer a series of quiz questions against an opponent. * **quiz:** Answer a quiz question. @@ -278,7 +277,6 @@ Xiao is a Discord bot coded in JavaScript with * **tic-tac-toe:** Play a game of tic-tac-toe with another user. * **typing-test:** See how fast you can type a sentence in a given time limit. * **whos-that-pokemon:** Guess who that Pokémon is. -* **wizard-convention:** Who is the Dragon? Who is the healer? Who is the mind reader? Will the Dragon eat them all? * **word-chain:** Try to come up with words that start with the last letter of your opponent's word. ### Image Manipulation: diff --git a/assets/json/mafia.json b/assets/json/mafia.json deleted file mode 100644 index b32d0835..00000000 --- a/assets/json/mafia.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "questions": { - "mafia": "Who do you want to kill?", - "doctor": "Who do you want to save?", - "detective": "Who do you think is the Mafia?" - }, - "stories": [ - ".", - " after they had left to get a little snack.", - " while they were in the library reading a story.", - " before they could get the chance to call 911.", - " while they were trying to sneak into someone's house.", - " when they left for a bathroom break.", - " with one bullet.", - " while they were making a very early coffee.", - " while they were attemping to flirt with the Mafia member.", - ", who willingly accepted their fate.", - " while they were playing a quick game of Mafia online like a loner.", - " while they were writing a letter to the president.", - " before they could have the chance to fight back.", - " just as they were about to get ready to leave in fear.", - ", who was a complete coward and was killed while screaming.", - ", who had no time to run.", - ", who was busy trying to find the Mafia.", - " with almost no sign of any remains.", - " before they could even mutter a word.", - ", who left a large mess in the kitchen." - ] -} diff --git a/assets/json/wizard-convention.json b/assets/json/wizard-convention.json deleted file mode 100644 index e77336d8..00000000 --- a/assets/json/wizard-convention.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "questions": { - "dragon": "Who do you want to eat?", - "healer": "Who do you want to heal?", - "mind reader": "Who do you think is the dragon?" - }, - "stories": [ - ".", - " after they had left to get a little snack.", - " while they were in the library fixing their wand.", - " before they could get the chance to call for help.", - " while they were trying to sneak into another wizard's room.", - " when they left for the bathroom.", - " in one big bite.", - " while they were making a very early coffee.", - " while they were attemping to flirt with it.", - ", who willingly accepted their fate.", - " while they were playing a quick game of Wizard Convention.", - " while they were writing a letter to the king.", - " before they could have the chance to fight back.", - " just as they were about to get ready to leave in fear.", - ", who was a complete coward and turned into a chicken at the sight of the beast.", - ", who had no time to run.", - ", who was busy trying to find the rumored dragon of the convention.", - " with almost no sign of any remains.", - " before they could even mutter a word.", - ", who left a large mess in the kitchen." - ] -} diff --git a/commands/games/mafia.js b/commands/games/mafia.js deleted file mode 100644 index be21822b..00000000 --- a/commands/games/mafia.js +++ /dev/null @@ -1,163 +0,0 @@ -const Command = require('../../structures/Command'); -const { Collection } = require('discord.js'); -const { stripIndents } = require('common-tags'); -const { shuffle, delay, awaitPlayers } = require('../../util/Util'); -const { questions, stories } = require('../../assets/json/mafia'); - -module.exports = class MafiaCommand extends Command { - constructor(client) { - super(client, { - name: 'mafia', - aliases: ['town-of-salem', 'werewolf'], - group: 'games', - memberName: 'mafia', - description: 'Who is the Mafia? Who is the doctor? Who is the detective? Will the Mafia kill them all?', - guildOnly: true - }); - } - - async run(msg) { // eslint-disable-line complexity - const current = this.client.games.get(msg.channel.id); - if (current) return msg.reply(`Please wait until the current game of \`${current.name}\` is finished.`); - this.client.games.set(msg.channel.id, { name: this.name }); - try { - await msg.say('You will need at least 2 more players, at maximum 10. To join, type `join game`.'); - const awaitedPlayers = await awaitPlayers(msg, 10, 3, { dmCheck: true }); - if (!awaitedPlayers) { - this.client.games.delete(msg.channel.id); - return msg.say('Game could not be started...'); - } - const players = await this.generatePlayers(awaitedPlayers); - let turn = 1; - while (players.size > 2 && players.some(p => p.role === 'mafia')) { - let killed = null; - let saved = null; - await msg.say(`Night ${turn}, sending DMs...`); - for (const player of players.values()) { - if (player.role.includes('pleb')) continue; - await msg.say(`The ${player.role} is making their decision...`); - const valid = Array.from(players.filter(p => p.role !== player.role).values()); - await player.user.send(stripIndents` - ${questions[player.role]} Please type the number. - ${valid.map((p, i) => `**${i + 1}.** ${p.user.tag}`).join('\n')} - `); - const filter = res => valid[Number.parseInt(res.content, 10) - 1]; - const decision = await player.user.dmChannel.awaitMessages(filter, { - max: 1, - time: 120000 - }); - if (!decision.size) { - await player.user.send('Sorry, time is up!'); - continue; - } - const choice = valid[Number.parseInt(decision.first().content, 10) - 1].id; - if (player.role === 'mafia') { - const chosen = players.get(choice); - killed = chosen.id; - await player.user.send(`${chosen.user.tag} will be killed...`); - } else if (player.role === 'doctor') { - const chosen = players.get(choice); - saved = chosen.id; - await player.user.send(`${chosen.user.tag} will be saved...`); - } else if (player.role === 'detective') { - await player.user.send(players.find(p => p.role === 'mafia').id === choice ? 'Yes.' : 'No.'); - } - } - const display = killed ? players.get(killed).user : null; - const story = stories[Math.floor(Math.random() * stories.length)]; - if (killed && killed === saved) { - await msg.say(stripIndents` - Late last night, a Mafia member emerged from the dark and tried to kill ${display}${story} - Thankfully, a doctor stepped in just in time to save the day. - Who is this mysterious Mafia member? You have one minute to decide. - `); - } else if (killed && players.size < 3) { - await msg.say(stripIndents` - Late last night, a Mafia member emerged from the dark and killed poor ${display}${story} - Sadly, after the event, the final citizen left the town in fear, leaving the Mafia to rule forever. - `); - break; - } else if (killed && killed !== saved) { - players.delete(killed); - await msg.say(stripIndents` - Late last night, a Mafia member emerged from the dark and killed poor ${display}${story} - Who is this mysterious Mafia member? You have one minute to decide. - `); - } else { - await msg.say(stripIndents` - Late last night, a Mafia member emerged from the dark. Thankfully, however, they didn't try to kill anyone. - Who is this mysterious Mafia member? You have one minute to decide. - `); - } - await delay(60000); - const playersArr = Array.from(players.values()); - await msg.say(stripIndents` - Who do you think is the Mafia member? Please type the number. - ${playersArr.map((p, i) => `**${i + 1}.** ${p.user.tag}`).join('\n')} - `); - const voted = []; - const filter = res => { - if (!players.some(p => p.user.id === res.author.id)) return false; - if (voted.includes(res.author.id)) return false; - if (!playersArr[Number.parseInt(res.content, 10) - 1]) return false; - voted.push(res.author.id); - return true; - }; - const votes = await msg.channel.awaitMessages(filter, { - max: players.size, - time: 120000 - }); - if (!votes.size) { - await msg.say('No one will be hanged.'); - continue; - } - const hanged = this.getHanged(votes, players, playersArr); - await msg.say(`${hanged.user} will be hanged.`); - players.delete(hanged.id); - ++turn; - } - this.client.games.delete(msg.channel.id); - const mafia = players.find(p => p.role === 'mafia'); - if (!mafia) return msg.say('The Mafia has been hanged! Thanks for playing!'); - return msg.say(`Oh no, the Mafia wasn't caught in time... Nice job, ${mafia.user}!`); - } catch (err) { - this.client.games.delete(msg.channel.id); - return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); - } - } - - async generatePlayers(list) { - let roles = ['mafia', 'doctor', 'detective']; - for (let i = 0; i < (list.length - 2); i++) roles.push(`pleb ${i + 1}`); - roles = shuffle(roles); - const players = new Collection(); - let i = 0; - for (const user of list) { - players.set(user.id, { - id: user.id, - user, - role: roles[i] - }); - await user.send(`Your role will be: ${roles[i]}!`); - i++; - } - return players; - } - - getHanged(votes, players, playersArr) { - const counts = new Collection(); - for (const vote of votes.values()) { - const player = players.get(playersArr[Number.parseInt(vote.content, 10) - 1].id); - if (counts.has(player.id)) { - ++counts.get(player.id).votes; - } else { - counts.set(player.id, { - id: player.id, - votes: 1, - user: player.user - }); - } - } - return counts.sort((a, b) => b.votes - a.votes).first(); - } -}; diff --git a/commands/games/wizard-convention.js b/commands/games/wizard-convention.js deleted file mode 100644 index 7b1c70d8..00000000 --- a/commands/games/wizard-convention.js +++ /dev/null @@ -1,163 +0,0 @@ -const Command = require('../../structures/Command'); -const { Collection } = require('discord.js'); -const { stripIndents } = require('common-tags'); -const { shuffle, delay, awaitPlayers } = require('../../util/Util'); -const { questions, stories } = require('../../assets/json/wizard-convention'); - -module.exports = class WizardConventionCommand extends Command { - constructor(client) { - super(client, { - name: 'wizard-convention', - aliases: ['wiz-convention'], - group: 'games', - memberName: 'wizard-convention', - description: 'Who is the Dragon? Who is the healer? Who is the mind reader? Will the Dragon eat them all?', - guildOnly: true - }); - } - - async run(msg) { // eslint-disable-line complexity - const current = this.client.games.get(msg.channel.id); - if (current) return msg.reply(`Please wait until the current game of \`${current.name}\` is finished.`); - this.client.games.set(msg.channel.id, { name: this.name }); - try { - await msg.say('You will need at least 2 more players, at maximum 10. To join, type `join game`.'); - const awaitedPlayers = await awaitPlayers(msg, 10, 3, { dmCheck: true }); - if (!awaitedPlayers) { - this.client.games.delete(msg.channel.id); - return msg.say('Game could not be started...'); - } - const players = await this.generatePlayers(awaitedPlayers); - let turn = 1; - while (players.size > 2 && players.some(p => p.role === 'dragon')) { - let eaten = null; - let healed = null; - await msg.say(`Night ${turn}, sending DMs...`); - for (const player of players.values()) { - if (player.role.includes('pleb')) continue; - await msg.say(`The ${player.role} is making their decision...`); - const valid = Array.from(players.filter(p => p.role !== player.role).values()); - await player.user.send(stripIndents` - ${questions[player.role]} Please type the number. - ${valid.map((p, i) => `**${i + 1}.** ${p.user.tag}`).join('\n')} - `); - const filter = res => valid[Number.parseInt(res.content, 10) - 1]; - const decision = await player.user.dmChannel.awaitMessages(filter, { - max: 1, - time: 120000 - }); - if (!decision.size) { - await player.user.send('Sorry, time is up!'); - continue; - } - const choice = valid[Number.parseInt(decision.first().content, 10) - 1].id; - if (player.role === 'dragon') { - const chosen = players.get(choice); - eaten = chosen.id; - await player.user.send(`${chosen.user.tag} will be eaten...`); - } else if (player.role === 'healer') { - const chosen = players.get(choice); - healed = chosen.id; - await player.user.send(`${chosen.user.tag} will be healed...`); - } else if (player.role === 'mind reader') { - await player.user.send(players.find(p => p.role === 'dragon').id === choice ? 'Yes.' : 'No.'); - } - } - const display = eaten ? players.get(eaten).user : null; - const story = stories[Math.floor(Math.random() * stories.length)]; - if (eaten && eaten === healed) { - await msg.say(stripIndents` - Late last night, a dragon emerged and tried to eat ${display}${story} - Thankfully, a healer stepped in just in time to save the day. - Who is this mysterious dragon? You have one minute to decide. - `); - } else if (eaten && players.size < 3) { - await msg.say(stripIndents` - Late last night, a dragon emerged and devoured poor ${display}${story} - Sadly, after the event, the final wizard ran in fear, leaving the dragon to rule forever. - `); - break; - } else if (eaten && eaten !== healed) { - players.delete(eaten); - await msg.say(stripIndents` - Late last night, a dragon emerged and devoured poor ${display}${story} - Who is this mysterious dragon? You have one minute to decide. - `); - } else { - await msg.say(stripIndents` - Late last night, a dragon emerged. Thankfully, however, it didn't try to eat anyone. - Who is this mysterious dragon? You have one minute to decide. - `); - } - await delay(60000); - const playersArr = Array.from(players.values()); - await msg.say(stripIndents` - Who do you think is the dragon? Please type the number. - ${playersArr.map((p, i) => `**${i + 1}.** ${p.user.tag}`).join('\n')} - `); - const voted = []; - const filter = res => { - if (!players.some(p => p.user.id === res.author.id)) return false; - if (voted.includes(res.author.id)) return false; - if (!playersArr[Number.parseInt(res.content, 10) - 1]) return false; - voted.push(res.author.id); - return true; - }; - const votes = await msg.channel.awaitMessages(filter, { - max: players.size, - time: 120000 - }); - if (!votes.size) { - await msg.say('No one will be expelled.'); - continue; - } - const expelled = this.getExpelled(votes, players, playersArr); - await msg.say(`${expelled.user} will be expelled.`); - players.delete(expelled.id); - ++turn; - } - this.client.games.delete(msg.channel.id); - const dragon = players.find(p => p.role === 'dragon'); - if (!dragon) return msg.say('The dragon has been vanquished! Thanks for playing!'); - return msg.say(`Oh no, the dragon wasn't caught in time... Nice job, ${dragon.user}!`); - } catch (err) { - this.client.games.delete(msg.channel.id); - return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); - } - } - - async generatePlayers(list) { - let roles = ['dragon', 'healer', 'mind reader']; - for (let i = 0; i < (list.length - 2); i++) roles.push(`pleb ${i + 1}`); - roles = shuffle(roles); - const players = new Collection(); - let i = 0; - for (const user of list) { - players.set(user.id, { - id: user.id, - user, - role: roles[i] - }); - await user.send(`Your role will be: ${roles[i]}!`); - i++; - } - return players; - } - - getExpelled(votes, players, playersArr) { - const counts = new Collection(); - for (const vote of votes.values()) { - const player = players.get(playersArr[Number.parseInt(vote.content, 10) - 1].id); - if (counts.has(player.id)) { - ++counts.get(player.id).votes; - } else { - counts.set(player.id, { - id: player.id, - votes: 1, - user: player.user - }); - } - } - return counts.sort((a, b) => b.votes - a.votes).first(); - } -}; diff --git a/package.json b/package.json index 6ca78633..96d93f78 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xiao", - "version": "106.0.1", + "version": "107.0.0", "description": "Your personal server companion.", "main": "Xiao.js", "scripts": { diff --git a/util/Util.js b/util/Util.js index 944d4860..704a9afb 100644 --- a/util/Util.js +++ b/util/Util.js @@ -75,32 +75,6 @@ module.exports = class Util { return today; } - static async awaitPlayers(msg, max, min, { time = 30000, dmCheck = false } = {}) { - const joined = []; - joined.push(msg.author.id); - const filter = res => { - if (res.author.bot) return false; - if (joined.includes(res.author.id)) return false; - if (res.content.toLowerCase() !== 'join game') return false; - joined.push(res.author.id); - res.react(SUCCESS_EMOJI_ID || '✅').catch(() => null); - return true; - }; - const verify = await msg.channel.awaitMessages(filter, { max, time }); - verify.set(msg.id, msg); - if (dmCheck) { - for (const message of verify.values()) { - try { - await message.author.send('Hi! Just testing that DMs work, pay this no mind.'); - } catch (err) { - verify.delete(message.id); - } - } - } - if (verify.size < min) return false; - return verify.map(message => message.author); - } - static async verify(channel, user, time = 30000) { const filter = res => { const value = res.content.toLowerCase();