From 27de28451e6cc863067b99e3515ca54a27d3e4ae Mon Sep 17 00:00:00 2001 From: Daniel Odendahl Jr Date: Mon, 27 Aug 2018 17:34:33 +0000 Subject: [PATCH] Quiz Duel Command --- README.md | 3 +- commands/games/quiz-duel.js | 114 ++++++++++++++++++++++++++++++++++++ commands/games/quiz.js | 2 +- package.json | 2 +- 4 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 commands/games/quiz-duel.js diff --git a/README.md b/README.md index 9e6d9eb7..b60c6a9d 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Xiao is a Discord bot coded in JavaScript with The bot is no longer available for invite. You can self-host the bot, or use her on the [home server](https://discord.gg/sbMe32W). -## Commands (295) +## Commands (296) ### Utility: * **eval**: Executes JavaScript code. @@ -203,6 +203,7 @@ on the [home server](https://discord.gg/sbMe32W). * **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. * **rock-paper-scissors**: Play Rock-Paper-Scissors. * **roulette**: Play a game of roulette. diff --git a/commands/games/quiz-duel.js b/commands/games/quiz-duel.js new file mode 100644 index 00000000..cd991983 --- /dev/null +++ b/commands/games/quiz-duel.js @@ -0,0 +1,114 @@ +const Command = require('../../structures/Command'); +const { stripIndents, oneLine } = require('common-tags'); +const request = require('node-superfetch'); +const { shuffle, verify } = require('../../util/Util'); +const choices = ['A', 'B', 'C', 'D']; + +module.exports = class QuizDuelCommand extends Command { + constructor(client) { + super(client, { + name: 'quiz-duel', + aliases: ['jeopardy-duel', 'trivia-duel'], + group: 'games', + memberName: 'quiz', + description: 'Answer a series of quiz questions against an opponent.', + args: [ + { + key: 'opponent', + prompt: 'What user would you like to play against?', + type: 'user' + }, + { + key: 'maxPts', + label: 'maximum amount of points', + prompt: 'What amount of points should determine the winner?', + type: 'integer' + } + ] + }); + + this.playing = new Set(); + } + + async run(msg, { opponent, maxPts }) { + if (opponent.bot) return msg.reply('Bots may not be played against.'); + if (opponent.id === msg.author.id) return msg.reply('You may not play against yourself.'); + if (this.playing.has(msg.channel.id)) return msg.reply('Only one game may be occurring per channel.'); + this.playing.add(msg.channel.id); + try { + await msg.say(`${opponent}, do you accept this challenge?`); + const verification = await verify(msg.channel, opponent); + if (!verification) { + this.playing.delete(msg.channel.id); + return msg.say('Looks like they declined...'); + } + let winner = null; + let userPoints = 0; + let oppoPoints = 0; + while (!winner) { + const question = await this.fetchQuestion(); + await msg.reply(stripIndents` + **You have 15 seconds to answer this question.** + ${question.question} + ${question.answers.map((answer, i) => `**${choices[i]}**. ${answer}`).join('\n')} + `); + const answered = []; + const filter = res => { + const choice = res.content.toUpperCase(); + if (!choices.includes(choice) || answered.includes(res.author.id)) return false; + if (![msg.author.id, opponent.id].includes(res.author.id)) return false; + answered.push(res.author.id); + if (question.answers[choices.indexOf(res.content.toUpperCase())] !== question.correct) { + msg.say(`${res.author}, that's incorrect!`).catch(() => null); + } + return true; + }; + const msgs = await msg.channel.awaitMessages(filter, { + max: 1, + time: 15000 + }); + if (!msgs.size) { + await msg.reply(`Sorry, time is up! It was ${question.correct}.`); + continue; + } + const result = msgs.first(); + if (userPoints >= maxPts) winner = msg.author; + else if (oppoPoints >= maxPts) winner = opponent; + const userWin = result.author.id === msg.author.id; + if (userWin) ++userPoints; + else ++oppoPoints; + const score = oneLine` + ${userWin ? '**' : ''}${userPoints}${userWin ? '**' : ''}- + ${userWin ? '' : '**'}${oppoPoints}${userWin ? '' : '**'} + `; + await msg.reply(`Nice one, ${result.author}! The score is now ${score}!`); + } + if (!winner) return msg.say('Aww, no one won...'); + return msg.say(`Congrats, ${winner}, you won!`); + } catch (err) { + this.playing.delete(msg.channel.id); + return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`); + } + } + + async fetchQuestion() { + const { body } = await request + .get('https://opentdb.com/api.php') + .query({ + amount: 1, + type: 'multiple', + encode: 'url3986' + }); + if (!body.results) return this.fetchQuestion(); + const question = body.results[0]; + const answers = question.incorrect_answers.map(answer => decodeURIComponent(answer.toLowerCase())); + const correct = decodeURIComponent(question.correct_answer.toLowerCase()); + answers.push(correct); + const shuffled = shuffle(answers); + return { + question: decodeURIComponent(question.question), + answers: shuffled, + correct + }; + } +}; diff --git a/commands/games/quiz.js b/commands/games/quiz.js index 90cd5c14..79dd59a5 100644 --- a/commands/games/quiz.js +++ b/commands/games/quiz.js @@ -10,7 +10,7 @@ module.exports = class QuizCommand extends Command { constructor(client) { super(client, { name: 'quiz', - aliases: ['jeopardy'], + aliases: ['jeopardy', 'trivia'], group: 'games', memberName: 'quiz', description: 'Answer a quiz question.', diff --git a/package.json b/package.json index 99b9e8d9..8235e98a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xiao", - "version": "87.4.2", + "version": "87.5.0", "description": "Your personal server companion.", "main": "Xiao.js", "scripts": {